From a0870cac8664cb5480dfb1c7f11459bc9e819d8f Mon Sep 17 00:00:00 2001 From: ACX <8075870+acx10@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:39:38 -0700 Subject: [PATCH 1/7] Remove Tailwind CSS and all remaining references (#2413) Co-authored-by: acx10 --- booklore-ui/package-lock.json | 744 ++++-------------- booklore-ui/package.json | 12 +- .../authentication-settings.component.html | 20 +- .../authentication-settings.component.scss | 8 + .../additional-file-uploader.component.html | 46 +- .../additional-file-uploader.component.scss | 124 ++- .../book-card/book-card.component.html | 4 +- .../book-card/book-card.component.scss | 2 + .../book-table/book-table.component.html | 24 +- .../book-table/book-table.component.scss | 72 ++ .../cover-scale-preference.service.spec.ts | 2 +- .../book-browser/filter-label.helper.spec.ts | 106 --- ...lock-unlock-metadata-dialog.component.html | 6 +- ...lock-unlock-metadata-dialog.component.scss | 25 + .../book-notes/book-notes-component.html | 50 +- .../book-notes/book-notes-component.scss | 72 +- .../book-reviews/book-reviews.component.html | 48 +- .../book-reviews/book-reviews.component.scss | 131 ++- .../book-sender/book-sender.component.html | 14 +- .../book-sender/book-sender.component.scss | 22 + .../series-page/series-page.component.html | 75 +- .../series-page/series-page.component.scss | 251 +++++- ...okdrop-file-metadata-picker.component.html | 96 +-- ...okdrop-file-metadata-picker.component.scss | 117 ++- .../bookdrop-file-review.component.html | 8 +- .../bookdrop-file-review.component.scss | 12 + .../bookdrop-files-widget.component.html | 14 +- .../bookdrop-files-widget.component.scss | 35 + .../dashboard-settings.component.scss | 2 - .../main-dashboard.component.html | 6 +- .../main-dashboard.component.scss | 19 + .../library-creator.component.html | 4 +- .../library-creator.component.scss | 4 + .../book-metadata-center.component.html | 4 +- .../book-metadata-center.component.scss | 10 + .../metadata-viewer.component.html | 4 +- .../metadata-viewer.component.scss | 5 + .../bulk-metadata-update-component.html | 168 ++-- .../bulk-metadata-update-component.scss | 202 +++++ .../metadata-manager.component.html | 4 +- .../metadata-manager.component.scss | 4 + ...data-advanced-fetch-options.component.html | 94 +-- ...data-advanced-fetch-options.component.scss | 133 ++++ .../multi-book-metadata-fetch-component.html | 6 +- .../multi-book-metadata-fetch-component.scss | 26 + .../pdf-reader/pdf-reader.component.html | 2 +- .../pdf-reader/pdf-reader.component.scss | 7 + .../pdf-reader/pdf-reader.component.ts | 1 + .../device-settings-component.html | 8 +- .../device-settings-component.scss | 22 +- .../email-v2-provider.component.html | 24 +- .../email-v2-provider.component.scss | 19 + .../email-v2-recipient.component.html | 6 +- .../email-v2-recipient.component.scss | 13 + .../settings/email-v2/email-v2.component.html | 6 +- .../settings/email-v2/email-v2.component.scss | 21 +- .../file-naming-pattern.component.html | 6 +- .../file-naming-pattern.component.scss | 5 + .../metadata-settings-component.html | 12 +- .../metadata-settings-component.scss | 14 + .../settings/opds-settings/opds-settings.html | 10 +- .../settings/opds-settings/opds-settings.scss | 18 + .../features/settings/settings.component.html | 2 +- .../features/settings/settings.component.scss | 5 + .../user-profile-dialog.component.html | 2 +- .../user-profile-dialog.component.scss | 5 + .../view-preferences-parent.component.html | 8 +- .../view-preferences-parent.component.scss | 14 + .../library-stats.component.html | 2 +- .../library-stats.component.scss | 7 + .../book-uploader.component.html | 4 +- .../book-uploader.component.scss | 6 +- .../directory-picker.component.html | 2 +- .../directory-picker.component.scss | 10 + .../file-mover/file-mover-component.html | 80 +- .../file-mover/file-mover-component.scss | 245 ++++++ .../live-notification-box.component.html | 10 +- .../live-notification-box.component.scss | 30 + .../metadata-progress-widget-component.html | 26 +- .../metadata-progress-widget-component.scss | 46 +- ...nified-notification-popover-component.html | 2 +- ...nified-notification-popover-component.scss | 5 + .../layout-menu/app.menu.component.html | 12 +- .../layout-menu/app.menu.component.scss | 40 + .../layout-menu/app.menu.component.ts | 1 + .../version-changelog-dialog.component.html | 2 +- .../version-changelog-dialog.component.scss | 79 +- .../layout-topbar/app.topbar.component.html | 102 +-- .../layout-topbar/app.topbar.component.scss | 135 ++++ .../service/app-settings.service.spec.ts | 2 +- .../app/shared/service/auth.service.spec.ts | 9 +- .../src/app/shared/service/auth.service.ts | 4 +- .../service/custom-font.service.spec.ts | 30 +- .../service/file-download.service.spec.ts | 34 +- .../shared/service/page-title.service.spec.ts | 2 +- .../reading-session-api.service.spec.ts | 8 +- .../shared/service/version.service.spec.ts | 9 +- .../assets/layout/styles/layout/_topbar.scss | 33 + booklore-ui/src/assets/styles/reset.scss | 83 ++ booklore-ui/src/styles.scss | 5 +- booklore-ui/src/test-setup.ts | 14 + booklore-ui/tailwind.config.js | 14 - booklore-ui/tsconfig.spec.json | 6 +- booklore-ui/vitest.config.ts | 21 + 104 files changed, 2852 insertions(+), 1333 deletions(-) delete mode 100644 booklore-ui/src/app/features/book/components/book-browser/filter-label.helper.spec.ts create mode 100644 booklore-ui/src/app/features/readers/pdf-reader/pdf-reader.component.scss create mode 100644 booklore-ui/src/app/shared/layout/component/layout-menu/app.menu.component.scss create mode 100644 booklore-ui/src/assets/styles/reset.scss create mode 100644 booklore-ui/src/test-setup.ts delete mode 100644 booklore-ui/tailwind.config.js create mode 100644 booklore-ui/vitest.config.ts diff --git a/booklore-ui/package-lock.json b/booklore-ui/package-lock.json index 17db3243b..1ef51192b 100644 --- a/booklore-ui/package-lock.json +++ b/booklore-ui/package-lock.json @@ -39,26 +39,24 @@ "quill": "^2.0.3", "rxjs": "^7.8.2", "showdown": "^2.1.0", - "tailwindcss-primeui": "^0.6.1", "tslib": "^2.8.1", + "uuid": "^11.1.0", "ws": "^8.19.0", "zone.js": "^0.16.0" }, "devDependencies": { + "@analogjs/vite-plugin-angular": "^2.2.2", + "@analogjs/vitest-angular": "^2.2.2", "@angular/build": "^21.1.0", "@angular/cli": "^21.1.0", "@angular/compiler-cli": "^21.1.0", - "@tailwindcss/typography": "^0.5.19", - "@types/jasmine": "^5.1.15", "@types/node": "^25.0.9", "@types/showdown": "^2.0.6", + "@types/uuid": "^10.0.0", "@vitest/coverage-v8": "^4.0.17", "angular-eslint": "^21.1.0", - "autoprefixer": "^10.4.23", "eslint": "^9.39.2", - "jasmine-core": "^5.13.0", "jsdom": "^27.4.0", - "tailwindcss": "^3.4.19", "typescript": "~5.9.3", "typescript-eslint": "^8.53.0", "vitest": "^4.0.17" @@ -280,18 +278,6 @@ "node": ">= 14.0.0" } }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -306,6 +292,48 @@ "node": ">=6.0.0" } }, + "node_modules/@analogjs/vite-plugin-angular": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@analogjs/vite-plugin-angular/-/vite-plugin-angular-2.2.2.tgz", + "integrity": "sha512-lZ+v/RXQw2stVWdN02h0d5ruynz67rA4VLu2g5Wn8hh4YF/4MhfREKi8ILeSSyRtg3XlhvfYpau2vCyaSDhpww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-morph": "^21.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/brandonroberts" + }, + "peerDependencies": { + "@angular-devkit/build-angular": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0", + "@angular/build": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0" + }, + "peerDependenciesMeta": { + "@angular-devkit/build-angular": { + "optional": true + }, + "@angular/build": { + "optional": true + } + } + }, + "node_modules/@analogjs/vitest-angular": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@analogjs/vitest-angular/-/vitest-angular-2.2.2.tgz", + "integrity": "sha512-vIN0UCVY3wG/EvVh9tCYT40LsnrYhiEAhIwkz+Rdp9Yj2SMRQHBTaZLeNMTUwoLjcb5kOH2uCQFWkEC34HZWjw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/brandonroberts" + }, + "peerDependencies": { + "@analogjs/vite-plugin-angular": "*", + "@angular-devkit/architect": ">=0.1500.0 < 0.2200.0", + "vitest": "^1.3.1 || ^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, "node_modules/@angular-devkit/architect": { "version": "0.2101.0", "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2101.0.tgz", @@ -2507,6 +2535,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -2528,6 +2557,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2537,12 +2567,14 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -3138,6 +3170,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -3151,6 +3184,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -3160,6 +3194,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -4483,17 +4518,17 @@ "integrity": "sha512-DLd/WeicnHS5SsWWSk3x6/pcivqchNaEvg9UEGVqAcfYEBVmS9D6980ckXjTtfpXLjdLDsd96M7IuX4w7nzq5g==", "license": "Apache-2.0" }, - "node_modules/@tailwindcss/typography": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz", - "integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==", + "node_modules/@ts-morph/common": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.22.0.tgz", + "integrity": "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "6.0.10" - }, - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + "fast-glob": "^3.3.2", + "minimatch": "^9.0.3", + "mkdirp": "^3.0.1", + "path-browserify": "^1.0.1" } }, "node_modules/@tufjs/canonical-json": { @@ -4578,13 +4613,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/jasmine": { - "version": "5.1.15", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.15.tgz", - "integrity": "sha512-ZAC8KjmV2MJxbNTrwXFN+HKeajpXQZp6KpPiR6Aa4XvaEnjP6qh23lL/Rqb7AYzlp3h/rcwDrQ7Gg7q28cQTQg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -4609,6 +4637,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.53.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz", @@ -5204,43 +5239,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "license": "MIT" - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -5287,43 +5285,6 @@ "dev": true, "license": "MIT" }, - "node_modules/autoprefixer": { - "version": "10.4.23", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", - "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001760", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -5381,18 +5342,6 @@ "require-from-string": "^2.0.2" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/body-parser": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", @@ -5439,6 +5388,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -5606,15 +5556,6 @@ "node": ">=6" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001760", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", @@ -5845,6 +5786,13 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/code-block-writer": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", + "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==", + "dev": true, + "license": "MIT" + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -6012,18 +5960,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/cssstyle": { "version": "5.3.6", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.6.tgz", @@ -6127,18 +6063,6 @@ "node": ">=8" } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "license": "Apache-2.0" - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "license": "MIT" - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -6822,6 +6746,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -6838,6 +6763,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -6878,9 +6804,10 @@ "license": "BSD-3-Clause" }, "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -6890,6 +6817,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -6920,6 +6848,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -6998,20 +6927,6 @@ "node": ">= 0.6" } }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, "node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", @@ -7039,6 +6954,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -7053,6 +6969,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7134,6 +7051,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -7209,6 +7127,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -7218,9 +7137,9 @@ } }, "node_modules/hono": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.4.tgz", - "integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==", + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.5.tgz", + "integrity": "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g==", "dev": true, "license": "MIT", "peer": true, @@ -7487,22 +7406,11 @@ "node": ">= 0.10" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -7518,6 +7426,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7543,6 +7452,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -7568,6 +7478,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -7663,13 +7574,6 @@ "node": ">=8" } }, - "node_modules/jasmine-core": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.13.0.tgz", - "integrity": "sha512-vsYjfh7lyqvZX5QgqKc4YH8phs7g96Z8bsdIFNEU3VqXhlHaq+vov/Fgn/sr6MiUczdZkyXRC3TX369Ll4Nzbw==", - "dev": true, - "license": "MIT" - }, "node_modules/jose": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", @@ -7854,24 +7758,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, "node_modules/listr2": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", @@ -8174,6 +8060,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -8183,6 +8070,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -8196,6 +8084,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -8413,6 +8302,22 @@ "node": ">= 18" } }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -8474,21 +8379,11 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, "funding": [ { "type": "github", @@ -8689,15 +8584,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/npm-bundled": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz", @@ -8817,20 +8703,12 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -9145,6 +9023,13 @@ "node": ">= 0.8" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9169,6 +9054,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, "license": "MIT" }, "node_modules/path-scurry": { @@ -9220,12 +9106,14 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9234,24 +9122,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/piscina": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.4.tgz", @@ -9279,6 +9149,7 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -9303,90 +9174,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", @@ -9394,64 +9181,6 @@ "dev": true, "license": "MIT" }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-nested/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "license": "MIT" - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -9548,6 +9277,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -9619,15 +9349,6 @@ "node": ">= 0.10" } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, "node_modules/readdirp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", @@ -9663,6 +9384,7 @@ "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -9720,6 +9442,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -9828,6 +9551,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -10232,6 +9956,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -10391,37 +10116,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10439,6 +10133,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10454,134 +10149,6 @@ "dev": true, "license": "MIT" }, - "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss-primeui": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/tailwindcss-primeui/-/tailwindcss-primeui-0.6.1.tgz", - "integrity": "sha512-T69Rylcrmnt8zy9ik+qZvsLuRIrS9/k6rYJSIgZ1trnbEzGDDQSCIdmfyZknevqiHwpSJHSmQ9XT2C+S/hJY4A==", - "license": "MIT", - "peerDependencies": { - "tailwindcss": ">=3.1.0" - } - }, - "node_modules/tailwindcss/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tailwindcss/node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/tailwindcss/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tailwindcss/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tailwindcss/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/tar": { "version": "7.5.6", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz", @@ -10609,27 +10176,6 @@ "node": ">=18" } }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -10651,6 +10197,7 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -10697,6 +10244,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -10764,11 +10312,16 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "license": "Apache-2.0" + "node_modules/ts-morph": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-21.0.1.tgz", + "integrity": "sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.22.0", + "code-block-writer": "^12.0.0" + } }, "node_modules/tslib": { "version": "2.8.1", @@ -10961,12 +10514,6 @@ "node": ">=6" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, "node_modules/uuid": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", @@ -10976,7 +10523,6 @@ "https://github.com/sponsors/ctavan" ], "license": "MIT", - "peer": true, "bin": { "uuid": "dist/esm/bin/uuid" } diff --git a/booklore-ui/package.json b/booklore-ui/package.json index 01504a7f9..7fe9db8dc 100644 --- a/booklore-ui/package.json +++ b/booklore-ui/package.json @@ -43,28 +43,26 @@ "quill": "^2.0.3", "rxjs": "^7.8.2", "showdown": "^2.1.0", - "tailwindcss-primeui": "^0.6.1", "tslib": "^2.8.1", + "uuid": "^11.1.0", "ws": "^8.19.0", "zone.js": "^0.16.0" }, "devDependencies": { + "@analogjs/vite-plugin-angular": "^2.2.2", + "@analogjs/vitest-angular": "^2.2.2", "@angular/build": "^21.1.0", "@angular/cli": "^21.1.0", "@angular/compiler-cli": "^21.1.0", - "@tailwindcss/typography": "^0.5.19", - "@types/jasmine": "^5.1.15", "@types/node": "^25.0.9", "@types/showdown": "^2.0.6", + "@types/uuid": "^10.0.0", "@vitest/coverage-v8": "^4.0.17", "angular-eslint": "^21.1.0", - "autoprefixer": "^10.4.23", "eslint": "^9.39.2", - "jasmine-core": "^5.13.0", "jsdom": "^27.4.0", - "tailwindcss": "^3.4.19", "typescript": "~5.9.3", "typescript-eslint": "^8.53.0", "vitest": "^4.0.17" } -} \ No newline at end of file +} diff --git a/booklore-ui/src/app/core/security/oauth2-management/authentication-settings.component.html b/booklore-ui/src/app/core/security/oauth2-management/authentication-settings.component.html index 8edbf3fe6..73e5a0a82 100644 --- a/booklore-ui/src/app/core/security/oauth2-management/authentication-settings.component.html +++ b/booklore-ui/src/app/core/security/oauth2-management/authentication-settings.component.html @@ -76,7 +76,7 @@ id="providerName" [(ngModel)]="oidcProvider.providerName" placeholder="e.g. Authentik" - class="w-full"/> + class="full-width"/>
@@ -85,19 +85,19 @@ id="clientId" [(ngModel)]="oidcProvider.clientId" placeholder="e.g. my-client-id" - class="w-full"/> + class="full-width"/>
- + Required scopes for OIDC login and token exchange. Must be supported and advertised in the provider's discovery metadata. @@ -110,7 +110,7 @@ id="issuerUri" [(ngModel)]="oidcProvider.issuerUri" placeholder="e.g. https://authentik.domain.com/application/o/booklore/ or https://pocket-id.domain.com" - class="w-full"/> + class="full-width"/>
@@ -121,7 +121,7 @@ id="claimUsername" [(ngModel)]="oidcProvider.claimMapping.username" placeholder="e.g. preferred_username" - class="w-full"/> + class="full-width"/>
@@ -130,7 +130,7 @@ id="claimEmail" [(ngModel)]="oidcProvider.claimMapping.email" placeholder="e.g. email" - class="w-full"/> + class="full-width"/>
@@ -139,11 +139,11 @@ id="claimName" [(ngModel)]="oidcProvider.claimMapping.name" placeholder="e.g. name or given_name" - class="w-full"/> + class="full-width"/>
- + These claims are used by Booklore to provision new OIDC users with their name, username, and email. Ensure they match the claims provided by your OIDC provider. @@ -178,7 +178,7 @@
- + Enabling auto-provisioning ensures that new users are automatically created with the selected default permissions. If turned off, users must be manually created in Booklore before they can log in. diff --git a/booklore-ui/src/app/core/security/oauth2-management/authentication-settings.component.scss b/booklore-ui/src/app/core/security/oauth2-management/authentication-settings.component.scss index be010d5e1..c796a33e5 100644 --- a/booklore-ui/src/app/core/security/oauth2-management/authentication-settings.component.scss +++ b/booklore-ui/src/app/core/security/oauth2-management/authentication-settings.component.scss @@ -250,3 +250,11 @@ padding-left: 1rem; margin-bottom: 1rem; } + +.full-width { + width: 100%; +} + +.info-icon { + color: #3b82f6; +} diff --git a/booklore-ui/src/app/features/book/components/additional-file-uploader/additional-file-uploader.component.html b/booklore-ui/src/app/features/book/components/additional-file-uploader/additional-file-uploader.component.html index 01c857b41..7ce8de011 100644 --- a/booklore-ui/src/app/features/book/components/additional-file-uploader/additional-file-uploader.component.html +++ b/booklore-ui/src/app/features/book/components/additional-file-uploader/additional-file-uploader.component.html @@ -25,24 +25,24 @@ optionLabel="label" optionValue="value" placeholder="Select file type" - class="w-full" + styleClass="full-width" [disabled]="isUploading" > -
- +
+
- -
-
+
+
-
+
@if (files?.length > 0) {
-
-
+
+
@for (uploadFile of this.files; track uploadFile; let i = $index) { -
-
- - +
+
+ + {{ uploadFile.file.name }} -
{{ formatSize(uploadFile.file.size) }}
+
{{ formatSize(uploadFile.file.size) }}
@switch (uploadFile.status) { @case ('Pending') { @@ -97,7 +97,7 @@ } @case ('Uploading') { @@ -105,7 +105,7 @@ } @case ('Uploaded') { @@ -113,7 +113,7 @@ } @case ('Failed') { @@ -130,14 +130,14 @@ -
- -

Drag and drop a file here to upload.

-

+

+ +

Drag and drop a file here to upload.

+

Upload an additional file for {{ book.metadata?.title || 'this book' }}.

-
\ No newline at end of file +
diff --git a/booklore-ui/src/app/features/book/components/additional-file-uploader/additional-file-uploader.component.scss b/booklore-ui/src/app/features/book/components/additional-file-uploader/additional-file-uploader.component.scss index 595271760..ba2612a61 100644 --- a/booklore-ui/src/app/features/book/components/additional-file-uploader/additional-file-uploader.component.scss +++ b/booklore-ui/src/app/features/book/components/additional-file-uploader/additional-file-uploader.component.scss @@ -26,6 +26,126 @@ gap: 1.5rem; } -:host ::ng-deep .p-fileupload-content p-progressbar { - display: none !important; +:host ::ng-deep { + .p-fileupload-content p-progressbar { + display: none !important; + } + + .full-width { + width: 100%; + } +} + +.file-upload { + width: 100%; +} + +.description-field { + width: 100%; +} + +.description-label { + display: block; + font-size: 0.875rem; + font-weight: 500; + margin-bottom: 0.5rem; +} + +.upload-header-actions { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + flex: 1; + gap: 1rem; +} + +.action-buttons { + display: flex; + gap: 1rem; +} + +.upload-content { + display: flex; + flex-direction: column; + gap: 2rem; + padding: 0 1rem; +} + +.file-list-scroll { + max-height: 24rem; + max-width: 22rem; + overflow-y: auto; + padding-right: 0.5rem; + + @media (min-width: 768px) { + max-width: none; + } +} + +.file-list { + display: flex; + flex-wrap: wrap; +} + +.file-row { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + gap: 1rem; +} + +.file-info { + display: flex; + align-items: center; + gap: 1rem; + overflow: hidden; + flex: 1; +} + +.file-badge { + flex-shrink: 0; +} + +.file-name { + font-weight: 600; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + flex: 1; +} + +.file-size { + flex-shrink: 0; +} + +.status-icon { + padding: 0.75rem; +} + +.empty-state { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + text-align: center; +} + +.empty-icon { + border: 2px solid; + border-radius: 9999px; + padding: 2rem; + font-size: 2.25rem; + color: var(--p-text-muted-color); +} + +.empty-text { + margin-top: 1.5rem; + margin-bottom: 0.5rem; +} + +.empty-subtext { + margin-top: 0.5rem; + margin-bottom: 0.5rem; } diff --git a/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.html b/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.html index 171fdd038..6868f66f3 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.html +++ b/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.html @@ -81,7 +81,7 @@
@if (!bottomBarHidden) { -
+
@if (_shouldShowStatusIcon) {
} -

{{ displayTitle }} diff --git a/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.scss b/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.scss index 18cabdb5a..595e06039 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.scss +++ b/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.scss @@ -65,6 +65,8 @@ overflow: hidden; text-overflow: ellipsis; text-align: center; + margin: 0; + padding-left: 0.5rem; } .info-btn, diff --git a/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.html b/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.html index c535b12cc..8ca07a1e4 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.html +++ b/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.html @@ -24,7 +24,7 @@ - + @for (col of visibleColumns; track col.field) { {{ col.header }} } @@ -37,7 +37,7 @@ - + -
+
Book Cover - {{ metadata.title }} + {{ metadata.title }}
@for (col of visibleColumns; track col.field) { @if (col.field === 'readStatus') { - + @if (shouldShowStatusIcon(book.readStatus)) {
} @else if (col.field === 'amazonRating' || col.field === 'goodreadsRating' || col.field === 'hardcoverRating' || col.field == 'ranobedbRating') { - - + + + class="cell-text"> @if(['title', 'authors', 'publisher', 'seriesName', 'categories', 'language'].includes(col.field)) { @for (item of getCellClickableValue(metadata, book, col.field); track $index; let isLast = $last) { - + {{ item.anchor }}@if (!isLast) {, } } } @else { diff --git a/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.scss b/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.scss index f56f0a363..a774bfe57 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.scss +++ b/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.scss @@ -36,3 +36,75 @@ .status-wont-read { color: #ec4899; } + +.cover-header-cell { + max-width: 3.5rem; + min-width: 3.5rem; +} + +.cell-center { + text-align: center; +} + +.cover-thumbnail { + width: 1.75rem; + height: 1.75rem; +} + +.tooltip-cover-container { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; +} + +.tooltip-cover-image { + width: 40rem; + height: auto; +} + +.tooltip-cover-title { + font-size: 0.875rem; + text-wrap: balance; + text-align: center; +} + +.cell-status { + text-align: center; + min-width: 4rem; + max-width: 4rem; +} + +.cell-rating { + min-width: 10rem; + max-width: 10rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.rating-wrapper { + display: flex; + align-items: center; + gap: 0.25rem; +} + +.cell-text { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: right; + min-width: 6rem; + max-width: 12rem; +} + +.cell-link { + &:hover { + text-decoration: underline; + color: #60a5fa; + } +} + +::ng-deep .cover-tooltip > .p-tooltip-text { + padding: 0.25rem; +} diff --git a/booklore-ui/src/app/features/book/components/book-browser/cover-scale-preference.service.spec.ts b/booklore-ui/src/app/features/book/components/book-browser/cover-scale-preference.service.spec.ts index dcf2816ef..1582f91c5 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/cover-scale-preference.service.spec.ts +++ b/booklore-ui/src/app/features/book/components/book-browser/cover-scale-preference.service.spec.ts @@ -1,4 +1,4 @@ -import {beforeEach, describe, expect, it, vi} from 'vitest'; +import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest'; import {TestBed} from '@angular/core/testing'; import {EnvironmentInjector, runInInjectionContext} from '@angular/core'; import {CoverScalePreferenceService} from './cover-scale-preference.service'; diff --git a/booklore-ui/src/app/features/book/components/book-browser/filter-label.helper.spec.ts b/booklore-ui/src/app/features/book/components/book-browser/filter-label.helper.spec.ts deleted file mode 100644 index 10dde7a16..000000000 --- a/booklore-ui/src/app/features/book/components/book-browser/filter-label.helper.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import {describe, expect, it, vi} from 'vitest'; -import {FilterLabelHelper} from './filter-label.helper'; - -vi.mock('./book-filter/book-filter.component', () => ({ - fileSizeRanges: [ - {id: 'small', label: 'Small Files'}, - {id: 'large', label: 'Large Files'} - ], - pageCountRanges: [ - {id: 'short', label: 'Short Books'}, - {id: 'long', label: 'Long Books'} - ], - matchScoreRanges: [ - {id: 'high', label: 'High Match'}, - {id: 'low', label: 'Low Match'} - ], - ratingOptions10: [ - {id: '5', label: 'Five Stars'}, - {id: '10', label: 'Ten Stars'} - ], - ratingRanges: [ - {id: 'A', label: 'A Range'}, - {id: 'B', label: 'B Range'} - ] -})); - -describe('FilterLabelHelper', () => { - describe('getFilterTypeName', () => { - it('should return mapped label for known filter type', () => { - expect(FilterLabelHelper.getFilterTypeName('author')).toBe('Author'); - expect(FilterLabelHelper.getFilterTypeName('category')).toBe('Genre'); - expect(FilterLabelHelper.getFilterTypeName('series')).toBe('Series'); - }); - - it('should capitalize and return unknown filter type', () => { - expect(FilterLabelHelper.getFilterTypeName('unknownType')).toBe('UnknownType'); - expect(FilterLabelHelper.getFilterTypeName('custom')).toBe('Custom'); - }); - }); - - describe('getFilterDisplayValue', () => { - it('should return file size label for known id', () => { - expect(FilterLabelHelper.getFilterDisplayValue('fileSize', 'small')).toBe('small'); - expect(FilterLabelHelper.getFilterDisplayValue('filesize', 'large')).toBe('large'); - }); - - it('should return value if file size id not found', () => { - expect(FilterLabelHelper.getFilterDisplayValue('fileSize', 'unknown')).toBe('unknown'); - }); - - it('should return page count label for known id', () => { - expect(FilterLabelHelper.getFilterDisplayValue('pageCount', 'short')).toBe('short'); - expect(FilterLabelHelper.getFilterDisplayValue('pagecount', 'long')).toBe('long'); - }); - - it('should return value if page count id not found', () => { - expect(FilterLabelHelper.getFilterDisplayValue('pageCount', 'unknown')).toBe('unknown'); - }); - - it('should return match score label for known id', () => { - expect(FilterLabelHelper.getFilterDisplayValue('matchScore', 'high')).toBe('high'); - expect(FilterLabelHelper.getFilterDisplayValue('matchscore', 'low')).toBe('low'); - }); - - it('should return value if match score id not found', () => { - expect(FilterLabelHelper.getFilterDisplayValue('matchScore', 'unknown')).toBe('unknown'); - }); - - it('should return personal rating label for known id', () => { - expect(FilterLabelHelper.getFilterDisplayValue('personalRating', '5')).toBe('5'); - expect(FilterLabelHelper.getFilterDisplayValue('personalrating', '10')).toBe('10'); - }); - - it('should return value if personal rating id not found', () => { - expect(FilterLabelHelper.getFilterDisplayValue('personalRating', 'unknown')).toBe('unknown'); - }); - - it('should return rating range label for amazon/goodreads/hardcover', () => { - expect(FilterLabelHelper.getFilterDisplayValue('amazonRating', 'A')).toBe('A'); - expect(FilterLabelHelper.getFilterDisplayValue('goodreadsRating', 'B')).toBe('B'); - expect(FilterLabelHelper.getFilterDisplayValue('hardcoverRating', 'A')).toBe('A'); - }); - - it('should return value if rating range id not found', () => { - expect(FilterLabelHelper.getFilterDisplayValue('amazonRating', 'unknown')).toBe('unknown'); - expect(FilterLabelHelper.getFilterDisplayValue('goodreadsRating', 'unknown')).toBe('unknown'); - expect(FilterLabelHelper.getFilterDisplayValue('hardcoverRating', 'unknown')).toBe('unknown'); - }); - - it('should return value for unknown filter type', () => { - expect(FilterLabelHelper.getFilterDisplayValue('unknownType', 'someValue')).toBe('someValue'); - }); - }); - - describe('capitalize', () => { - it('should capitalize the first letter', () => { - // @ts-expect-private - // @ts-ignore - expect(FilterLabelHelper.capitalize('test')).toBe('Test'); - // @ts-ignore - expect(FilterLabelHelper.capitalize('T')).toBe('T'); - // @ts-ignore - expect(FilterLabelHelper.capitalize('')).toBe(''); - }); - }); -}); diff --git a/booklore-ui/src/app/features/book/components/book-browser/lock-unlock-metadata-dialog/lock-unlock-metadata-dialog.component.html b/booklore-ui/src/app/features/book/components/book-browser/lock-unlock-metadata-dialog/lock-unlock-metadata-dialog.component.html index 042dc0b66..d629d83e3 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/lock-unlock-metadata-dialog/lock-unlock-metadata-dialog.component.html +++ b/booklore-ui/src/app/features/book/components/book-browser/lock-unlock-metadata-dialog/lock-unlock-metadata-dialog.component.html @@ -18,10 +18,10 @@
-
+
@for (field of lockableFields; track field) { -
- +
+
@if (loading) { -
+
- Loading notes... + Loading notes...
} @else if (notes.length === 0) { -
+
-

No notes yet for this book

-

+

No notes yet for this book

+

Click "Add Note" to create your first note and start capturing your thoughts

@@ -29,14 +29,14 @@
@for (note of notes; track note.id + '-' + note.createdAt + '-' + $index) { -
+
-
-
-

{{ note.title }}

+
+
+

{{ note.title }}

- - + + @if (note.createdAt !== note.updatedAt) { Updated {{ formatDate(note.updatedAt) }} } @else { @@ -71,8 +71,8 @@
-
-
{{ note.content }}
+
+
{{ note.content }}
@@ -104,34 +104,34 @@ [closable]="true" [dismissableMask]="true"> -
+
- +
- +
-
+
-
+
- +
- +
-
+
@if (loading) { -
+
- Getting latest reviews... + Getting latest reviews...
} @else if (reviews?.length === 0) { -
+
@if (hasPermission && !reviewsLocked && reviewDownloadEnabled) { }
-

No reviews available for this book

+

No reviews available for this book

@if (!reviewDownloadEnabled) { -

+

Book review downloads are currently disabled. Enable this in Metadata Settings to fetch reviews.

} @else if (hasPermission && !reviewsLocked) { -

+

Click "Fetch Reviews" to download reviews from configured providers

} @@ -37,7 +37,7 @@
@for (review of reviews; track review.id || $index) { -
+
@if (review.spoiler && !isSpoilerRevealed(review.id!)) { -
-
-
- {{ review.reviewerName || 'Anonymous' }} +
+
+
+ {{ review.reviewerName || 'Anonymous' }} @if (review.metadataProvider) {
- + @if (review.date) { - {{ formatDate(review.date) }} + {{ formatDate(review.date) }} }
-
+
@if (review.rating) { -
+
- {{ review.rating }}/5 + {{ review.rating }}/5
} @if (hasPermission) { @if (reviewsLocked) { -
- +
@@ -110,7 +110,7 @@ @if (review.title && (!review.spoiler || isSpoilerRevealed(review.id!))) {
-

{{ review.title }}

@@ -121,19 +121,19 @@ @if (review.spoiler && !isSpoilerRevealed(review.id!)) {
@if (review.title) { -

{{ review.title }}

+

{{ review.title }}

} @if (review.body) { -
{{ review.body }}
+
{{ review.body }}
} @else { -
No review content available
+
No review content available
}
} @else { @if (review.body) { -
{{ review.body }}
+
{{ review.body }}
} @else { -
No review content available
+
No review content available
} }
diff --git a/booklore-ui/src/app/features/book/components/book-reviews/book-reviews.component.scss b/booklore-ui/src/app/features/book/components/book-reviews/book-reviews.component.scss index 87343f657..abbe013a7 100644 --- a/booklore-ui/src/app/features/book/components/book-reviews/book-reviews.component.scss +++ b/booklore-ui/src/app/features/book/components/book-reviews/book-reviews.component.scss @@ -54,21 +54,43 @@ } } +.loading-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2rem; + gap: 1rem; +} + +.loading-text { + color: #9ca3af; +} + .empty-state { position: relative; padding: 3rem !important; + text-align: center; + color: #9ca3af; .empty-state-title { font-size: 1.25rem; font-weight: 600; margin-top: 1rem; margin-bottom: 0.5rem; + color: #e5e7eb; } .empty-state-subtitle { max-width: 400px; - margin: 0 auto; + margin: 0.5rem auto 0; line-height: 1.6; + font-size: 0.875rem; + color: #9ca3af; + + &--warning { + color: #fbbf24; + } } .empty-state-decoration { @@ -177,6 +199,25 @@ border-bottom: 1px solid rgba(255, 255, 255, 0.1); position: relative; + .review-header-inner { + display: flex; + justify-content: space-between; + align-items: flex-start; + padding: 0.75rem; + } + + .reviewer-info-group { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .reviewer-name-row { + display: flex; + align-items: center; + gap: 0.5rem; + } + .reviewer-name { max-width: 120px; white-space: nowrap; @@ -186,6 +227,8 @@ -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; + font-weight: 500; + font-size: 0.875rem; } .review-meta { @@ -198,6 +241,46 @@ } } + .review-meta-icon { + font-size: 0.75rem; + margin-right: 0.25rem; + } + + .review-meta-text { + font-size: 0.875rem; + color: #9ca3af; + } + + .review-actions { + display: flex; + align-items: center; + gap: 0.5rem; + } + + .rating-wrapper { + display: flex; + align-items: center; + gap: 0.25rem; + } + + .rating-text { + font-size: 0.875rem; + font-weight: 500; + } + + .lock-icon-container { + display: flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + } + + .lock-icon { + color: #f59e0b; + font-size: 0.875rem; + } + .action-btn-hover { opacity: 0.7; transition: all 0.3s ease; @@ -248,6 +331,24 @@ } } +.review-title { + max-width: 450px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + cursor: help; + font-weight: 500; + font-size: 1.25rem; + color: #e5e7eb; + line-height: 1.25; + margin: 0; + + &--blurred { + filter: blur(4px); + margin-bottom: 0.5rem; + } +} + .review-body { flex: 1; min-height: 0; @@ -256,6 +357,11 @@ word-wrap: break-word; white-space: pre-wrap; box-sizing: border-box; + color: #d4d4d8; + + &--blurred { + filter: blur(4px); + } &::-webkit-scrollbar { width: 4px; @@ -276,10 +382,21 @@ } } -.review-title { - max-width: 450px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - cursor: help; +.review-empty-text { + color: #a1a1aa; + font-style: italic; + font-size: 0.875rem; + + &--blurred { + filter: blur(4px); + } +} + +@keyframes float { + 0%, 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-10px); + } } diff --git a/booklore-ui/src/app/features/book/components/book-sender/book-sender.component.html b/booklore-ui/src/app/features/book/components/book-sender/book-sender.component.html index a10be99d5..1b23afcff 100644 --- a/booklore-ui/src/app/features/book/components/book-sender/book-sender.component.html +++ b/booklore-ui/src/app/features/book/components/book-sender/book-sender.component.html @@ -18,21 +18,21 @@
-
-
- +
+
+ + styleClass="full-width">
-
- +
+ + styleClass="full-width">
diff --git a/booklore-ui/src/app/features/book/components/book-sender/book-sender.component.scss b/booklore-ui/src/app/features/book/components/book-sender/book-sender.component.scss index 93b0f51c7..4f04e3b7d 100644 --- a/booklore-ui/src/app/features/book/components/book-sender/book-sender.component.scss +++ b/booklore-ui/src/app/features/book/components/book-sender/book-sender.component.scss @@ -24,3 +24,25 @@ .dialog-footer { @include panel.dialog-footer; } + +.form-fields { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.form-field { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.field-label { + font-size: 0.875rem; + font-weight: 500; + color: #d1d5db; +} + +:host ::ng-deep .full-width { + width: 100%; +} diff --git a/booklore-ui/src/app/features/book/components/series-page/series-page.component.html b/booklore-ui/src/app/features/book/components/series-page/series-page.component.html index b2439c9c0..35177a01b 100644 --- a/booklore-ui/src/app/features/book/components/series-page/series-page.component.html +++ b/booklore-ui/src/app/features/book/components/series-page/series-page.component.html @@ -1,5 +1,5 @@ @if (filteredBooks$ | async; as books) { -
+
@@ -7,26 +7,25 @@ Series Details - + @if (books[0]; as firstBook) { -
-
+
+
- -
+
-
-
-

+
+
+

{{ seriesTitle$ | async }}

-

+

@for (author of firstBook.metadata?.authors; track $index; let isLast = $last) { - + {{ author }} @if (!isLast) { @@ -34,27 +33,25 @@ } }

-
@if (firstBook.metadata?.categories?.length) { -
-
+
+
@for (category of firstBook.metadata?.categories; track category) { - + }
} -
-
+