This commit is contained in:
@@ -4,52 +4,79 @@ import Topbar from '@/components/Topbar';
|
||||
import { ImagesResponse, TagsResponse } from '@/interfaces/api';
|
||||
import { PaginatorPosition } from '@/interfaces/paginator';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { Suspense } from 'react';
|
||||
|
||||
export default async function GalleryPage({ params }: { params: Promise<{ page: number; tag: string }> }) {
|
||||
const { tag, page } = await params;
|
||||
interface GalleryPageProps {
|
||||
params: Promise<{
|
||||
tag: string;
|
||||
page: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
const fetchImages = async () => {
|
||||
const apiUrl = new URL(
|
||||
`/api/images?page=${page}&tag=${tag === 'all' ? '' : tag}`,
|
||||
process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000',
|
||||
);
|
||||
const response = await fetch(apiUrl.toString());
|
||||
if (!response.ok) {
|
||||
throw new Error(`Network response was not ok: ${response.statusText}`);
|
||||
}
|
||||
export default async function GalleryPage({
|
||||
params,
|
||||
}: GalleryPageProps) {
|
||||
const { tag, page: pageParam } = await params;
|
||||
const page = Number.parseInt(pageParam, 10);
|
||||
|
||||
return (await response.json()) as ImagesResponse;
|
||||
};
|
||||
|
||||
const fetchTags = async () => {
|
||||
const apiUrl = new URL('/api/tags', process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000');
|
||||
const response = await fetch(apiUrl.toString());
|
||||
if (!response.ok) {
|
||||
throw new Error(`Network response was not ok: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return (await response.json()) as TagsResponse;
|
||||
};
|
||||
|
||||
const images = await fetchImages();
|
||||
const tags = await fetchTags();
|
||||
|
||||
if (images.totalPages < page && images.totalPages > 0) {
|
||||
redirect(`/gallery/${tag}/${images.totalPages}`);
|
||||
if (!Number.isInteger(page) || page < 1) {
|
||||
redirect(`/gallery/${encodeURIComponent(tag)}/1`);
|
||||
}
|
||||
|
||||
if (page <= 0) {
|
||||
redirect(`/gallery/${tag}/1`);
|
||||
const siteUrl =
|
||||
process.env.NEXT_PUBLIC_SITE_URL ?? 'http://localhost:3000';
|
||||
|
||||
const imagesUrl = new URL('/api/images', siteUrl);
|
||||
imagesUrl.searchParams.set('page', String(page));
|
||||
imagesUrl.searchParams.set('tag', tag === 'all' ? '' : tag);
|
||||
|
||||
const tagsUrl = new URL('/api/tags', siteUrl);
|
||||
|
||||
const [imagesResponse, tagsResponse] = await Promise.all([
|
||||
fetch(imagesUrl, {
|
||||
cache: 'no-store',
|
||||
}),
|
||||
fetch(tagsUrl, {
|
||||
cache: 'no-store',
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!imagesResponse.ok) {
|
||||
throw new Error(
|
||||
`Failed to load images: ${imagesResponse.status} ${imagesResponse.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!tagsResponse.ok) {
|
||||
throw new Error(
|
||||
`Failed to load tags: ${tagsResponse.status} ${tagsResponse.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const images = (await imagesResponse.json()) as ImagesResponse;
|
||||
const tags = (await tagsResponse.json()) as TagsResponse;
|
||||
|
||||
if (images.totalPages > 0 && page > images.totalPages) {
|
||||
redirect(
|
||||
`/gallery/${encodeURIComponent(tag)}/${images.totalPages}`,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<div>Loading gallery...</div>}>
|
||||
<Topbar activeTag={tag} tags={tags} page={page} totalPages={images.totalPages} />
|
||||
<Gallery initialImages={images.images} />
|
||||
<Paginator page={page} totalPages={images.totalPages} position={PaginatorPosition.BOTTOM} />
|
||||
</Suspense>
|
||||
<Topbar
|
||||
activeTag={tag}
|
||||
tags={tags}
|
||||
page={page}
|
||||
totalPages={images.totalPages}
|
||||
/>
|
||||
|
||||
<Gallery initialImages={images.images} />
|
||||
|
||||
<Paginator
|
||||
page={page}
|
||||
totalPages={images.totalPages}
|
||||
position={PaginatorPosition.BOTTOM}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export default async function Page({ params }: { params: Promise<{ page: number; tag: string }> }) {
|
||||
redirect(`gallery/${(await params).tag}/1`);
|
||||
interface TagPageProps {
|
||||
params: Promise<{
|
||||
tag: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export default async function TagPage({ params }: TagPageProps) {
|
||||
const { tag } = await params;
|
||||
|
||||
redirect(`/gallery/${encodeURIComponent(tag)}/1`);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export default async function Page() {
|
||||
redirect(`gallery/all/1`);
|
||||
redirect(`/gallery/all/1`);
|
||||
}
|
||||
|
||||
+25
-11
@@ -1,6 +1,8 @@
|
||||
* {
|
||||
--header-height: 50px;
|
||||
--color-accent: #3cdbc0;
|
||||
--color-background: #0d1113;
|
||||
--color-surface: #151b1d;
|
||||
}
|
||||
|
||||
:root {
|
||||
@@ -8,9 +10,9 @@
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color-scheme: dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: rgb(27, 27, 27);
|
||||
background-color: var(--color-background);
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
@@ -18,22 +20,34 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
body,
|
||||
#root {
|
||||
html {
|
||||
min-height: 100%;
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-height: 100vh;
|
||||
font-size: 16px;
|
||||
letter-spacing: 1px;
|
||||
scrollbar-gutter: stable;
|
||||
|
||||
background-color: var(--color-background);
|
||||
background-image:
|
||||
radial-gradient(circle at 85% 10%, rgba(60, 219, 192, 0.12) 0%, transparent 32%),
|
||||
radial-gradient(circle at 10% 85%, rgba(27, 115, 124, 0.08) 0%, transparent 38%),
|
||||
linear-gradient(145deg, #0d1113 0%, #101719 50%, #0b0e10 100%);
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 16px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
letter-spacing: 1px;
|
||||
min-height: 100vh;
|
||||
scrollbar-gutter: stable;
|
||||
background: linear-gradient(-120deg, rgba(0, 0, 0, 0), #06565a49);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
padding: 0 40px;
|
||||
overflow: hidden;
|
||||
background-image: url('/landing-page.jpg');
|
||||
min-height: calc(100vh - var(--header-height));
|
||||
background-size: cover;
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
|
||||
Reference in New Issue
Block a user