Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bf9f6e39c |
|
|
@ -7,6 +7,10 @@ const inter = Inter({ subsets: ["latin"] });
|
|||
export const metadata: Metadata = {
|
||||
title: "kv-pix | AI Image Generator",
|
||||
description: "Generate images with Google ImageFX (Whisk)",
|
||||
robots: {
|
||||
index: false,
|
||||
follow: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
|
|
|||
|
|
@ -164,8 +164,24 @@ export function PromptLibrary({ onSelect }: { onSelect?: (prompt: string) => voi
|
|||
return filteredPrompts;
|
||||
};
|
||||
|
||||
// Pagination State
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [itemsPerPage, setItemsPerPage] = useState(24);
|
||||
|
||||
// Reset pagination when filters change
|
||||
useEffect(() => {
|
||||
setCurrentPage(1);
|
||||
}, [searchTerm, selectedCategory, selectedSource, sortMode]);
|
||||
|
||||
const finalPrompts = displayPrompts();
|
||||
|
||||
// Pagination Logic
|
||||
const totalPages = Math.ceil(finalPrompts.length / itemsPerPage);
|
||||
const paginatedPrompts = finalPrompts.slice(
|
||||
(currentPage - 1) * itemsPerPage,
|
||||
currentPage * itemsPerPage
|
||||
);
|
||||
|
||||
const uniqueCategories = ['All', ...Array.from(new Set(prompts.map(p => p.category)))].filter(Boolean);
|
||||
const uniqueSources = ['All', ...Array.from(new Set(prompts.map(p => p.source)))].filter(Boolean);
|
||||
|
||||
|
|
@ -237,23 +253,42 @@ export function PromptLibrary({ onSelect }: { onSelect?: (prompt: string) => voi
|
|||
))}
|
||||
</div>
|
||||
|
||||
{/* Sub-Categories (only show if NOT history/foryou to keep clean? Or keep it?) */}
|
||||
{/* Sub-Categories */}
|
||||
{sortMode === 'all' && (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{uniqueCategories.map(cat => (
|
||||
<button
|
||||
key={cat}
|
||||
onClick={() => setSelectedCategory(cat)}
|
||||
className={cn(
|
||||
"px-4 py-2 rounded-full text-sm font-medium transition-colors",
|
||||
selectedCategory === cat
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "bg-card hover:bg-secondary text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{cat}
|
||||
</button>
|
||||
))}
|
||||
<div className="flex flex-wrap gap-2 py-4 overflow-x-auto scrollbar-hide">
|
||||
{(() => {
|
||||
const priority = ['NAM', 'NỮ', 'SINH NHẬT', 'HALLOWEEN', 'NOEL', 'NEW YEAR', 'TRẺ EM', 'COUPLE', 'CHA - MẸ', 'MẸ BẦU', 'ĐẶC BIỆT'];
|
||||
|
||||
// Sort uniqueCategories (which only contains categories that exist in data)
|
||||
const sortedCategories = uniqueCategories.sort((a, b) => {
|
||||
if (a === 'All') return -1;
|
||||
if (b === 'All') return 1;
|
||||
|
||||
const idxA = priority.indexOf(a);
|
||||
const idxB = priority.indexOf(b);
|
||||
|
||||
if (idxA !== -1 && idxB !== -1) return idxA - idxB;
|
||||
if (idxA !== -1) return -1;
|
||||
if (idxB !== -1) return 1;
|
||||
|
||||
return a.localeCompare(b);
|
||||
});
|
||||
|
||||
return sortedCategories.map(cat => (
|
||||
<button
|
||||
key={cat}
|
||||
onClick={() => setSelectedCategory(cat)}
|
||||
className={cn(
|
||||
"px-4 py-2 text-sm font-bold uppercase tracking-wider transition-all duration-200 rounded-md whitespace-nowrap",
|
||||
selectedCategory === cat
|
||||
? "bg-[#8B1E1E] text-white border border-white/80 shadow-[0_0_12px_rgba(139,30,30,0.6)]" // Active: Deep Red + Glow
|
||||
: "text-gray-400 hover:text-yellow-400 border border-transparent hover:bg-white/5" // Inactive: Yellow Hover
|
||||
)}
|
||||
>
|
||||
{cat}
|
||||
</button>
|
||||
));
|
||||
})()}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -276,69 +311,137 @@ export function PromptLibrary({ onSelect }: { onSelect?: (prompt: string) => voi
|
|||
))}
|
||||
</div>
|
||||
|
||||
{/* Top Pagination Controls */}
|
||||
{!loading && totalPages > 1 && (
|
||||
<div className="flex items-center justify-end gap-2 py-2">
|
||||
<span className="text-sm font-medium text-muted-foreground mr-2">
|
||||
Page {currentPage} of {totalPages}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className="px-3 py-1 rounded-lg bg-secondary text-sm font-medium disabled:opacity-50 hover:bg-secondary/80 transition-colors"
|
||||
>
|
||||
Prev
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className="px-3 py-1 rounded-lg bg-secondary text-sm font-medium disabled:opacity-50 hover:bg-secondary/80 transition-colors"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loading && !prompts.length ? (
|
||||
<div className="flex justify-center py-20">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<AnimatePresence mode="popLayout">
|
||||
{finalPrompts.map((p) => (
|
||||
<motion.div
|
||||
key={p.id}
|
||||
layout
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.9 }}
|
||||
className="group relative flex flex-col bg-card border rounded-xl overflow-hidden hover:border-primary/50 transition-all hover:shadow-lg"
|
||||
>
|
||||
{p.images && p.images.length > 0 ? (
|
||||
<div className="aspect-video relative overflow-hidden bg-secondary/50">
|
||||
<img
|
||||
src={p.images[0]}
|
||||
alt={p.title}
|
||||
className="object-cover w-full h-full transition-transform group-hover:scale-105"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="aspect-video bg-gradient-to-br from-secondary to-background p-4 flex items-center justify-center text-muted-foreground/20">
|
||||
<Sparkles className="h-12 w-12" />
|
||||
</div>
|
||||
)}
|
||||
<>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<AnimatePresence mode="popLayout">
|
||||
{paginatedPrompts.map((p) => (
|
||||
<motion.div
|
||||
key={p.id}
|
||||
layout
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.9 }}
|
||||
className="group relative flex flex-col bg-card border rounded-xl overflow-hidden hover:border-primary/50 transition-all hover:shadow-lg"
|
||||
>
|
||||
{p.images && p.images.length > 0 ? (
|
||||
<div className="aspect-video relative overflow-hidden bg-secondary/50">
|
||||
<img
|
||||
src={p.images[0]}
|
||||
alt={p.title}
|
||||
className="object-cover w-full h-full transition-transform group-hover:scale-105"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="aspect-video bg-gradient-to-br from-secondary to-background p-4 flex items-center justify-center text-muted-foreground/20">
|
||||
<Sparkles className="h-12 w-12" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="p-4 flex flex-col flex-1 gap-3">
|
||||
<div className="flex justify-between items-start gap-2">
|
||||
<h3 className="font-semibold line-clamp-1" title={p.title}>{p.title}</h3>
|
||||
<span className="text-xs px-2 py-0.5 rounded-full bg-secondary text-muted-foreground whitespace-nowrap">
|
||||
{p.source}
|
||||
</span>
|
||||
</div>
|
||||
<div className="p-4 flex flex-col flex-1 gap-3">
|
||||
<div className="flex justify-between items-start gap-2">
|
||||
<h3 className="font-semibold line-clamp-1" title={p.title}>{p.title}</h3>
|
||||
<span className="text-xs px-2 py-0.5 rounded-full bg-secondary text-muted-foreground whitespace-nowrap">
|
||||
{p.source}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-muted-foreground line-clamp-3 flex-1 font-mono bg-secondary/30 p-2 rounded">
|
||||
{p.prompt}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground line-clamp-3 flex-1 font-mono bg-secondary/30 p-2 rounded">
|
||||
{p.prompt}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center justify-between pt-2 border-t mt-auto">
|
||||
<button
|
||||
onClick={() => handleSelect(p)}
|
||||
className="text-xs font-medium text-primary hover:underline flex items-center gap-1"
|
||||
>
|
||||
Use Prompt
|
||||
</button>
|
||||
<button
|
||||
onClick={() => navigator.clipboard.writeText(p.prompt)}
|
||||
className="p-1.5 text-muted-foreground hover:text-primary transition-colors"
|
||||
title="Copy to clipboard"
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
</button>
|
||||
<div className="flex items-center justify-between pt-2 border-t mt-auto">
|
||||
<button
|
||||
onClick={() => handleSelect(p)}
|
||||
className="text-xs font-medium text-primary hover:underline flex items-center gap-1"
|
||||
>
|
||||
Use Prompt
|
||||
</button>
|
||||
<button
|
||||
onClick={() => navigator.clipboard.writeText(p.prompt)}
|
||||
className="p-1.5 text-muted-foreground hover:text-primary transition-colors"
|
||||
title="Copy to clipboard"
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
{/* Pagination Controls */}
|
||||
{totalPages > 1 && (
|
||||
<div className="flex flex-col sm:flex-row items-center justify-between gap-4 py-8 border-t mt-8">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">Show:</span>
|
||||
{[24, 48, 96].map(size => (
|
||||
<button
|
||||
key={size}
|
||||
onClick={() => { setItemsPerPage(size); setCurrentPage(1); }}
|
||||
className={cn(
|
||||
"px-2 py-1 rounded text-xs font-medium transition-colors",
|
||||
itemsPerPage === size
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "bg-secondary text-muted-foreground hover:bg-secondary/80"
|
||||
)}
|
||||
>
|
||||
{size}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className="px-4 py-2 rounded-lg bg-secondary text-sm font-medium disabled:opacity-50 hover:bg-secondary/80 transition-colors"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
Page {currentPage} of {totalPages}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className="px-4 py-2 rounded-lg bg-secondary text-sm font-medium disabled:opacity-50 hover:bg-secondary/80 transition-colors"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{!loading && finalPrompts.length === 0 && (
|
||||
|
|
|
|||
18002
data/habu_prompts.json
Normal file
33908
data/prompts.json
|
|
@ -1,4 +1,36 @@
|
|||
import { Prompt } from '@/lib/types';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
export class HabuCrawler {
|
||||
async crawl(): Promise<Prompt[]> {
|
||||
console.log("[HabuCrawler] Reading from local data...");
|
||||
const filePath = path.join(process.cwd(), 'data', 'habu_prompts.json');
|
||||
try {
|
||||
const data = await fs.readFile(filePath, 'utf-8');
|
||||
const habuPrompts = JSON.parse(data);
|
||||
|
||||
return habuPrompts.map((p: any) => ({
|
||||
id: 0, // Will be overwritten by sync service
|
||||
title: p.name || 'Untitled Habu Prompt',
|
||||
prompt: p.prompt,
|
||||
category: 'Habu', // Default category since mapping is unknown
|
||||
category_type: 'style',
|
||||
description: p.prompt ? (p.prompt.substring(0, 150) + (p.prompt.length > 150 ? '...' : '')) : '',
|
||||
images: p.imageUrl ? [p.imageUrl] : [],
|
||||
author: 'Habu',
|
||||
source: 'habu',
|
||||
source_url: `https://taoanhez.com/#/prompt-library/${p.id}`,
|
||||
createdAt: p.createdAt ? new Date(p.createdAt).getTime() : Date.now(),
|
||||
useCount: 0
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error("[HabuCrawler] Error reading habu data", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class JimmyLvCrawler {
|
||||
async crawl(): Promise<Prompt[]> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { Prompt, PromptCache } from '@/lib/types';
|
||||
import { JimmyLvCrawler, YouMindCrawler, ZeroLuCrawler } from '@/lib/crawler';
|
||||
import { JimmyLvCrawler, YouMindCrawler, ZeroLuCrawler, HabuCrawler } from '@/lib/crawler';
|
||||
|
||||
const DATA_FILE = path.join(process.cwd(), 'data', 'prompts.json');
|
||||
|
||||
|
|
@ -21,15 +21,17 @@ export async function syncPromptsService(): Promise<{ success: boolean, count: n
|
|||
const jimmyCrawler = new JimmyLvCrawler();
|
||||
const youMindCrawler = new YouMindCrawler();
|
||||
const zeroLuCrawler = new ZeroLuCrawler();
|
||||
const habuCrawler = new HabuCrawler();
|
||||
|
||||
const [jimmyPrompts, youMindPrompts, zeroLuPrompts] = await Promise.all([
|
||||
const [jimmyPrompts, youMindPrompts, zeroLuPrompts, habuPrompts] = await Promise.all([
|
||||
jimmyCrawler.crawl(),
|
||||
youMindCrawler.crawl(),
|
||||
zeroLuCrawler.crawl()
|
||||
zeroLuCrawler.crawl(),
|
||||
habuCrawler.crawl()
|
||||
]);
|
||||
|
||||
const crawledPrompts = [...jimmyPrompts, ...youMindPrompts, ...zeroLuPrompts];
|
||||
console.log(`[SyncService] Total crawled ${crawledPrompts.length} prompts (Jimmy: ${jimmyPrompts.length}, YouMind: ${youMindPrompts.length}, ZeroLu: ${zeroLuPrompts.length}).`);
|
||||
const crawledPrompts = [...jimmyPrompts, ...youMindPrompts, ...zeroLuPrompts, ...habuPrompts];
|
||||
console.log(`[SyncService] Total crawled ${crawledPrompts.length} prompts (Jimmy: ${jimmyPrompts.length}, YouMind: ${youMindPrompts.length}, ZeroLu: ${zeroLuPrompts.length}, Habu: ${habuPrompts.length}).`);
|
||||
|
||||
// 2. Read existing
|
||||
const cache = await getPrompts();
|
||||
|
|
|
|||
10
package-lock.json
generated
|
|
@ -1947,6 +1947,7 @@
|
|||
"integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
|
|
@ -1964,6 +1965,7 @@
|
|||
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
|
|
@ -2030,6 +2032,7 @@
|
|||
"integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.51.0",
|
||||
"@typescript-eslint/types": "8.51.0",
|
||||
|
|
@ -2619,6 +2622,7 @@
|
|||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
|
@ -3644,6 +3648,7 @@
|
|||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
|
|
@ -3817,6 +3822,7 @@
|
|||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
|
|
@ -6268,6 +6274,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
|
|
@ -6280,6 +6287,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
|
|
@ -7101,6 +7109,7 @@
|
|||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -7280,6 +7289,7 @@
|
|||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "v2_temp",
|
||||
"version": "0.1.0",
|
||||
"version": "2.5.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
|
|
|||
BIN
public/images/prompts/1.png
Normal file
|
After Width: | Height: | Size: 340 KiB |
BIN
public/images/prompts/10.png
Normal file
|
After Width: | Height: | Size: 381 KiB |
BIN
public/images/prompts/100.png
Normal file
|
After Width: | Height: | Size: 287 KiB |
BIN
public/images/prompts/1000.png
Normal file
|
After Width: | Height: | Size: 349 KiB |
BIN
public/images/prompts/1001.png
Normal file
|
After Width: | Height: | Size: 386 KiB |
BIN
public/images/prompts/1002.png
Normal file
|
After Width: | Height: | Size: 298 KiB |
BIN
public/images/prompts/1003.png
Normal file
|
After Width: | Height: | Size: 454 KiB |
BIN
public/images/prompts/1004.png
Normal file
|
After Width: | Height: | Size: 405 KiB |
BIN
public/images/prompts/1005.png
Normal file
|
After Width: | Height: | Size: 432 KiB |
BIN
public/images/prompts/1006.png
Normal file
|
After Width: | Height: | Size: 323 KiB |
BIN
public/images/prompts/1007.png
Normal file
|
After Width: | Height: | Size: 341 KiB |
BIN
public/images/prompts/1008.png
Normal file
|
After Width: | Height: | Size: 413 KiB |
BIN
public/images/prompts/1009.png
Normal file
|
After Width: | Height: | Size: 504 KiB |
BIN
public/images/prompts/101.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
BIN
public/images/prompts/1010.png
Normal file
|
After Width: | Height: | Size: 483 KiB |
BIN
public/images/prompts/1011.png
Normal file
|
After Width: | Height: | Size: 257 KiB |
BIN
public/images/prompts/1012.png
Normal file
|
After Width: | Height: | Size: 412 KiB |
BIN
public/images/prompts/1013.png
Normal file
|
After Width: | Height: | Size: 348 KiB |
BIN
public/images/prompts/1014.png
Normal file
|
After Width: | Height: | Size: 337 KiB |
BIN
public/images/prompts/1015.png
Normal file
|
After Width: | Height: | Size: 242 KiB |
BIN
public/images/prompts/1016.png
Normal file
|
After Width: | Height: | Size: 432 KiB |
BIN
public/images/prompts/1017.png
Normal file
|
After Width: | Height: | Size: 373 KiB |
BIN
public/images/prompts/1018.png
Normal file
|
After Width: | Height: | Size: 443 KiB |
BIN
public/images/prompts/1019.png
Normal file
|
After Width: | Height: | Size: 361 KiB |
BIN
public/images/prompts/102.png
Normal file
|
After Width: | Height: | Size: 340 KiB |
BIN
public/images/prompts/1020.png
Normal file
|
After Width: | Height: | Size: 368 KiB |
BIN
public/images/prompts/1021.png
Normal file
|
After Width: | Height: | Size: 350 KiB |
BIN
public/images/prompts/1022.png
Normal file
|
After Width: | Height: | Size: 284 KiB |
BIN
public/images/prompts/1023.png
Normal file
|
After Width: | Height: | Size: 419 KiB |
BIN
public/images/prompts/1024.png
Normal file
|
After Width: | Height: | Size: 366 KiB |
BIN
public/images/prompts/1025.png
Normal file
|
After Width: | Height: | Size: 377 KiB |
BIN
public/images/prompts/1026.png
Normal file
|
After Width: | Height: | Size: 379 KiB |
BIN
public/images/prompts/1027.jpg
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
public/images/prompts/1028.png
Normal file
|
After Width: | Height: | Size: 452 KiB |
BIN
public/images/prompts/1029.png
Normal file
|
After Width: | Height: | Size: 369 KiB |
BIN
public/images/prompts/103.png
Normal file
|
After Width: | Height: | Size: 422 KiB |
BIN
public/images/prompts/1030.png
Normal file
|
After Width: | Height: | Size: 383 KiB |
BIN
public/images/prompts/1031.png
Normal file
|
After Width: | Height: | Size: 457 KiB |
BIN
public/images/prompts/1032.png
Normal file
|
After Width: | Height: | Size: 379 KiB |
BIN
public/images/prompts/1033.png
Normal file
|
After Width: | Height: | Size: 462 KiB |
BIN
public/images/prompts/1034.png
Normal file
|
After Width: | Height: | Size: 384 KiB |
BIN
public/images/prompts/1035.png
Normal file
|
After Width: | Height: | Size: 456 KiB |
BIN
public/images/prompts/1036.png
Normal file
|
After Width: | Height: | Size: 407 KiB |
BIN
public/images/prompts/1037.png
Normal file
|
After Width: | Height: | Size: 429 KiB |
BIN
public/images/prompts/1038.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
BIN
public/images/prompts/1039.png
Normal file
|
After Width: | Height: | Size: 453 KiB |
BIN
public/images/prompts/104.png
Normal file
|
After Width: | Height: | Size: 478 KiB |
BIN
public/images/prompts/1040.png
Normal file
|
After Width: | Height: | Size: 363 KiB |
BIN
public/images/prompts/1041.png
Normal file
|
After Width: | Height: | Size: 293 KiB |
BIN
public/images/prompts/1042.png
Normal file
|
After Width: | Height: | Size: 365 KiB |
BIN
public/images/prompts/1043.jpg
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
public/images/prompts/1044.png
Normal file
|
After Width: | Height: | Size: 450 KiB |
BIN
public/images/prompts/1045.png
Normal file
|
After Width: | Height: | Size: 408 KiB |
BIN
public/images/prompts/1046.png
Normal file
|
After Width: | Height: | Size: 330 KiB |
BIN
public/images/prompts/1047.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
BIN
public/images/prompts/1048.png
Normal file
|
After Width: | Height: | Size: 403 KiB |
BIN
public/images/prompts/1049.png
Normal file
|
After Width: | Height: | Size: 361 KiB |
BIN
public/images/prompts/105.png
Normal file
|
After Width: | Height: | Size: 383 KiB |
BIN
public/images/prompts/1050.png
Normal file
|
After Width: | Height: | Size: 367 KiB |
BIN
public/images/prompts/1051.png
Normal file
|
After Width: | Height: | Size: 393 KiB |
BIN
public/images/prompts/1052.png
Normal file
|
After Width: | Height: | Size: 377 KiB |
BIN
public/images/prompts/1053.png
Normal file
|
After Width: | Height: | Size: 463 KiB |
BIN
public/images/prompts/1054.png
Normal file
|
After Width: | Height: | Size: 460 KiB |
BIN
public/images/prompts/1055.png
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
public/images/prompts/1056.png
Normal file
|
After Width: | Height: | Size: 373 KiB |
BIN
public/images/prompts/1057.png
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
public/images/prompts/1058.png
Normal file
|
After Width: | Height: | Size: 375 KiB |
BIN
public/images/prompts/1059.png
Normal file
|
After Width: | Height: | Size: 427 KiB |
BIN
public/images/prompts/106.png
Normal file
|
After Width: | Height: | Size: 482 KiB |
BIN
public/images/prompts/1060.png
Normal file
|
After Width: | Height: | Size: 522 KiB |
BIN
public/images/prompts/1061.png
Normal file
|
After Width: | Height: | Size: 418 KiB |
BIN
public/images/prompts/1062.png
Normal file
|
After Width: | Height: | Size: 428 KiB |
BIN
public/images/prompts/1063.jpg
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
public/images/prompts/1064.png
Normal file
|
After Width: | Height: | Size: 377 KiB |
BIN
public/images/prompts/1065.png
Normal file
|
After Width: | Height: | Size: 374 KiB |
BIN
public/images/prompts/1066.png
Normal file
|
After Width: | Height: | Size: 450 KiB |
BIN
public/images/prompts/1067.png
Normal file
|
After Width: | Height: | Size: 349 KiB |
BIN
public/images/prompts/1068.png
Normal file
|
After Width: | Height: | Size: 404 KiB |
BIN
public/images/prompts/1069.png
Normal file
|
After Width: | Height: | Size: 438 KiB |
BIN
public/images/prompts/107.png
Normal file
|
After Width: | Height: | Size: 378 KiB |
BIN
public/images/prompts/1070.png
Normal file
|
After Width: | Height: | Size: 456 KiB |
BIN
public/images/prompts/1071.png
Normal file
|
After Width: | Height: | Size: 466 KiB |
BIN
public/images/prompts/1072.png
Normal file
|
After Width: | Height: | Size: 462 KiB |
BIN
public/images/prompts/1073.png
Normal file
|
After Width: | Height: | Size: 438 KiB |
BIN
public/images/prompts/1074.png
Normal file
|
After Width: | Height: | Size: 472 KiB |
BIN
public/images/prompts/1075.png
Normal file
|
After Width: | Height: | Size: 494 KiB |
BIN
public/images/prompts/1076.png
Normal file
|
After Width: | Height: | Size: 426 KiB |
BIN
public/images/prompts/1077.png
Normal file
|
After Width: | Height: | Size: 425 KiB |
BIN
public/images/prompts/1078.png
Normal file
|
After Width: | Height: | Size: 462 KiB |
BIN
public/images/prompts/1079.png
Normal file
|
After Width: | Height: | Size: 387 KiB |
BIN
public/images/prompts/108.png
Normal file
|
After Width: | Height: | Size: 537 KiB |
BIN
public/images/prompts/1080.png
Normal file
|
After Width: | Height: | Size: 419 KiB |