From b2f454880770369866052f93659b84eac41dd7c1 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Sun, 30 Nov 2025 23:00:40 -0500 Subject: [PATCH] Should be mostly working, doing some additional QOL --- fictionarchive-web-astro/package-lock.json | 242 +++++++++++++++--- fictionarchive-web-astro/package.json | 5 +- .../src/lib/components/HeroSection.svelte | 21 ++ .../src/lib/components/HomePage.svelte | 38 +++ .../src/lib/components/Navbar.svelte | 26 +- .../src/lib/components/NavigationCard.svelte | 80 ++++++ .../src/lib/components/NovelCard.svelte | 110 ++++++-- .../components/RecentlyUpdatedSection.svelte | 81 ++++++ .../components/ui/navigation-menu/index.ts | 28 ++ .../navigation-menu-content.svelte | 21 ++ .../navigation-menu-indicator.svelte | 22 ++ .../navigation-menu-item.svelte | 17 ++ .../navigation-menu-link.svelte | 20 ++ .../navigation-menu-list.svelte | 17 ++ .../navigation-menu-trigger.svelte | 34 +++ .../navigation-menu-viewport.svelte | 22 ++ .../ui/navigation-menu/navigation-menu.svelte | 32 +++ .../src/lib/components/ui/tooltip/index.ts | 18 ++ .../ui/tooltip/tooltip-content.svelte | 24 ++ .../src/lib/graphql/__generated__/graphql.ts | 4 +- .../src/lib/graphql/queries/novels.graphql | 11 + .../src/lib/utils/time.ts | 23 ++ .../src/pages/index.astro | 6 +- .../src/pages/novels/index.astro | 10 + 24 files changed, 839 insertions(+), 73 deletions(-) create mode 100644 fictionarchive-web-astro/src/lib/components/HeroSection.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/HomePage.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/NavigationCard.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/RecentlyUpdatedSection.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/index.ts create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-content.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-indicator.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-item.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-link.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-list.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-trigger.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-viewport.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu.svelte create mode 100644 fictionarchive-web-astro/src/lib/components/ui/tooltip/index.ts create mode 100644 fictionarchive-web-astro/src/lib/components/ui/tooltip/tooltip-content.svelte create mode 100644 fictionarchive-web-astro/src/lib/utils/time.ts create mode 100644 fictionarchive-web-astro/src/pages/novels/index.astro diff --git a/fictionarchive-web-astro/package-lock.json b/fictionarchive-web-astro/package-lock.json index 763c194..8e90ed0 100644 --- a/fictionarchive-web-astro/package-lock.json +++ b/fictionarchive-web-astro/package-lock.json @@ -16,6 +16,7 @@ "astro": "^5.16.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.1.0", "graphql": "^16.12.0", "oidc-client-ts": "^3.4.1", "svelte": "^5.45.2", @@ -28,7 +29,9 @@ "@graphql-codegen/typed-document-node": "^6.1.3", "@graphql-codegen/typescript": "^5.0.5", "@graphql-codegen/typescript-operations": "^5.0.5", - "@lucide/svelte": "^0.555.0", + "@internationalized/date": "^3.10.0", + "@lucide/svelte": "^0.544.0", + "bits-ui": "^2.14.4", "dotenv": "^16.6.1", "tailwind-variants": "^3.2.2", "tw-animate-css": "^1.4.0" @@ -939,6 +942,34 @@ "dev": true, "license": "MIT" }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@graphql-codegen/add": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@graphql-codegen/add/-/add-6.0.0.tgz", @@ -1025,21 +1056,21 @@ } }, "node_modules/@graphql-codegen/client-preset": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-5.2.0.tgz", - "integrity": "sha512-I8mcyNmuEoQGaUGiJHl9lAgyqCkMD/3TyUU3W2DS/aF4pwCpys378ZyYIE/Tw0Ods/tdPUvq/6p+JRkPlxtk1A==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-5.2.1.tgz", + "integrity": "sha512-6qFjHQQUWrEH+MVvWs5sPUgme8X+Ivg3WfzaCESooRBQZ4/EnSFlXkPWUTbOKYLRUoMv4g6iTRcZQf6u1wtHZA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", "@graphql-codegen/add": "^6.0.0", - "@graphql-codegen/gql-tag-operations": "5.1.0", + "@graphql-codegen/gql-tag-operations": "5.1.1", "@graphql-codegen/plugin-helpers": "^6.1.0", - "@graphql-codegen/typed-document-node": "^6.1.3", - "@graphql-codegen/typescript": "^5.0.5", - "@graphql-codegen/typescript-operations": "^5.0.5", - "@graphql-codegen/visitor-plugin-common": "^6.2.0", + "@graphql-codegen/typed-document-node": "^6.1.4", + "@graphql-codegen/typescript": "^5.0.6", + "@graphql-codegen/typescript-operations": "^5.0.6", + "@graphql-codegen/visitor-plugin-common": "^6.2.1", "@graphql-tools/documents": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-typed-document-node/core": "3.2.0", @@ -1092,14 +1123,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/gql-tag-operations": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-5.1.0.tgz", - "integrity": "sha512-acb0AKLSpNd5Wx3nl1pWR8+AckMTlzggOzQ7GUORznGkpK5mZBTNaOmIiUqT5bbu0fxADZfYpsiz+xmocFNedg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-5.1.1.tgz", + "integrity": "sha512-XewD0XxN2sgKieEIFeGWV5yT5X2aNy+eg+K8bHlUD7QfyrN2bi67rv/O5Edu7LVDOJR69uqVBp++18d742mn3Q==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.0", - "@graphql-codegen/visitor-plugin-common": "6.2.0", + "@graphql-codegen/visitor-plugin-common": "6.2.1", "@graphql-tools/utils": "^10.0.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" @@ -1172,14 +1203,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typed-document-node": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-6.1.3.tgz", - "integrity": "sha512-U1+16S3EWnR4T5b9219pu/47InfDB3UZ2E/CihJXgkeSklNteNBtw3D8m9R+ZanIq/GIsEin2hYpR++PO6neLQ==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-6.1.4.tgz", + "integrity": "sha512-ITWsA+qvT7R64z7KmYHXfgyD5ff069FAGq/hpR0EWVfzXT4RW1Xn/3Biw7/jvwMGsS1BTjo8ZLSIMNM8KjE3GA==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.0", - "@graphql-codegen/visitor-plugin-common": "6.2.0", + "@graphql-codegen/visitor-plugin-common": "6.2.1", "auto-bind": "~4.0.0", "change-case-all": "1.0.15", "tslib": "~2.6.0" @@ -1199,15 +1230,15 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typescript": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-5.0.5.tgz", - "integrity": "sha512-NwrUTjKALbeOrFyL/741DP/uRfcHKLD+kYL+e1de+X9b1wa1CfpMIdRIhGTuivuD5y6PYh3VePrE98Q5qz0+Ww==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-5.0.6.tgz", + "integrity": "sha512-rKW3wYInAnmO/DmKjhW3/KLMxUauUCZuMEPQmuoHChnwIuMjn5kVXCdArGyQqv+vVtFj55aS+sJLN4MPNNjSNg==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.0", "@graphql-codegen/schema-ast": "^5.0.0", - "@graphql-codegen/visitor-plugin-common": "6.2.0", + "@graphql-codegen/visitor-plugin-common": "6.2.1", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -1219,15 +1250,15 @@ } }, "node_modules/@graphql-codegen/typescript-operations": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-5.0.5.tgz", - "integrity": "sha512-4PpndN6teJ/mN/QxGYhaBwkpN+Q3/lOeM5sArZ5tiDDI4ItxjPRCEm/gOGv52nRHmB6xoQ5/9uqY52KWcf9AWA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-5.0.6.tgz", + "integrity": "sha512-pkR/82qWO50OHWeV3BiDuVxNFxiJerpmNjFep71VlabADXiU3GIeSaDd6G9a1/SCniVTXZQk2ivCb0ZJiuwo1A==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.1.0", - "@graphql-codegen/typescript": "^5.0.5", - "@graphql-codegen/visitor-plugin-common": "6.2.0", + "@graphql-codegen/typescript": "^5.0.6", + "@graphql-codegen/visitor-plugin-common": "6.2.1", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -1259,9 +1290,9 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/visitor-plugin-common": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.2.0.tgz", - "integrity": "sha512-8mx5uDDEwhP3G1jdeBdvVm4QhbEdkwXQa1hAXBWGofL87ePs5PUhz4IuQpwiS/CfFa4cqxcAWbe0k74x8iWfKw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.2.1.tgz", + "integrity": "sha512-5QT1hCV3286mrmoIC7vlFXsTlwELMexhuFIkjh+oVGGL1E8hxkIPAU0kfH/lsPbQHKi8zKmic2pl3tAdyYxNyg==", "dev": true, "license": "MIT", "dependencies": { @@ -2605,6 +2636,17 @@ } } }, + "node_modules/@internationalized/date": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.10.0.tgz", + "integrity": "sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -2651,9 +2693,9 @@ } }, "node_modules/@lucide/svelte": { - "version": "0.555.0", - "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-0.555.0.tgz", - "integrity": "sha512-aqTOMjBjf/HNwrhggRdb83T0QslZdpJTyTwr/chtXTGw7u4Hcu4zQb/5uA+csF0KKawKWVnsNI1MdHEHeEXTcQ==", + "version": "0.544.0", + "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-0.544.0.tgz", + "integrity": "sha512-9f9O6uxng2pLB01sxNySHduJN3HTl5p0HDu4H26VR51vhZfiMzyOMe9Mhof3XAk4l813eTtl+/DYRvGyoRR+yw==", "dev": true, "license": "ISC", "peerDependencies": { @@ -3093,9 +3135,9 @@ "license": "MIT" }, "node_modules/@sveltejs/acorn-typescript": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.7.tgz", - "integrity": "sha512-znp1A/Y1Jj4l/Zy7PX5DZKBE0ZNY+5QBngiE21NJkfSTyzzC5iKNWOtwFXKtIrn7MXEFBck4jD95iBNkGjK92Q==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.8.tgz", + "integrity": "sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==", "license": "MIT", "peerDependencies": { "acorn": "^8.9.0" @@ -3787,9 +3829,9 @@ "license": "MIT" }, "node_modules/astro": { - "version": "5.16.2", - "resolved": "https://registry.npmjs.org/astro/-/astro-5.16.2.tgz", - "integrity": "sha512-NFXqhB1UgBvleF5rLZ7a31Qzprf1lSch+k8o2XTvsw1d97gxGrjVVeWa8AnZUFtirz84YPW6+5NbLVNzS2y+uQ==", + "version": "5.16.3", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.16.3.tgz", + "integrity": "sha512-KzDk41F9Dspf5fM/Ls4XZhV4/csjJcWBrlenbnp5V3NGwU1zEaJz/HIyrdKdf5yw+FgwCeD2+Yos1Xkx9gnI0A==", "license": "MIT", "peer": true, "dependencies": { @@ -3987,6 +4029,31 @@ "baseline-browser-mapping": "dist/cli.js" } }, + "node_modules/bits-ui": { + "version": "2.14.4", + "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.14.4.tgz", + "integrity": "sha512-W6kenhnbd/YVvur+DKkaVJ6GldE53eLewur5AhUCqslYQ0vjZr8eWlOfwZnMiPB+PF5HMVqf61vXBvmyrAmPWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.1", + "@floating-ui/dom": "^1.7.1", + "esm-env": "^1.1.2", + "runed": "^0.35.1", + "svelte-toolbelt": "^0.10.6", + "tabbable": "^6.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/huntabyte" + }, + "peerDependencies": { + "@internationalized/date": "^3.8.1", + "svelte": "^5.33.0" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -4785,6 +4852,16 @@ "dev": true, "license": "MIT" }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debounce": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.2.0.tgz", @@ -6199,6 +6276,13 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "dev": true, + "license": "MIT" + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -6991,6 +7075,16 @@ "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -8935,6 +9029,31 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/runed": { + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.35.1.tgz", + "integrity": "sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==", + "dev": true, + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "esm-env": "^1.0.0", + "lz-string": "^1.5.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.21.0", + "svelte": "^5.7.0" + }, + "peerDependenciesMeta": { + "@sveltejs/kit": { + "optional": true + } + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -9284,6 +9403,16 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9324,6 +9453,27 @@ "node": ">=18" } }, + "node_modules/svelte-toolbelt": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.10.6.tgz", + "integrity": "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/huntabyte" + ], + "dependencies": { + "clsx": "^2.1.1", + "runed": "^0.35.1", + "style-to-object": "^1.0.8" + }, + "engines": { + "node": ">=18", + "pnpm": ">=8.7.0" + }, + "peerDependencies": { + "svelte": "^5.30.2" + } + }, "node_modules/svelte2tsx": { "version": "0.7.45", "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.45.tgz", @@ -9407,6 +9557,13 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/tabbable": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.3.0.tgz", + "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==", + "dev": true, + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", @@ -10365,9 +10522,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "devOptional": true, "license": "ISC", "peer": true, @@ -10376,6 +10533,9 @@ }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { diff --git a/fictionarchive-web-astro/package.json b/fictionarchive-web-astro/package.json index 73e0bbe..d7ca864 100644 --- a/fictionarchive-web-astro/package.json +++ b/fictionarchive-web-astro/package.json @@ -18,6 +18,7 @@ "astro": "^5.16.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.1.0", "graphql": "^16.12.0", "oidc-client-ts": "^3.4.1", "svelte": "^5.45.2", @@ -30,7 +31,9 @@ "@graphql-codegen/typed-document-node": "^6.1.3", "@graphql-codegen/typescript": "^5.0.5", "@graphql-codegen/typescript-operations": "^5.0.5", - "@lucide/svelte": "^0.555.0", + "@internationalized/date": "^3.10.0", + "@lucide/svelte": "^0.544.0", + "bits-ui": "^2.14.4", "dotenv": "^16.6.1", "tailwind-variants": "^3.2.2", "tw-animate-css": "^1.4.0" diff --git a/fictionarchive-web-astro/src/lib/components/HeroSection.svelte b/fictionarchive-web-astro/src/lib/components/HeroSection.svelte new file mode 100644 index 0000000..c465591 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/HeroSection.svelte @@ -0,0 +1,21 @@ + + +
+

+ {greeting} +

+

+ Your personal fiction library +

+
diff --git a/fictionarchive-web-astro/src/lib/components/HomePage.svelte b/fictionarchive-web-astro/src/lib/components/HomePage.svelte new file mode 100644 index 0000000..3ddc7b1 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/HomePage.svelte @@ -0,0 +1,38 @@ + + +
+ + + + + +
diff --git a/fictionarchive-web-astro/src/lib/components/Navbar.svelte b/fictionarchive-web-astro/src/lib/components/Navbar.svelte index db7b066..94d1f24 100644 --- a/fictionarchive-web-astro/src/lib/components/Navbar.svelte +++ b/fictionarchive-web-astro/src/lib/components/Navbar.svelte @@ -1,7 +1,16 @@
@@ -10,12 +19,15 @@ FA FictionArchive - - - -
- -
+ + + + Novels + + + +
+
diff --git a/fictionarchive-web-astro/src/lib/components/NavigationCard.svelte b/fictionarchive-web-astro/src/lib/components/NavigationCard.svelte new file mode 100644 index 0000000..644c673 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/NavigationCard.svelte @@ -0,0 +1,80 @@ + + + + +{#if disabled} +
+
+ +
+
+ {title} + {description} +
+ + Coming soon + +
+{:else} + +
+ +
+
+ {title} + {description} +
+ + + +
+{/if} diff --git a/fictionarchive-web-astro/src/lib/components/NovelCard.svelte b/fictionarchive-web-astro/src/lib/components/NovelCard.svelte index e5512a5..dcc2a48 100644 --- a/fictionarchive-web-astro/src/lib/components/NovelCard.svelte +++ b/fictionarchive-web-astro/src/lib/components/NovelCard.svelte @@ -1,15 +1,39 @@ - - {#if coverSrc} -
- {title} + + +
+ {#if coverSrc} +
+ {title} +
+ {:else} +
+ {/if} + + {statusLabel} +
- {:else} -
- {/if} - - - {title} - - - -

- {description} -

-
-
+ + + {title} + + + +

+ {description} +

+ {#if chapterDisplay || relativeTime} +
+ {#if chapterDisplay} + {chapterDisplay} + {/if} + {#if chapterDisplay && relativeTime} + + {/if} + {#if relativeTime && absoluteTime} + + + + + + + {absoluteTime} + + + + {/if} +
+ {/if} +
+ +
diff --git a/fictionarchive-web-astro/src/lib/components/RecentlyUpdatedSection.svelte b/fictionarchive-web-astro/src/lib/components/RecentlyUpdatedSection.svelte new file mode 100644 index 0000000..11382a1 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/RecentlyUpdatedSection.svelte @@ -0,0 +1,81 @@ + + +
+
+
+ +

Recently Updated

+
+ + View all + +
+ + {#if fetching} +
+
+
+ {:else if error} +
+

Could not load novels: {error}

+
+ {:else if novels.length === 0} +
+

No novels found yet.

+
+ {:else} +
+ {#each novels as novel (novel.id)} + + + + {/each} +
+ {/if} +
diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/index.ts b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/index.ts new file mode 100644 index 0000000..bbc250f --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/index.ts @@ -0,0 +1,28 @@ +import Root from "./navigation-menu.svelte"; +import Content from "./navigation-menu-content.svelte"; +import Indicator from "./navigation-menu-indicator.svelte"; +import Item from "./navigation-menu-item.svelte"; +import Link from "./navigation-menu-link.svelte"; +import List from "./navigation-menu-list.svelte"; +import Trigger from "./navigation-menu-trigger.svelte"; +import Viewport from "./navigation-menu-viewport.svelte"; + +export { + Root, + Content, + Indicator, + Item, + Link, + List, + Trigger, + Viewport, + // + Root as NavigationMenuRoot, + Content as NavigationMenuContent, + Indicator as NavigationMenuIndicator, + Item as NavigationMenuItem, + Link as NavigationMenuLink, + List as NavigationMenuList, + Trigger as NavigationMenuTrigger, + Viewport as NavigationMenuViewport, +}; diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-content.svelte b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-content.svelte new file mode 100644 index 0000000..e246772 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-content.svelte @@ -0,0 +1,21 @@ + + + diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-indicator.svelte b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-indicator.svelte new file mode 100644 index 0000000..6190a3f --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-indicator.svelte @@ -0,0 +1,22 @@ + + + +
+
diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-item.svelte b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-item.svelte new file mode 100644 index 0000000..b00b4b4 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-item.svelte @@ -0,0 +1,17 @@ + + + diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-link.svelte b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-link.svelte new file mode 100644 index 0000000..867851e --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-link.svelte @@ -0,0 +1,20 @@ + + + diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-list.svelte b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-list.svelte new file mode 100644 index 0000000..c2c5880 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-list.svelte @@ -0,0 +1,17 @@ + + + diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-trigger.svelte b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-trigger.svelte new file mode 100644 index 0000000..68c5a8f --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-trigger.svelte @@ -0,0 +1,34 @@ + + + + + + {@render children?.()} + + diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-viewport.svelte b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-viewport.svelte new file mode 100644 index 0000000..99d1efc --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu-viewport.svelte @@ -0,0 +1,22 @@ + + +
+ +
diff --git a/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu.svelte b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu.svelte new file mode 100644 index 0000000..69c3d13 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/navigation-menu/navigation-menu.svelte @@ -0,0 +1,32 @@ + + + + {@render children?.()} + + {#if viewport} + + {/if} + diff --git a/fictionarchive-web-astro/src/lib/components/ui/tooltip/index.ts b/fictionarchive-web-astro/src/lib/components/ui/tooltip/index.ts new file mode 100644 index 0000000..3b1f184 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/tooltip/index.ts @@ -0,0 +1,18 @@ +import { Tooltip as TooltipPrimitive } from 'bits-ui'; +import Content from './tooltip-content.svelte'; + +const Root = TooltipPrimitive.Root; +const Trigger = TooltipPrimitive.Trigger; +const Provider = TooltipPrimitive.Provider; + +export { + Root, + Trigger, + Content, + Provider, + // + Root as Tooltip, + Trigger as TooltipTrigger, + Content as TooltipContent, + Provider as TooltipProvider +}; diff --git a/fictionarchive-web-astro/src/lib/components/ui/tooltip/tooltip-content.svelte b/fictionarchive-web-astro/src/lib/components/ui/tooltip/tooltip-content.svelte new file mode 100644 index 0000000..88598cf --- /dev/null +++ b/fictionarchive-web-astro/src/lib/components/ui/tooltip/tooltip-content.svelte @@ -0,0 +1,24 @@ + + + + + diff --git a/fictionarchive-web-astro/src/lib/graphql/__generated__/graphql.ts b/fictionarchive-web-astro/src/lib/graphql/__generated__/graphql.ts index 1ec658e..4eb8a76 100644 --- a/fictionarchive-web-astro/src/lib/graphql/__generated__/graphql.ts +++ b/fictionarchive-web-astro/src/lib/graphql/__generated__/graphql.ts @@ -779,7 +779,7 @@ export type NovelsQueryVariables = Exact<{ }>; -export type NovelsQuery = { novels: { edges: Array<{ cursor: string, node: { id: any, url: string, name: { texts: Array<{ language: Language, text: string }> }, description: { texts: Array<{ language: Language, text: string }> }, coverImage: { originalPath: string, newPath: string | null } | null } }> | null, pageInfo: { hasNextPage: boolean, endCursor: string | null } } | null }; +export type NovelsQuery = { novels: { edges: Array<{ cursor: string, node: { id: any, url: string, rawStatus: NovelStatus, lastUpdatedTime: any, name: { texts: Array<{ language: Language, text: string }> }, description: { texts: Array<{ language: Language, text: string }> }, coverImage: { originalPath: string, newPath: string | null } | null, chapters: Array<{ order: any, name: { texts: Array<{ language: Language, text: string }> } }> } }> | null, pageInfo: { hasNextPage: boolean, endCursor: string | null } } | null }; -export const NovelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Novels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"after"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"novels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"after"},"value":{"kind":"Variable","name":{"kind":"Name","value":"after"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"name"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"texts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"text"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"description"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"texts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"text"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"coverImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"originalPath"}},{"kind":"Field","name":{"kind":"Name","value":"newPath"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const NovelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Novels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"after"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"novels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"after"},"value":{"kind":"Variable","name":{"kind":"Name","value":"after"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"name"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"texts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"text"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"description"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"texts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"text"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"coverImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"originalPath"}},{"kind":"Field","name":{"kind":"Name","value":"newPath"}}]}},{"kind":"Field","name":{"kind":"Name","value":"rawStatus"}},{"kind":"Field","name":{"kind":"Name","value":"lastUpdatedTime"}},{"kind":"Field","name":{"kind":"Name","value":"chapters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"}},{"kind":"Field","name":{"kind":"Name","value":"name"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"texts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"text"}}]}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/fictionarchive-web-astro/src/lib/graphql/queries/novels.graphql b/fictionarchive-web-astro/src/lib/graphql/queries/novels.graphql index d7a2592..74c5b20 100644 --- a/fictionarchive-web-astro/src/lib/graphql/queries/novels.graphql +++ b/fictionarchive-web-astro/src/lib/graphql/queries/novels.graphql @@ -21,6 +21,17 @@ query Novels($first: Int, $after: String) { originalPath newPath } + rawStatus + lastUpdatedTime + chapters { + order + name { + texts { + language + text + } + } + } } } pageInfo { diff --git a/fictionarchive-web-astro/src/lib/utils/time.ts b/fictionarchive-web-astro/src/lib/utils/time.ts new file mode 100644 index 0000000..807a626 --- /dev/null +++ b/fictionarchive-web-astro/src/lib/utils/time.ts @@ -0,0 +1,23 @@ +import { formatDistanceToNow, format, differenceInDays } from 'date-fns'; + +/** + * Formats a date as relative time (e.g., "2 hours ago") if within 7 days, + * otherwise returns an absolute date (e.g., "Mar 15"). + */ +export function formatRelativeTime(date: Date | string): string { + const d = typeof date === 'string' ? new Date(date) : date; + const daysDiff = differenceInDays(new Date(), d); + + if (daysDiff <= 7) { + return formatDistanceToNow(d, { addSuffix: true }); + } + return format(d, 'MMM d'); +} + +/** + * Formats a date as an absolute timestamp (e.g., "Mar 15, 2024, 3:30 PM"). + */ +export function formatAbsoluteTime(date: Date | string): string { + const d = typeof date === 'string' ? new Date(date) : date; + return format(d, 'PPpp'); +} diff --git a/fictionarchive-web-astro/src/pages/index.astro b/fictionarchive-web-astro/src/pages/index.astro index 52bfa60..f2cf1fc 100644 --- a/fictionarchive-web-astro/src/pages/index.astro +++ b/fictionarchive-web-astro/src/pages/index.astro @@ -2,9 +2,9 @@ export const prerender = true; // Static page import AppLayout from '../layouts/AppLayout.astro'; -import NovelsPage from '../lib/components/NovelsPage.svelte'; +import HomePage from '../lib/components/HomePage.svelte'; --- - - + + diff --git a/fictionarchive-web-astro/src/pages/novels/index.astro b/fictionarchive-web-astro/src/pages/novels/index.astro new file mode 100644 index 0000000..83dd387 --- /dev/null +++ b/fictionarchive-web-astro/src/pages/novels/index.astro @@ -0,0 +1,10 @@ +--- +export const prerender = true; // Static page + +import AppLayout from '../../layouts/AppLayout.astro'; +import NovelsPage from '../../lib/components/NovelsPage.svelte'; +--- + + + +