Skip to content

Commit

Permalink
Merge pull request #20 from kevinreber/add-create-image-logic
Browse files Browse the repository at this point in the history
Add create image logic and Set Details Page
  • Loading branch information
kevinreber authored Nov 4, 2024
2 parents 90daeff + b18f7a9 commit 6186aaa
Show file tree
Hide file tree
Showing 24 changed files with 3,041 additions and 154 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
env:
USE_MOCK_DALLE: "true"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand All @@ -22,6 +24,7 @@ jobs:
run: |
echo "DATABASE_URL=${{ secrets.DATABASE_URL }}" > .env
echo "SESSION_SECRET=${{ secrets.SESSION_SECRET }}" >> .env
echo "USE_MOCK_DALLE=true" >> .env
- name: Generate Prisma Client
run: npx prisma generate
- name: Start Server
Expand All @@ -30,6 +33,7 @@ jobs:
run: npx playwright test
env:
CI: true
USE_MOCK_DALLE: "true"
- uses: actions/upload-artifact@v4
if: always()
with:
Expand Down
91 changes: 75 additions & 16 deletions app/components/CreatePageForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from "react";
import { Form, useLoaderData } from "@remix-run/react";
import { Form, useLoaderData, useNavigation } from "@remix-run/react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardFooter } from "@/components/ui/card";
// import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { ScrollArea } from "@/components/ui/scroll-area";
Expand All @@ -13,11 +12,23 @@ import {
DialogOverlay,
DialogTitle,
} from "@/components/ui/dialog";
import { ChevronDown, Check } from "lucide-react";
import { ChevronDown, Check, Loader2 } from "lucide-react";
import { CreatePageLoader } from "~/routes/create";

const MOBILE_WIDTH = 768;
const MAX_TEXT_AREA_CHAR_COUNT = 300;
const MAX_TEXT_AREA_CHAR_COUNT = 500;
const DEFAULT_SELECTED_MODEL = {
name: "Stable Diffusion 1.6",
value: "stable-diffusion-v1-6",
image: "/assets/model-thumbs/sd-1-5.jpg",
description: "The most popular first-generation stable diffusion model.",
};

const DEFAULT_SELECTED_STYLE = {
name: "Anime",
value: "anime",
image: "/assets/preset-text-styles/anime-v2.jpg",
};

const Image = ({
src,
Expand All @@ -43,24 +54,41 @@ const Image = ({
);
};

const DEFAULT_SELECTED_MODEL = {
name: "Stable Diffusion 1.5",
value: "stable-diffusion-1-5",
image: "/assets/model-thumbs/sd-1-5.jpg",
description: "The most popular first-generation stable diffusion model.",
};
const NumberSelector = ({ value = 1, onChange }) => {
const numbers = [1, 2, 3, 4];

const DEFAULT_SELECTED_STYLE = {
name: "Anime",
value: "anime",
image: "/assets/preset-text-styles/anime-v2.jpg",
return (
<div className="space-y-2">
<label className="text-sm font-medium">Number of Images</label>
<div className="flex gap-2">
{numbers.map((number) => (
<Button
key={number}
type="button"
onClick={() => onChange(number)}
variant={value === number ? "secondary" : "outline"}
className={`w-14 h-[40px] text-lg ${
value === number
? "bg-zinc-700 hover:bg-zinc-600"
: "bg-zinc-800/50 hover:bg-zinc-700/50"
}`}
>
{number}
</Button>
))}
</div>
</div>
);
};

const CreatePageForm = () => {
const loaderData = useLoaderData<CreatePageLoader>();
const styleOptions = loaderData.styleOptions || [];
const modelOptions = loaderData.modelOptions || [];

const navigation = useNavigation();
const isSubmitting = navigation.state === "submitting";

const [isMobile, setIsMobile] = React.useState(false);
const [modelDialogOpen, setModelDialogOpen] = React.useState(false);
const [styleDialogOpen, setStyleDialogOpen] = React.useState(false);
Expand All @@ -74,6 +102,7 @@ const CreatePageForm = () => {
const [selectedSection, setSelectedSection] = React.useState<
"model" | "style" | null
>(null);
const [numImages, setNumImages] = React.useState(1);

React.useEffect(() => {
const checkMobile = () => setIsMobile(window.innerWidth < MOBILE_WIDTH);
Expand Down Expand Up @@ -109,8 +138,10 @@ const CreatePageForm = () => {
<input type="hidden" name="model" value={selectedModel.value} />
<Button
variant="outline"
type="button"
className="w-full justify-between mt-1 border"
onClick={handleModelClick}
disabled={isSubmitting}
>
<div className="flex justify-between pl-2 pr-2 w-full items-center">
<div className="flex items-center">
Expand All @@ -130,8 +161,10 @@ const CreatePageForm = () => {
<input type="hidden" name="style" value={selectedStyle.value} />
<Button
variant="outline"
type="button"
className="w-full justify-between mt-1 border"
onClick={handleStyleClick}
disabled={isSubmitting}
>
<div className="flex justify-between pl-2 pr-2 w-full items-center">
<div className="flex items-center">
Expand Down Expand Up @@ -161,9 +194,20 @@ const CreatePageForm = () => {
{prompt.length}/{MAX_TEXT_AREA_CHAR_COUNT}
</span>
</div>
<div>
<input type="hidden" name="numberOfImages" value={numImages} />
<NumberSelector value={numImages} onChange={setNumImages} />
</div>
</CardContent>
<CardFooter>
<Button className="w-full bg-pink-600 hover:bg-pink-700 text-white">
<Button
type="submit"
className="w-full bg-pink-600 hover:bg-pink-700 text-white"
disabled={isSubmitting}
>
{isSubmitting && (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
)}
CREATE
</Button>
</CardFooter>
Expand Down Expand Up @@ -266,8 +310,10 @@ const CreatePageForm = () => {
/>
<Button
variant="outline"
type="button"
className="w-full justify-between mt-1 border p-2"
onClick={handleModelClick}
disabled={isSubmitting}
>
<div className="flex justify-between pl-2 pr-2 w-full items-center">
<div className="flex items-center">
Expand All @@ -293,8 +339,10 @@ const CreatePageForm = () => {
/>
<Button
variant="outline"
type="button"
className="w-full justify-between mt-1 border p-2"
onClick={handleStyleClick}
disabled={isSubmitting}
>
<div className="flex justify-between pl-2 pr-2 w-full items-center">
<div className="flex items-center">
Expand Down Expand Up @@ -327,9 +375,20 @@ const CreatePageForm = () => {
{prompt.length}/{MAX_TEXT_AREA_CHAR_COUNT}
</span>
</div>
<div>
<input type="hidden" name="numberOfImages" value={numImages} />
<NumberSelector value={numImages} onChange={setNumImages} />
</div>
</CardContent>
<CardFooter>
<Button className="w-full bg-pink-600 hover:bg-pink-700 text-white">
<Button
type="submit"
className="w-full bg-pink-600 hover:bg-pink-700 text-white"
disabled={isSubmitting}
>
{isSubmitting && (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
)}
Generate
</Button>
</CardFooter>
Expand Down
10 changes: 5 additions & 5 deletions app/components/NavigationSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ const NavigationSidebar = () => {
icon: <Search className="md:h-4 md:w-4" />,
href: "/explore",
},
{
title: "Collections",
icon: <Layers className="md:h-4 md:w-4" />,
href: "/collections",
},
{
title: "Create",
icon: <PenTool className="md:h-4 md:w-4" />,
href: "/create",
},
// {
// title: "Collections",
// icon: <Layers className="md:h-4 md:w-4" />,
// href: "/collections",
// },
{
title: "Profile",
icon: <User className="md:h-4 md:w-4" />,
Expand Down
77 changes: 77 additions & 0 deletions app/pages/SetDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { useLoaderData } from "@remix-run/react";
import { PageContainer } from "~/components";
import { SetPageLoader } from "~/routes/set.$setId";

const Image = ({
src,
alt,
size = 24,
}: {
src: string;
alt: string;
size?: number;
}) => {
return (
<div
className="relative overflow-hidden m-auto w-full h-full"
style={{ maxWidth: size, maxHeight: size }}
>
<img
className="inset-0 object-cover cursor-pointer w-full h-full"
src={src}
alt={alt}
loading="lazy"
/>
</div>
);
};

const SetDetailsPage = () => {
const loaderData = useLoaderData<SetPageLoader>();
const setData = loaderData.data ?? {
images: [],
prompt: "",
createdAt: "",
user: {},
};
const setImages = setData.images;
const setPrompt = setData.prompt;
const setCreatedAt = setData.createdAt;
const setUser = setData.user;
console.log(setImages);
return (
<PageContainer>
<div className="flex flex-col justify-between w-full max-w-5xl m-auto">
<h1 className="text-2xl font-semibold mb-4">Set Details</h1>
<div className="w-full flex flex-col gap-4">
<div>
<div className="font-semibold">Prompt</div>
<div className="text-sm italic text-zinc-300">{setPrompt}</div>
</div>
<div>
<div className="font-semibold">Created At</div>
<div className="text-sm text-zinc-300">
{setCreatedAt} by{" "}
<a className="font-semibold text-blue-500" href="/">
{setUser.username}
</a>
</div>
</div>
<div>
<div className="font-semibold mb-2">Images</div>
<div className="flex flex-wrap gap-4">
{/* Render all images in the set */}
{setImages.map((image) => (
<div key={image.id}>
<Image src={image.url} alt={image.title} size={200} />
</div>
))}
</div>
</div>
</div>
</div>
</PageContainer>
);
};

export default SetDetailsPage;
2 changes: 1 addition & 1 deletion app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
userData = await getLoggedInUserGoogleSSOData(sessionAuth);
}

console.log("userData in root loader:", userData);
// console.log("userData in root loader:", userData);

return json(
{
Expand Down
Loading

0 comments on commit 6186aaa

Please sign in to comment.