├── public ├── placeholder.jpg ├── placeholder-logo.png ├── placeholder-user.jpg ├── logos │ ├── bfl.svg │ ├── google.svg │ ├── bytedance.svg │ ├── fal.svg │ ├── qwen.svg │ └── fal-logo.svg ├── placeholder-logo.svg └── placeholder.svg ├── postcss.config.mjs ├── lib ├── utils.ts ├── model-endpoints.json ├── indexeddb.ts └── queries.ts ├── next.config.mjs ├── components ├── theme-provider.tsx ├── providers.tsx └── ui │ ├── label.tsx │ ├── textarea.tsx │ ├── input.tsx │ ├── button.tsx │ ├── dialog.tsx │ └── select.tsx ├── .gitignore ├── components.json ├── tsconfig.json ├── README.md ├── app ├── layout.tsx ├── api │ └── generate-image │ │ └── route.ts ├── globals.css └── page.tsx ├── LICENSE ├── package.json └── styles └── globals.css /public/placeholder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aykutkardas/v0-for-images/HEAD/public/placeholder.jpg -------------------------------------------------------------------------------- /public/placeholder-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aykutkardas/v0-for-images/HEAD/public/placeholder-logo.png -------------------------------------------------------------------------------- /public/placeholder-user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aykutkardas/v0-for-images/HEAD/public/placeholder-user.jpg -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | '@tailwindcss/postcss': {}, 5 | }, 6 | } 7 | 8 | export default config 9 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | eslint: { 4 | ignoreDuringBuilds: true, 5 | }, 6 | typescript: { 7 | ignoreBuildErrors: true, 8 | }, 9 | images: { 10 | unoptimized: true, 11 | }, 12 | } 13 | 14 | export default nextConfig -------------------------------------------------------------------------------- /components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { 5 | ThemeProvider as NextThemesProvider, 6 | type ThemeProviderProps, 7 | } from 'next-themes' 8 | 9 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 10 | return {children} 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # next.js 7 | /.next/ 8 | /out/ 9 | 10 | # production 11 | /build 12 | 13 | # debug 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | .pnpm-debug.log* 18 | 19 | # env files 20 | .env* 21 | 22 | # vercel 23 | .vercel 24 | 25 | # typescript 26 | *.tsbuildinfo 27 | next-env.d.ts -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /lib/model-endpoints.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "label": "Qwen Edit", 4 | "endpoint": "fal-ai/qwen-image-edit", 5 | "logo": "/logos/qwen.svg" 6 | }, 7 | { 8 | "label": "Seededit", 9 | "endpoint": "fal-ai/bytedance/seededit/v3/edit-image", 10 | "logo": "/logos/bytedance.svg" 11 | }, 12 | { 13 | "label": "Kontext Pro Edit", 14 | "endpoint": "fal-ai/flux-pro/kontext", 15 | "logo": "/logos/bfl.svg" 16 | }, 17 | { 18 | "label": "Nano Banana Edit", 19 | "endpoint": "fal-ai/nano-banana/edit", 20 | "logo": "/logos/google.svg" 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /public/logos/bfl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /components/providers.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import type React from "react" 4 | 5 | import { QueryClient, QueryClientProvider } from "@tanstack/react-query" 6 | import { useState } from "react" 7 | 8 | export function Providers({ children }: { children: React.ReactNode }) { 9 | const [queryClient] = useState( 10 | () => 11 | new QueryClient({ 12 | defaultOptions: { 13 | queries: { 14 | staleTime: 1000 * 60 * 5, // 5 minutes 15 | refetchOnWindowFocus: false, 16 | }, 17 | }, 18 | }), 19 | ) 20 | 21 | return {children} 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "target": "ES6", 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /public/logos/google.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { 6 | return ( 7 |