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 |
},
|