add pagination page + display model name
Browse files- app/_actions/logos.ts +24 -1
- app/_components/gallery/index.tsx +5 -1
- app/_components/gallery/list.tsx +51 -0
- app/_components/generation/index.tsx +4 -1
- app/gallery/page.tsx +19 -0
- app/layout.tsx +18 -0
- app/page.tsx +2 -2
- components/_navigation/index.tsx +7 -2
- package-lock.json +20 -0
- package.json +1 -0
app/_actions/logos.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
import prisma from "@/_utils/prisma";
|
4 |
|
5 |
-
export const
|
6 |
const images = await prisma.logo.findMany({
|
7 |
select: {
|
8 |
id: true,
|
@@ -14,3 +14,26 @@ export const getLogos = async () => {
|
|
14 |
});
|
15 |
return images.map((image) => image.id);
|
16 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
import prisma from "@/_utils/prisma";
|
4 |
|
5 |
+
export const getLastLogos = async () => {
|
6 |
const images = await prisma.logo.findMany({
|
7 |
select: {
|
8 |
id: true,
|
|
|
14 |
});
|
15 |
return images.map((image) => image.id);
|
16 |
};
|
17 |
+
|
18 |
+
const ITEMS_PER_PAGE = 24;
|
19 |
+
|
20 |
+
export const getLogos = async (page: number = 0) => {
|
21 |
+
const images = await prisma.logo.findMany({
|
22 |
+
select: {
|
23 |
+
id: true,
|
24 |
+
},
|
25 |
+
skip: page * ITEMS_PER_PAGE,
|
26 |
+
take: ITEMS_PER_PAGE,
|
27 |
+
orderBy: {
|
28 |
+
id: "desc",
|
29 |
+
},
|
30 |
+
});
|
31 |
+
|
32 |
+
const total = await prisma.logo.count();
|
33 |
+
const hasMore = total > (page + 1) * ITEMS_PER_PAGE;
|
34 |
+
|
35 |
+
return {
|
36 |
+
logos: images.map((image) => image.id),
|
37 |
+
hasMore,
|
38 |
+
};
|
39 |
+
};
|
app/_components/gallery/index.tsx
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
export const Gallery = ({ logos }: { logos: Array<number> }) => {
|
2 |
return (
|
3 |
<section id="gallery" className="w-full py-10 lg:py-16">
|
@@ -10,10 +12,12 @@ export const Gallery = ({ logos }: { logos: Array<number> }) => {
|
|
10 |
</h3>
|
11 |
<div className="max-lg:grid max-lg:grid-cols-2 lg:flex lg:items-start lg:justify-center gap-6 flex-wrap">
|
12 |
{logos.map((index) => (
|
13 |
-
<
|
14 |
key={index}
|
15 |
src={`/api/images/${index}`}
|
16 |
alt="Generated logo"
|
|
|
|
|
17 |
className="rounded-2xl w-full lg:size-72 object-cover"
|
18 |
/>
|
19 |
))}
|
|
|
1 |
+
import Image from "next/image";
|
2 |
+
|
3 |
export const Gallery = ({ logos }: { logos: Array<number> }) => {
|
4 |
return (
|
5 |
<section id="gallery" className="w-full py-10 lg:py-16">
|
|
|
12 |
</h3>
|
13 |
<div className="max-lg:grid max-lg:grid-cols-2 lg:flex lg:items-start lg:justify-center gap-6 flex-wrap">
|
14 |
{logos.map((index) => (
|
15 |
+
<Image
|
16 |
key={index}
|
17 |
src={`/api/images/${index}`}
|
18 |
alt="Generated logo"
|
19 |
+
width={500}
|
20 |
+
height={500}
|
21 |
className="rounded-2xl w-full lg:size-72 object-cover"
|
22 |
/>
|
23 |
))}
|
app/_components/gallery/list.tsx
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use client";
|
2 |
+
|
3 |
+
import InfiniteScroll from "react-infinite-scroll-component";
|
4 |
+
import Image from "next/image";
|
5 |
+
import { useState } from "react";
|
6 |
+
import { getLogos } from "@/app/_actions/logos";
|
7 |
+
|
8 |
+
export const InfiniteGallery = ({
|
9 |
+
logos: initialLogos,
|
10 |
+
hasMore: initialHasMore,
|
11 |
+
}: {
|
12 |
+
logos: Array<number>;
|
13 |
+
hasMore: boolean;
|
14 |
+
}) => {
|
15 |
+
const [page, setPage] = useState(0);
|
16 |
+
const [logos, setLogos] = useState([...initialLogos]);
|
17 |
+
const [hasMore, setHasMore] = useState(initialHasMore);
|
18 |
+
|
19 |
+
const fetchMoreData = async () => {
|
20 |
+
const logos = await getLogos(page + 1);
|
21 |
+
setLogos([...logos.logos]);
|
22 |
+
setHasMore(logos.hasMore);
|
23 |
+
setPage(page + 1);
|
24 |
+
};
|
25 |
+
|
26 |
+
return (
|
27 |
+
<InfiniteScroll
|
28 |
+
dataLength={logos.length} //This is important field to render the next data
|
29 |
+
next={fetchMoreData}
|
30 |
+
hasMore={hasMore}
|
31 |
+
loader={<h4>Loading...</h4>}
|
32 |
+
className="max-lg:grid max-lg:grid-cols-2 lg:flex lg:items-start lg:justify-center gap-6 flex-wrap"
|
33 |
+
endMessage={
|
34 |
+
<div className="w-full max-lg:col-span-2 text-zinc-400 text-center">
|
35 |
+
Yay! You have seen it all
|
36 |
+
</div>
|
37 |
+
}
|
38 |
+
>
|
39 |
+
{logos.map((index) => (
|
40 |
+
<Image
|
41 |
+
key={index}
|
42 |
+
src={`/api/images/${index}`}
|
43 |
+
alt="Generated logo"
|
44 |
+
width={500}
|
45 |
+
height={500}
|
46 |
+
className="rounded-2xl w-full lg:size-72 object-cover"
|
47 |
+
/>
|
48 |
+
))}
|
49 |
+
</InfiniteScroll>
|
50 |
+
);
|
51 |
+
};
|
app/_components/generation/index.tsx
CHANGED
@@ -11,6 +11,7 @@ import { Industry } from "./step/industry";
|
|
11 |
import { Description } from "./step/description";
|
12 |
import classNames from "classnames";
|
13 |
import { toast } from "react-toastify";
|
|
|
14 |
|
15 |
export const Generation = () => {
|
16 |
const [form, setForm] = useState<Form>({
|
@@ -63,10 +64,12 @@ export const Generation = () => {
|
|
63 |
</div>
|
64 |
{result && (
|
65 |
<div className="lg:col-span-3 flex items-center justify-center rounded-3xl">
|
66 |
-
<
|
67 |
src={`/api/images/${result}`}
|
68 |
alt="Generated logo"
|
69 |
className="h-[300px]"
|
|
|
|
|
70 |
/>
|
71 |
</div>
|
72 |
)}
|
|
|
11 |
import { Description } from "./step/description";
|
12 |
import classNames from "classnames";
|
13 |
import { toast } from "react-toastify";
|
14 |
+
import Image from "next/image";
|
15 |
|
16 |
export const Generation = () => {
|
17 |
const [form, setForm] = useState<Form>({
|
|
|
64 |
</div>
|
65 |
{result && (
|
66 |
<div className="lg:col-span-3 flex items-center justify-center rounded-3xl">
|
67 |
+
<Image
|
68 |
src={`/api/images/${result}`}
|
69 |
alt="Generated logo"
|
70 |
className="h-[300px]"
|
71 |
+
width={400}
|
72 |
+
height={400}
|
73 |
/>
|
74 |
</div>
|
75 |
)}
|
app/gallery/page.tsx
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { InfiniteGallery } from "@/app/_components/gallery/list";
|
2 |
+
import { getLogos } from "@/app/_actions/logos";
|
3 |
+
|
4 |
+
async function lastLogos() {
|
5 |
+
const logos = await getLogos();
|
6 |
+
return logos;
|
7 |
+
}
|
8 |
+
export const revalidate = 0;
|
9 |
+
|
10 |
+
export default async function Gallery() {
|
11 |
+
const { hasMore, logos } = await lastLogos();
|
12 |
+
return (
|
13 |
+
<section className="w-full py-10 lg:py-16">
|
14 |
+
<div className="max-lg:grid max-lg:grid-cols-2 lg:flex lg:items-start lg:justify-center gap-6 flex-wrap">
|
15 |
+
<InfiniteGallery logos={logos} hasMore={hasMore} />
|
16 |
+
</div>
|
17 |
+
</section>
|
18 |
+
);
|
19 |
+
}
|
app/layout.tsx
CHANGED
@@ -56,6 +56,24 @@ export default function RootLayout({
|
|
56 |
<div className="h-screen w-full overflow-auto font-[family-name:var(--font-nohemi-sans)] p-6 scroll-smooth">
|
57 |
<Navigation />
|
58 |
{children}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
</div>
|
60 |
<ToastContainer />
|
61 |
</body>
|
|
|
56 |
<div className="h-screen w-full overflow-auto font-[family-name:var(--font-nohemi-sans)] p-6 scroll-smooth">
|
57 |
<Navigation />
|
58 |
{children}
|
59 |
+
<footer className="mt-4 w-full max-w-4xl mx-auto border-t border-zinc-800 pt-8 pb-3 text-center">
|
60 |
+
<p className="text-sm text-zinc-400">
|
61 |
+
Powered by{" "}
|
62 |
+
<a
|
63 |
+
href="https://github.com/huggingface/huggingface.js"
|
64 |
+
className="font-mono text-amber-500 hover:text-amber-400"
|
65 |
+
>
|
66 |
+
huggingface.js
|
67 |
+
</a>{" "}
|
68 |
+
and{" "}
|
69 |
+
<a
|
70 |
+
href="https://huggingface.co/Shakker-Labs/FLUX.1-dev-LoRA-Logo-Design"
|
71 |
+
className="font-mono text-zinc-100 hover:text-white"
|
72 |
+
>
|
73 |
+
Shakker-Labs/FLUX.1-dev-LoRA-Logo-Design
|
74 |
+
</a>
|
75 |
+
</p>
|
76 |
+
</footer>
|
77 |
</div>
|
78 |
<ToastContainer />
|
79 |
</body>
|
app/page.tsx
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
-
import {
|
2 |
import { Gallery } from "./_components/gallery";
|
3 |
import { Generation } from "./_components/generation";
|
4 |
import { HeroHeader } from "./_components/hero-header";
|
5 |
|
6 |
async function lastLogos() {
|
7 |
-
const logos = await
|
8 |
return logos;
|
9 |
}
|
10 |
export const revalidate = 0;
|
|
|
1 |
+
import { getLastLogos } from "./_actions/logos";
|
2 |
import { Gallery } from "./_components/gallery";
|
3 |
import { Generation } from "./_components/generation";
|
4 |
import { HeroHeader } from "./_components/hero-header";
|
5 |
|
6 |
async function lastLogos() {
|
7 |
+
const logos = await getLastLogos();
|
8 |
return logos;
|
9 |
}
|
10 |
export const revalidate = 0;
|
components/_navigation/index.tsx
CHANGED
@@ -2,10 +2,11 @@ import Image from "next/image";
|
|
2 |
|
3 |
import Arrow from "@/assets/svg/arrow.svg";
|
4 |
import Logo from "@/assets/logo.png";
|
|
|
5 |
|
6 |
export const Navigation = () => {
|
7 |
return (
|
8 |
-
<div className="rounded-full bg-zinc-950 border border-white/10 px-6 py-2.5 lg:py-4 flex items-center justify-center lg:justify-between max-w-max lg:max-w-xl lg:w-full mx-auto shadow-md relative">
|
9 |
<div className="flex items-center justify-center gap-3 relative">
|
10 |
<div className="relative">
|
11 |
<Image src={Logo} alt="logo" className="size-6" />
|
@@ -20,7 +21,11 @@ export const Navigation = () => {
|
|
20 |
</div>
|
21 |
<p className="font-semibold text-lg text-white">LogoAI</p>
|
22 |
</div>
|
23 |
-
<ul className="hidden lg:flex items-center justify-right gap-3
|
|
|
|
|
|
|
|
|
24 |
</div>
|
25 |
);
|
26 |
};
|
|
|
2 |
|
3 |
import Arrow from "@/assets/svg/arrow.svg";
|
4 |
import Logo from "@/assets/logo.png";
|
5 |
+
import Link from "next/link";
|
6 |
|
7 |
export const Navigation = () => {
|
8 |
return (
|
9 |
+
<div className="rounded-full bg-zinc-950 border border-white/10 px-6 py-2.5 lg:pr-7 lg:py-4 flex items-center justify-center lg:justify-between max-w-max lg:max-w-xl lg:w-full mx-auto shadow-md relative">
|
10 |
<div className="flex items-center justify-center gap-3 relative">
|
11 |
<div className="relative">
|
12 |
<Image src={Logo} alt="logo" className="size-6" />
|
|
|
21 |
</div>
|
22 |
<p className="font-semibold text-lg text-white">LogoAI</p>
|
23 |
</div>
|
24 |
+
<ul className="hidden lg:flex items-center justify-right gap-3">
|
25 |
+
<li className="text-zinc-400 hover:text-white">
|
26 |
+
<Link href="/gallery">Gallery</Link>
|
27 |
+
</li>
|
28 |
+
</ul>
|
29 |
</div>
|
30 |
);
|
31 |
};
|
package-lock.json
CHANGED
@@ -16,6 +16,7 @@
|
|
16 |
"react": "^18",
|
17 |
"react-dom": "^18",
|
18 |
"react-icons": "^5.3.0",
|
|
|
19 |
"react-toastify": "^10.0.5",
|
20 |
"react-use": "^17.5.1"
|
21 |
},
|
@@ -4497,6 +4498,25 @@
|
|
4497 |
"react": "*"
|
4498 |
}
|
4499 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4500 |
"node_modules/react-is": {
|
4501 |
"version": "16.13.1",
|
4502 |
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
|
|
16 |
"react": "^18",
|
17 |
"react-dom": "^18",
|
18 |
"react-icons": "^5.3.0",
|
19 |
+
"react-infinite-scroll-component": "^6.1.0",
|
20 |
"react-toastify": "^10.0.5",
|
21 |
"react-use": "^17.5.1"
|
22 |
},
|
|
|
4498 |
"react": "*"
|
4499 |
}
|
4500 |
},
|
4501 |
+
"node_modules/react-infinite-scroll-component": {
|
4502 |
+
"version": "6.1.0",
|
4503 |
+
"resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz",
|
4504 |
+
"integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==",
|
4505 |
+
"dependencies": {
|
4506 |
+
"throttle-debounce": "^2.1.0"
|
4507 |
+
},
|
4508 |
+
"peerDependencies": {
|
4509 |
+
"react": ">=16.0.0"
|
4510 |
+
}
|
4511 |
+
},
|
4512 |
+
"node_modules/react-infinite-scroll-component/node_modules/throttle-debounce": {
|
4513 |
+
"version": "2.3.0",
|
4514 |
+
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz",
|
4515 |
+
"integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==",
|
4516 |
+
"engines": {
|
4517 |
+
"node": ">=8"
|
4518 |
+
}
|
4519 |
+
},
|
4520 |
"node_modules/react-is": {
|
4521 |
"version": "16.13.1",
|
4522 |
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
package.json
CHANGED
@@ -17,6 +17,7 @@
|
|
17 |
"react": "^18",
|
18 |
"react-dom": "^18",
|
19 |
"react-icons": "^5.3.0",
|
|
|
20 |
"react-toastify": "^10.0.5",
|
21 |
"react-use": "^17.5.1"
|
22 |
},
|
|
|
17 |
"react": "^18",
|
18 |
"react-dom": "^18",
|
19 |
"react-icons": "^5.3.0",
|
20 |
+
"react-infinite-scroll-component": "^6.1.0",
|
21 |
"react-toastify": "^10.0.5",
|
22 |
"react-use": "^17.5.1"
|
23 |
},
|