├── LICENSE.md ├── .env.local.example ├── src ├── vite-env.d.ts ├── components │ ├── PromptCard │ │ ├── index.ts │ │ ├── PromptCard.tsx │ │ ├── ActionButtons.tsx │ │ ├── ImageGrid.tsx │ │ └── PropertiesDisplay.tsx │ ├── PromptForm │ │ ├── index.ts │ │ ├── PromptControls.tsx │ │ ├── ControlNetSelector.tsx │ │ ├── ColorGradingSelector.tsx │ │ ├── ImageUpload.tsx │ │ ├── PromptForm.tsx │ │ ├── AspectRatioSlider.tsx │ │ ├── AddLoraText.tsx │ │ └── AdvancedControls.tsx │ ├── LoadingSpinner.tsx │ ├── ui │ │ ├── skeleton.tsx │ │ ├── textarea.tsx │ │ ├── label.tsx │ │ ├── toaster.tsx │ │ ├── input.tsx │ │ ├── tooltip.tsx │ │ ├── slider.tsx │ │ ├── badge.tsx │ │ ├── switch.tsx │ │ ├── card.tsx │ │ ├── tabs.tsx │ │ ├── button.tsx │ │ ├── bidirectional-slider.tsx │ │ ├── dialog.tsx │ │ ├── sheet.tsx │ │ ├── toast.tsx │ │ ├── select.tsx │ │ └── dropdown-menu.tsx │ ├── MasonryLayout.tsx │ ├── ModelSelector.tsx │ ├── WithLayout.tsx │ ├── MoonToggle.tsx │ ├── MobileTabNav.tsx │ ├── PromptImage.tsx │ ├── theme-provider.tsx │ ├── Gallery.tsx │ ├── GalleryItem.tsx │ ├── Navbar.tsx │ ├── PromptDetails.tsx │ └── ImageZoom.tsx ├── lib │ └── utils.ts ├── pages │ ├── index.ts │ ├── Gallery.tsx │ ├── UsersPrompts.tsx │ └── Prompt.tsx ├── hooks │ ├── useLike.ts │ ├── useTrash.ts │ ├── useInfiniteScroll.ts │ ├── useCopy.ts │ ├── useAPrompt.ts │ ├── usePromptPolling.ts │ ├── useImageUpload.ts │ ├── usePromptForm.ts │ ├── usePromptSubmit.ts │ ├── usePrompts.ts │ ├── usePromptNavigation.ts │ └── use-toast.ts ├── main.tsx ├── api │ └── prompts.ts ├── index.css ├── services │ └── apiClient.ts ├── store │ ├── promptFormStore.ts │ └── promptStore.ts └── types │ └── index.ts ├── tsconfig.node.tsbuildinfo ├── public └── logo.png ├── postcss.config.js ├── tsconfig.json ├── .gitignore ├── index.html ├── .gitpod.yml ├── components.json ├── tsconfig.node.json ├── tsconfig.app.json ├── tailwind.config.js ├── eslint.config.js ├── .github └── workflows │ └── deploy.yml ├── vite.config.ts ├── tsconfig.app.tsbuildinfo ├── package.json └── README.md /LICENSE.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.env.local.example: -------------------------------------------------------------------------------- 1 | ASTRIA_API_KEY=fill your astria api key -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.node.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./vite.config.ts"],"version":"5.6.3"} -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astriaai/imagine/HEAD/public/logo.png -------------------------------------------------------------------------------- /src/components/PromptCard/index.ts: -------------------------------------------------------------------------------- 1 | import PromptCard from "./PromptCard"; 2 | 3 | export default PromptCard; -------------------------------------------------------------------------------- /src/components/PromptForm/index.ts: -------------------------------------------------------------------------------- 1 | import PromptForm from "./PromptForm"; 2 | 3 | export default PromptForm; -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /src/pages/index.ts: -------------------------------------------------------------------------------- 1 | import Gallery from './Gallery'; 2 | import UsersPrompts from './UsersPrompts'; 3 | import Prompt from './Prompt'; 4 | 5 | export { 6 | Gallery, 7 | UsersPrompts, 8 | Prompt 9 | }; -------------------------------------------------------------------------------- /src/components/LoadingSpinner.tsx: -------------------------------------------------------------------------------- 1 | import { Loader2 } from "lucide-react"; 2 | 3 | const LoadingSpinner: React.FC = () => { 4 | return ; 5 | }; 6 | 7 | export default LoadingSpinner; 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ], 7 | "compilerOptions": { 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": ["./src/*"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | .env 15 | 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | .vercel 28 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Astria Imagine 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | # Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart 6 | 7 | tasks: 8 | - init: npm install && npm run build 9 | command: npm run dev 10 | 11 | 12 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/index.css", 9 | "baseColor": "zinc", 10 | "cssVariables": false, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } -------------------------------------------------------------------------------- /src/hooks/useLike.ts: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { likePrompt } from "@/api/prompts"; 3 | 4 | export const useLike = (initialLiked: boolean) => { 5 | const [isLiked, setIsLiked] = useState(initialLiked); 6 | 7 | const handleLike = async (promptId: number) => { 8 | if (promptId) { 9 | const response = await likePrompt(promptId); 10 | if (response) { 11 | setIsLiked(!isLiked); 12 | } 13 | } 14 | }; 15 | 16 | return { isLiked, handleLike }; 17 | }; 18 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /src/pages/Gallery.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import WithLayout from "@/components/WithLayout"; 3 | import PromptForm from "@/components/PromptForm"; 4 | import MasonryGallery from "@/components/Gallery"; 5 | import usePrompts from "@/hooks/usePrompts"; 6 | 7 | const Gallery: React.FC = () => { 8 | const { galleryPrompts, fetchMoreData } = usePrompts(); 9 | 10 | return ( 11 |
12 | 13 | fetchMoreData(true)} /> 14 |
15 | ); 16 | }; 17 | 18 | const GalleryWithLayout = WithLayout(Gallery); 19 | export default GalleryWithLayout; 20 | -------------------------------------------------------------------------------- /src/components/MasonryLayout.tsx: -------------------------------------------------------------------------------- 1 | // components/MasonryLayout.tsx 2 | import Masonry from "react-masonry-css"; 3 | 4 | interface MasonryLayoutProps { 5 | children: React.ReactNode; 6 | } 7 | 8 | const breakpointColumnsObj = { 9 | default: 4, 10 | 2560: 5, 11 | 1100: 4, 12 | 700: 3, 13 | 500: 2, 14 | }; 15 | 16 | const MasonryLayout: React.FC = ({ children }) => { 17 | return ( 18 | 23 | {children} 24 | 25 | ); 26 | }; 27 | 28 | export default MasonryLayout; 29 | -------------------------------------------------------------------------------- /src/hooks/useTrash.ts: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { trashPrompt } from "@/api/prompts"; 3 | import { useStore } from "@/store/promptStore"; 4 | 5 | 6 | export const useTrash = () => { 7 | const [isTrashed, setIsTrashed] = useState(false); 8 | const { removeSinglePrompt } = useStore(); 9 | 10 | const handleTrash = async (tuneId:number, promptId: number) => { 11 | if (promptId) { 12 | const response = await trashPrompt(tuneId, promptId); 13 | if (response === 204) { 14 | setIsTrashed(!isTrashed); 15 | removeSinglePrompt(promptId); 16 | } 17 | } 18 | }; 19 | 20 | return { isTrashed, handleTrash }; 21 | }; 22 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | import { createHashRouter, RouterProvider } from "react-router-dom"; 3 | import { Gallery, UsersPrompts, Prompt } from "./pages"; 4 | import "./index.css"; 5 | import { ThemeProvider } from "@/components/theme-provider"; 6 | 7 | const router = createHashRouter( 8 | [ 9 | { 10 | path: "/", 11 | element: , 12 | }, 13 | { 14 | path: "/gallery", 15 | element: , 16 | }, 17 | { 18 | path: "/prompt/:id/:index", 19 | element: , 20 | }, 21 | ] 22 | ); 23 | 24 | createRoot(document.getElementById("root")!).render( 25 | 26 | 27 | 28 | ); 29 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": [ 11 | "./src/*" 12 | ] 13 | }, 14 | 15 | /* Bundler mode */ 16 | "moduleResolution": "bundler", 17 | "allowImportingTsExtensions": true, 18 | "isolatedModules": true, 19 | "moduleDetection": "force", 20 | "noEmit": true, 21 | "jsx": "react-jsx", 22 | 23 | /* Linting */ 24 | "strict": true, 25 | "noUnusedLocals": true, 26 | "noUnusedParameters": true, 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": ["src"] 30 | } 31 | -------------------------------------------------------------------------------- /src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes { } 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |