diff --git a/package-lock.json b/package-lock.json index 16e6b429..c437d0ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "akari", - "version": "2.0.8", + "version": "2.0.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "akari", - "version": "2.0.8", + "version": "2.0.9", "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", @@ -26,7 +26,7 @@ "embla-carousel-react": "^8.6.0", "js-cookie": "^3.0.5", "lucide-react": "^0.575.0", - "next": "^16.2.1", + "next": "^16.2.2", "next-themes": "^0.4.6", "openapi-fetch": "^0.17.0", "radix-ui": "^1.4.3", @@ -1320,9 +1320,9 @@ } }, "node_modules/@next/env": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.1.tgz", - "integrity": "sha512-n8P/HCkIWW+gVal2Z8XqXJ6aB3J0tuM29OcHpCsobWlChH/SITBs1DFBk/HajgrwDkqqBXPbuUuzgDvUekREPg==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.2.tgz", + "integrity": "sha512-LqSGz5+xGk9EL/iBDr2yo/CgNQV6cFsNhRR2xhSXYh7B/hb4nePCxlmDvGEKG30NMHDFf0raqSyOZiQrO7BkHQ==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1336,9 +1336,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.1.tgz", - "integrity": "sha512-BwZ8w8YTaSEr2HIuXLMLxIdElNMPvY9fLqb20LX9A9OMGtJilhHLbCL3ggyd0TwjmMcTxi0XXt+ur1vWUoxj2Q==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.2.tgz", + "integrity": "sha512-B92G3ulrwmkDSEJEp9+XzGLex5wC1knrmCSIylyVeiAtCIfvEJYiN3v5kXPlYt5R4RFlsfO/v++aKV63Acrugg==", "cpu": [ "arm64" ], @@ -1352,9 +1352,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.1.tgz", - "integrity": "sha512-/vrcE6iQSJq3uL3VGVHiXeaKbn8Es10DGTGRJnRZlkNQQk3kaNtAJg8Y6xuAlrx/6INKVjkfi5rY0iEXorZ6uA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.2.tgz", + "integrity": "sha512-7ZwSgNKJNQiwW0CKhNm9B1WS2L1Olc4B2XY0hPYCAL3epFnugMhuw5TMWzMilQ3QCZcCHoYm9NGWTHbr5REFxw==", "cpu": [ "x64" ], @@ -1368,9 +1368,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.1.tgz", - "integrity": "sha512-uLn+0BK+C31LTVbQ/QU+UaVrV0rRSJQ8RfniQAHPghDdgE+SlroYqcmFnO5iNjNfVWCyKZHYrs3Nl0mUzWxbBw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.2.tgz", + "integrity": "sha512-c3m8kBHMziMgo2fICOP/cd/5YlrxDU5YYjAJeQLyFsCqVF8xjOTH/QYG4a2u48CvvZZSj1eHQfBCbyh7kBr30Q==", "cpu": [ "arm64" ], @@ -1384,9 +1384,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.1.tgz", - "integrity": "sha512-ssKq6iMRnHdnycGp9hCuGnXJZ0YPr4/wNwrfE5DbmvEcgl9+yv97/Kq3TPVDfYome1SW5geciLB9aiEqKXQjlQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.2.tgz", + "integrity": "sha512-VKLuscm0P/mIfzt+SDdn2+8TNNJ7f0qfEkA+az7OqQbjzKdBxAHs0UvuiVoCtbwX+dqMEL9U54b5wQ/aN3dHeg==", "cpu": [ "arm64" ], @@ -1400,9 +1400,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.1.tgz", - "integrity": "sha512-HQm7SrHRELJ30T1TSmT706IWovFFSRGxfgUkyWJZF/RKBMdbdRWJuFrcpDdE5vy9UXjFOx6L3mRdqH04Mmx0hg==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.2.tgz", + "integrity": "sha512-kU3OPHJq6sBUjOk7wc5zJ7/lipn8yGldMoAv4z67j6ov6Xo/JvzA7L7LCsyzzsXmgLEhk3Qkpwqaq/1+XpNR3g==", "cpu": [ "x64" ], @@ -1416,9 +1416,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.1.tgz", - "integrity": "sha512-aV2iUaC/5HGEpbBkE+4B8aHIudoOy5DYekAKOMSHoIYQ66y/wIVeaRx8MS2ZMdxe/HIXlMho4ubdZs/J8441Tg==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.2.tgz", + "integrity": "sha512-CKXRILyErMtUftp+coGcZ38ZwE/Aqq45VMCcRLr2I4OXKrgxIBDXHnBgeX/UMil0S09i2JXaDL3Q+TN8D/cKmg==", "cpu": [ "x64" ], @@ -1432,9 +1432,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.1.tgz", - "integrity": "sha512-IXdNgiDHaSk0ZUJ+xp0OQTdTgnpx1RCfRTalhn3cjOP+IddTMINwA7DXZrwTmGDO8SUr5q2hdP/du4DcrB1GxA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.2.tgz", + "integrity": "sha512-sS/jSk5VUoShUqINJFvNjVT7JfR5ORYj/+/ZpOYbbIohv/lQfduWnGAycq2wlknbOql2xOR0DoV0s6Xfcy49+g==", "cpu": [ "arm64" ], @@ -1448,9 +1448,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.1.tgz", - "integrity": "sha512-qvU+3a39Hay+ieIztkGSbF7+mccbbg1Tk25hc4JDylf8IHjYmY/Zm64Qq1602yPyQqvie+vf5T/uPwNxDNIoeg==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.2.tgz", + "integrity": "sha512-aHaKceJgdySReT7qeck5oShucxWRiiEuwCGK8HHALe6yZga8uyFpLkPgaRw3kkF04U7ROogL/suYCNt/+CuXGA==", "cpu": [ "x64" ], @@ -3189,9 +3189,9 @@ "license": "Python-2.0" }, "node_modules/@redocly/openapi-core/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -4155,9 +4155,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -4885,9 +4885,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -7006,9 +7006,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -8548,9 +8548,9 @@ } }, "node_modules/mjml-cli/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -8954,12 +8954,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/next/-/next-16.2.1.tgz", - "integrity": "sha512-VaChzNL7o9rbfdt60HUj8tev4m6d7iC1igAy157526+cJlXOQu5LzsBXNT+xaJnTP/k+utSX5vMv7m0G+zKH+Q==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.2.tgz", + "integrity": "sha512-i6AJdyVa4oQjyvX/6GeER8dpY/xlIV+4NMv/svykcLtURJSy/WzDnnUk/TM4d0uewFHK7xSQz4TbIwPgjky+3A==", "license": "MIT", "dependencies": { - "@next/env": "16.2.1", + "@next/env": "16.2.2", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", @@ -8973,14 +8973,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.2.1", - "@next/swc-darwin-x64": "16.2.1", - "@next/swc-linux-arm64-gnu": "16.2.1", - "@next/swc-linux-arm64-musl": "16.2.1", - "@next/swc-linux-x64-gnu": "16.2.1", - "@next/swc-linux-x64-musl": "16.2.1", - "@next/swc-win32-arm64-msvc": "16.2.1", - "@next/swc-win32-x64-msvc": "16.2.1", + "@next/swc-darwin-arm64": "16.2.2", + "@next/swc-darwin-x64": "16.2.2", + "@next/swc-linux-arm64-gnu": "16.2.2", + "@next/swc-linux-arm64-musl": "16.2.2", + "@next/swc-linux-x64-gnu": "16.2.2", + "@next/swc-linux-x64-musl": "16.2.2", + "@next/swc-win32-arm64-msvc": "16.2.2", + "@next/swc-win32-x64-msvc": "16.2.2", "sharp": "^0.34.5" }, "peerDependencies": { diff --git a/package.json b/package.json index 4e0927c4..79aeae86 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "akari", - "version": "2.0.8", + "version": "2.0.9", "homepage": "https://github.com/sn0w12/Akari#readme", "engines": { "node": ">=20" @@ -39,7 +39,7 @@ "embla-carousel-react": "^8.6.0", "js-cookie": "^3.0.5", "lucide-react": "^0.575.0", - "next": "^16.2.1", + "next": "^16.2.2", "next-themes": "^0.4.6", "openapi-fetch": "^0.17.0", "radix-ui": "^1.4.3", diff --git a/src/app/(default)/author/[id]/page.tsx b/src/app/(default)/author/[id]/page.tsx index 0538254e..f90b1a4e 100644 --- a/src/app/(default)/author/[id]/page.tsx +++ b/src/app/(default)/author/[id]/page.tsx @@ -35,7 +35,7 @@ export async function generateMetadata( ): Promise { const { id, page } = await props.params; const name = id.replaceAll("-", " "); - const description = `View all manga by ${name} on Akari for free.`; + const description = `Browse the full manga catalog by ${name} on Akari.`; const { data } = await getAuthor(name, page ? parseInt(page) : 1); diff --git a/src/app/(default)/genre/[id]/page.tsx b/src/app/(default)/genre/[id]/page.tsx index 688fae19..8571350e 100644 --- a/src/app/(default)/genre/[id]/page.tsx +++ b/src/app/(default)/genre/[id]/page.tsx @@ -29,7 +29,7 @@ export async function generateStaticParams() { export async function generateMetadata(props: PageProps): Promise { const { id, page } = await props.params; const name = id.replaceAll("-", " "); - const description = `View all ${name} manga`; + const description = `Browse manga in the ${name} genre and find your next read on Akari.`; const { data } = await getGenre(name, page ? parseInt(page) : 1); diff --git a/src/app/(default)/latest/[page]/page.tsx b/src/app/(default)/latest/[page]/page.tsx index a2c77ec5..a61e3f23 100644 --- a/src/app/(default)/latest/[page]/page.tsx +++ b/src/app/(default)/latest/[page]/page.tsx @@ -1,6 +1,5 @@ -import { createMetadata } from "@/lib/seo"; import { Metadata } from "next"; -import Page from "../page"; +import Page, { generateMetadata as parentGenerateMetadata } from "../page"; interface PageProps { params: Promise<{ page: string }>; @@ -10,12 +9,9 @@ export async function generateStaticParams() { return [{ page: "2" }]; } -export const metadata: Metadata = createMetadata({ - title: "Latest Releases", - description: "Read the latest manga releases for free on Akari.", - image: "/og/akari.webp", - canonicalPath: "/latest", -}); +export async function generateMetadata(props: PageProps): Promise { + return parentGenerateMetadata(props); +} export default async function LatestPage(props: PageProps) { return ; diff --git a/src/app/(default)/manga/[id]/[scanlator]/[subId]/page.tsx b/src/app/(default)/manga/[id]/[scanlator]/[subId]/page.tsx index ed575b19..523aa68e 100644 --- a/src/app/(default)/manga/[id]/[scanlator]/[subId]/page.tsx +++ b/src/app/(default)/manga/[id]/[scanlator]/[subId]/page.tsx @@ -88,6 +88,10 @@ export async function generateMetadata({ description: description, image: createOgImage("manga", chapter.mangaId), canonicalPath: `/manga/${mangaParams.id}/${mangaParams.scanlator}/${mangaParams.subId}`, + pagination: { + next: `/manga/${mangaParams.id}/${mangaParams.scanlator}/${chapter.nextChapter}`, + previous: `/manga/${mangaParams.id}/${mangaParams.scanlator}/${chapter.lastChapter}`, + }, }); } diff --git a/src/app/(default)/manga/[id]/page.tsx b/src/app/(default)/manga/[id]/page.tsx index d9daab32..7aec055d 100644 --- a/src/app/(default)/manga/[id]/page.tsx +++ b/src/app/(default)/manga/[id]/page.tsx @@ -13,11 +13,6 @@ export interface MangaPageProps { params: Promise<{ id: string }>; } -function truncate(text: string, maxLength: number): string { - if (text.length <= maxLength) return text; - return text.slice(0, maxLength - 1).trimEnd() + "…"; -} - export async function generateStaticParams() { if (STATIC_GENERATION_DISABLED) { return [{ id: "737e7c9c-abac-4977-9c56-0a4ff26b295e" }]; @@ -41,11 +36,9 @@ export async function generateMetadata( } const manga = data.data; - const description = truncate(manga.description, 300); - return createMetadata({ title: manga.title, - description: description, + description: manga.description, image: createOgImage("manga", manga.id), canonicalPath: `/manga/${params.id}`, }); diff --git a/src/app/(default)/page.tsx b/src/app/(default)/page.tsx index 3e940a11..d8633e32 100644 --- a/src/app/(default)/page.tsx +++ b/src/app/(default)/page.tsx @@ -20,7 +20,7 @@ import { getPopularData } from "./popular/page"; export const metadata: Metadata = createMetadata({ title: "Akari Manga", - description: "Read manga for free on Akari.", + description: "Browse popular manga and the latest releases on Akari.", image: "/og/akari.webp", canonicalPath: "/", pagination: { diff --git a/src/components/manga-details/chapters-client.tsx b/src/components/manga-details/chapters-client.tsx index c7fda3f7..5104be8a 100644 --- a/src/components/manga-details/chapters-client.tsx +++ b/src/components/manga-details/chapters-client.tsx @@ -56,24 +56,26 @@ function ChaptersControls({ return (
- + {scanlatorOptions.length > 1 && ( + + )}
{isLoading || isUserLoading ? ( ) : ( Go to First Chapter diff --git a/src/components/manga-details/chapters.tsx b/src/components/manga-details/chapters.tsx index 04eb537b..7cb638c2 100644 --- a/src/components/manga-details/chapters.tsx +++ b/src/components/manga-details/chapters.tsx @@ -1,5 +1,7 @@ import { client, serverHeaders } from "@/lib/api"; +import { createJsonLd } from "@/lib/seo"; import { cacheLife, cacheTag } from "next/cache"; +import { CollectionPage } from "schema-dts"; import { ChaptersSection } from "./chapters-client"; export async function getMangaChapters(id: string) { @@ -35,12 +37,40 @@ export async function ChaptersSectionServer({ data.data.preferredScanlatorId ?? data.data.chapters[0]?.scanlatorId ?? 1; + + const chapterListJsonLd = createJsonLd({ + "@type": "CollectionPage", + url: `/manga/${id}`, + name: "Chapters", + mainEntity: { + "@type": "ItemList", + url: `/manga/${id}`, + numberOfItems: data.data.chapters.length, + itemListElement: data.data.chapters.map((chapter, index) => ({ + "@type": "ListItem", + position: index + 1, + url: `/manga/${id}/${chapter.scanlatorId}/${chapter.number}`, + })), + }, + }); + return ( - + <> +