diff --git a/esbuild.config.mjs b/esbuild.config.mjs index fe0877a..71b44e3 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -2,6 +2,7 @@ import esbuild from "esbuild"; import process from "process"; import builtins from "builtin-modules"; import esbuildSvelte from "esbuild-svelte"; +import { sassPlugin } from "esbuild-sass-plugin"; import { sveltePreprocess } from "svelte-preprocess"; import dotenv from "dotenv"; import dotenvExpand from "dotenv-expand"; @@ -60,6 +61,7 @@ const context = await esbuild.context({ !warning.filename?.includes("node_modules"), }, }), + sassPlugin(), { name: "copy-plugin", setup(build) { diff --git a/package.json b/package.json index d5bc881..ff883d0 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "dependencies": { "chart.js": "^4.5.0", "chroma-js": "^3.1.2", + "esbuild-sass-plugin": "^3.3.1", "uuid": "^11.1.0", "yaml": "^2.8.0", "zod": "^3.25.67" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1333920..6e6d067 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: chroma-js: specifier: ^3.1.2 version: 3.1.2 + esbuild-sass-plugin: + specifier: ^3.3.1 + version: 3.3.1(esbuild@0.17.3)(sass-embedded@1.89.2) uuid: specifier: ^11.1.0 version: 11.1.0 @@ -112,6 +115,9 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@bufbuild/protobuf@2.6.0': + resolution: {integrity: sha512-6cuonJVNOIL7lTj5zgo/Rc2bKAo4/GvN+rKCrUj7GdEHRzCk8zKOfFwUsL9nAVk5rSIsRmlgcpLzTRysopEeeg==} + '@codemirror/state@6.5.2': resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} @@ -576,6 +582,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} + builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -632,6 +641,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -730,6 +742,12 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + esbuild-sass-plugin@3.3.1: + resolution: {integrity: sha512-SnO1ls+d52n6j8gRRpjexXI8MsHEaumS0IdDHaYM29Y6gakzZYMls6i9ql9+AWMSQk/eryndmUpXEgT34QrX1A==} + peerDependencies: + esbuild: '>=0.20.1' + sass-embedded: ^1.71.1 + esbuild-svelte@0.9.3: resolution: {integrity: sha512-CgEcGY1r/d16+aggec3czoFBEBaYIrFOnMxpsO6fWNaNEqHregPN5DLAPZDqrL7rXDNplW+WMu8s3GMq9FqgJA==} engines: {node: '>=18'} @@ -1339,6 +1357,9 @@ packages: peerDependencies: svelte: ^5.7.0 + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -1347,6 +1368,9 @@ packages: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} + safe-identifier@0.4.2: + resolution: {integrity: sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==} + safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -1355,6 +1379,107 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + sass-embedded-android-arm64@1.89.2: + resolution: {integrity: sha512-+pq7a7AUpItNyPu61sRlP6G2A8pSPpyazASb+8AK2pVlFayCSPAEgpwpCE9A2/Xj86xJZeMizzKUHxM2CBCUxA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + + sass-embedded-android-arm@1.89.2: + resolution: {integrity: sha512-oHAPTboBHRZlDBhyRB6dvDKh4KvFs+DZibDHXbkSI6dBZxMTT+Yb2ivocHnctVGucKTLQeT7+OM5DjWHyynL/A==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + + sass-embedded-android-riscv64@1.89.2: + resolution: {integrity: sha512-HfJJWp/S6XSYvlGAqNdakeEMPOdhBkj2s2lN6SHnON54rahKem+z9pUbCriUJfM65Z90lakdGuOfidY61R9TYg==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + + sass-embedded-android-x64@1.89.2: + resolution: {integrity: sha512-BGPzq53VH5z5HN8de6jfMqJjnRe1E6sfnCWFd4pK+CAiuM7iw5Fx6BQZu3ikfI1l2GY0y6pRXzsVLdp/j4EKEA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + + sass-embedded-darwin-arm64@1.89.2: + resolution: {integrity: sha512-UCm3RL/tzMpG7DsubARsvGUNXC5pgfQvP+RRFJo9XPIi6elopY5B6H4m9dRYDpHA+scjVthdiDwkPYr9+S/KGw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + + sass-embedded-darwin-x64@1.89.2: + resolution: {integrity: sha512-D9WxtDY5VYtMApXRuhQK9VkPHB8R79NIIR6xxVlN2MIdEid/TZWi1MHNweieETXhWGrKhRKglwnHxxyKdJYMnA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + + sass-embedded-linux-arm64@1.89.2: + resolution: {integrity: sha512-2N4WW5LLsbtrWUJ7iTpjvhajGIbmDR18ZzYRywHdMLpfdPApuHPMDF5CYzHbS+LLx2UAx7CFKBnj5LLjY6eFgQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-arm@1.89.2: + resolution: {integrity: sha512-leP0t5U4r95dc90o8TCWfxNXwMAsQhpWxTkdtySDpngoqtTy3miMd7EYNYd1znI0FN1CBaUvbdCMbnbPwygDlA==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-arm64@1.89.2: + resolution: {integrity: sha512-nTyuaBX6U1A/cG7WJh0pKD1gY8hbg1m2SnzsyoFG+exQ0lBX/lwTLHq3nyhF+0atv7YYhYKbmfz+sjPP8CZ9lw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-musl-arm@1.89.2: + resolution: {integrity: sha512-Z6gG2FiVEEdxYHRi2sS5VIYBmp17351bWtOCUZ/thBM66+e70yiN6Eyqjz80DjL8haRUegNQgy9ZJqsLAAmr9g==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-riscv64@1.89.2: + resolution: {integrity: sha512-N6oul+qALO0SwGY8JW7H/Vs0oZIMrRMBM4GqX3AjM/6y8JsJRxkAwnfd0fDyK+aICMFarDqQonQNIx99gdTZqw==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-musl-x64@1.89.2: + resolution: {integrity: sha512-K+FmWcdj/uyP8GiG9foxOCPfb5OAZG0uSVq80DKgVSC0U44AdGjvAvVZkrgFEcZ6cCqlNC2JfYmslB5iqdL7tg==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-linux-riscv64@1.89.2: + resolution: {integrity: sha512-g9nTbnD/3yhOaskeqeBQETbtfDQWRgsjHok6bn7DdAuwBsyrR3JlSFyqKc46pn9Xxd9SQQZU8AzM4IR+sY0A0w==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-x64@1.89.2: + resolution: {integrity: sha512-Ax7dKvzncyQzIl4r7012KCMBvJzOz4uwSNoyoM5IV6y5I1f5hEwI25+U4WfuTqdkv42taCMgpjZbh9ERr6JVMQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-win32-arm64@1.89.2: + resolution: {integrity: sha512-j96iJni50ZUsfD6tRxDQE2QSYQ2WrfHxeiyAXf41Kw0V4w5KYR/Sf6rCZQLMTUOHnD16qTMVpQi20LQSqf4WGg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + + sass-embedded-win32-x64@1.89.2: + resolution: {integrity: sha512-cS2j5ljdkQsb4PaORiClaVYynE9OAPZG/XjbOMxpQmjRIf7UroY4PEIH+Waf+y47PfXFX9SyxhYuw2NIKGbEng==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + + sass-embedded@1.89.2: + resolution: {integrity: sha512-Ack2K8rc57kCFcYlf3HXpZEJFNUX8xd8DILldksREmYXQkRHI879yy8q4mRDJgrojkySMZqmmmW1NxrFxMsYaA==} + engines: {node: '>=16.0.0'} + hasBin: true + sass@1.89.2: resolution: {integrity: sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==} engines: {node: '>=14.0.0'} @@ -1480,6 +1605,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -1539,6 +1668,14 @@ packages: resolution: {integrity: sha512-TF+8irl7rpj3+fpaLuPRX5BqReTAqckp0Fumxa/mCeK3fo0/MnBb9W/Z2bLwtqj3C3r5Lm6NKIAw7YrgIv1Fwg==} engines: {node: '>=18'} + sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + + sync-message-port@1.1.3: + resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} + engines: {node: '>=16.0.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1602,6 +1739,9 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -1659,6 +1799,8 @@ snapshots: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 + '@bufbuild/protobuf@2.6.0': {} + '@codemirror/state@6.5.2': dependencies: '@marijn/find-cluster-break': 1.0.2 @@ -2056,6 +2198,8 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer-builder@0.2.0: {} + builtin-modules@3.3.0: {} call-bind-apply-helpers@1.0.2: @@ -2112,6 +2256,8 @@ snapshots: color-name@1.1.4: {} + colorjs.io@0.5.2: {} + concat-map@0.0.1: {} crelt@1.0.6: {} @@ -2269,6 +2415,14 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + esbuild-sass-plugin@3.3.1(esbuild@0.17.3)(sass-embedded@1.89.2): + dependencies: + esbuild: 0.17.3 + resolve: 1.22.10 + safe-identifier: 0.4.2 + sass: 1.89.2 + sass-embedded: 1.89.2 + esbuild-svelte@0.9.3(esbuild@0.17.3)(svelte@5.34.8): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -2916,6 +3070,10 @@ snapshots: esm-env: 1.2.2 svelte: 5.34.8 + rxjs@7.8.2: + dependencies: + tslib: 2.4.0 + sade@1.8.1: dependencies: mri: 1.2.0 @@ -2928,6 +3086,8 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-identifier@0.4.2: {} + safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -2939,6 +3099,82 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + sass-embedded-android-arm64@1.89.2: + optional: true + + sass-embedded-android-arm@1.89.2: + optional: true + + sass-embedded-android-riscv64@1.89.2: + optional: true + + sass-embedded-android-x64@1.89.2: + optional: true + + sass-embedded-darwin-arm64@1.89.2: + optional: true + + sass-embedded-darwin-x64@1.89.2: + optional: true + + sass-embedded-linux-arm64@1.89.2: + optional: true + + sass-embedded-linux-arm@1.89.2: + optional: true + + sass-embedded-linux-musl-arm64@1.89.2: + optional: true + + sass-embedded-linux-musl-arm@1.89.2: + optional: true + + sass-embedded-linux-musl-riscv64@1.89.2: + optional: true + + sass-embedded-linux-musl-x64@1.89.2: + optional: true + + sass-embedded-linux-riscv64@1.89.2: + optional: true + + sass-embedded-linux-x64@1.89.2: + optional: true + + sass-embedded-win32-arm64@1.89.2: + optional: true + + sass-embedded-win32-x64@1.89.2: + optional: true + + sass-embedded@1.89.2: + dependencies: + '@bufbuild/protobuf': 2.6.0 + buffer-builder: 0.2.0 + colorjs.io: 0.5.2 + immutable: 5.1.3 + rxjs: 7.8.2 + supports-color: 8.1.1 + sync-child-process: 1.0.2 + varint: 6.0.0 + optionalDependencies: + sass-embedded-android-arm: 1.89.2 + sass-embedded-android-arm64: 1.89.2 + sass-embedded-android-riscv64: 1.89.2 + sass-embedded-android-x64: 1.89.2 + sass-embedded-darwin-arm64: 1.89.2 + sass-embedded-darwin-x64: 1.89.2 + sass-embedded-linux-arm: 1.89.2 + sass-embedded-linux-arm64: 1.89.2 + sass-embedded-linux-musl-arm: 1.89.2 + sass-embedded-linux-musl-arm64: 1.89.2 + sass-embedded-linux-musl-riscv64: 1.89.2 + sass-embedded-linux-musl-x64: 1.89.2 + sass-embedded-linux-riscv64: 1.89.2 + sass-embedded-linux-x64: 1.89.2 + sass-embedded-win32-arm64: 1.89.2 + sass-embedded-win32-x64: 1.89.2 + sass@1.89.2: dependencies: chokidar: 4.0.3 @@ -3084,6 +3320,10 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} svelte-check@4.2.2(picomatch@4.0.2)(svelte@5.34.8)(typescript@5.0.4): @@ -3128,6 +3368,12 @@ snapshots: magic-string: 0.30.17 zimmerframe: 1.1.2 + sync-child-process@1.0.2: + dependencies: + sync-message-port: 1.1.3 + + sync-message-port@1.1.3: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -3203,6 +3449,8 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + varint@6.0.0: {} + w3c-keyname@2.2.8: {} which-boxed-primitive@1.1.1: diff --git a/src/main.ts b/src/main.ts index b8bc086..8a79dbb 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,6 +22,7 @@ import { BackupReadingLogCommand } from "@commands/CreateReadingLogBackupCommand import { RestoreReadingLogBackupCommand } from "@commands/RestoreReadingLogBackupCommand"; import { Goodreads } from "@data-sources/Goodreads"; import { CreateBookFromGoodreadsUrlCommand } from "@commands/CreateBookFromGoodreadsUrlCommand"; +import { registerBookshelfCodeBlockProcessor } from "@ui/code-blocks/BookshelfCodeBlock"; export default class BookTrackerPlugin extends Plugin { public settings: BookTrackerPluginSettings; @@ -85,6 +86,7 @@ export default class BookTrackerPlugin extends Plugin { registerReadingLogCodeBlockProcessor(this); registerReadingStatsCodeBlockProcessor(this); + registerBookshelfCodeBlockProcessor(this); } onunload() {} diff --git a/src/ui/code-blocks/BookshelfCodeBlock.ts b/src/ui/code-blocks/BookshelfCodeBlock.ts new file mode 100644 index 0000000..0caa87d --- /dev/null +++ b/src/ui/code-blocks/BookshelfCodeBlock.ts @@ -0,0 +1,28 @@ +import { registerCodeBlockRenderer } from "."; +import { SvelteCodeBlockRenderer } from "./SvelteCodeBlockRenderer"; +import BookshelfCodeBlockView from "./BookshelfCodeBlockView.svelte"; +import type BookTrackerPlugin from "@src/main"; + +export function registerBookshelfCodeBlockProcessor( + plugin: BookTrackerPlugin +): void { + registerCodeBlockRenderer( + plugin, + "bookshelf", + (source, el) => new BookshelfCodeBlockRenderer(plugin, source, el) + ); +} + +export class BookshelfCodeBlockRenderer extends SvelteCodeBlockRenderer< + typeof BookshelfCodeBlockView +> { + constructor( + plugin: BookTrackerPlugin, + source: string, + contentEl: HTMLElement + ) { + super(contentEl, BookshelfCodeBlockView, { props: { plugin, source } }); + } + + onunload() {} +} diff --git a/src/ui/code-blocks/BookshelfCodeBlockView.svelte b/src/ui/code-blocks/BookshelfCodeBlockView.svelte new file mode 100644 index 0000000..3ea4490 --- /dev/null +++ b/src/ui/code-blocks/BookshelfCodeBlockView.svelte @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ui/components/bookshelf/Book.svelte b/src/ui/components/bookshelf/Book.svelte new file mode 100644 index 0000000..f0ff61d --- /dev/null +++ b/src/ui/components/bookshelf/Book.svelte @@ -0,0 +1,109 @@ + + +{#if orientation} + {#if orientation === "tilted"} + + + + {:else if orientation === "on-display"} + +
+ {#if title} + +

By: {author}

+ {/if} +
+ {/if} +{:else if design === "split-bands"} + + + +{:else if design === "dual-top-bands"} + + + +{:else if design === "colored-spine"} + + + +{:else} + + + +{/if} + + diff --git a/src/ui/components/bookshelf/BookStack.svelte b/src/ui/components/bookshelf/BookStack.svelte new file mode 100644 index 0000000..8d21913 --- /dev/null +++ b/src/ui/components/bookshelf/BookStack.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/ui/components/bookshelf/BookStackElement.svelte b/src/ui/components/bookshelf/BookStackElement.svelte new file mode 100644 index 0000000..aa2b23e --- /dev/null +++ b/src/ui/components/bookshelf/BookStackElement.svelte @@ -0,0 +1,49 @@ + + +
  • + {#if design === "split-bands"} + + + + {:else if design === "dual-top-bands"} + + + + {:else if design === "colored-spine"} + + + + {:else} + + + + {/if} +
  • diff --git a/src/ui/components/bookshelf/BookText.svelte b/src/ui/components/bookshelf/BookText.svelte new file mode 100644 index 0000000..86a7e0d --- /dev/null +++ b/src/ui/components/bookshelf/BookText.svelte @@ -0,0 +1,20 @@ + + +
    + {#if title} +

    {title}

    + {/if} + {#if subtitle} +

    {subtitle}

    + {/if} +
    diff --git a/src/ui/components/bookshelf/Bookshelf.svelte b/src/ui/components/bookshelf/Bookshelf.svelte new file mode 100644 index 0000000..7438adb --- /dev/null +++ b/src/ui/components/bookshelf/Bookshelf.svelte @@ -0,0 +1,32 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/bookshelf.scss b/src/ui/components/bookshelf/bookshelf.scss new file mode 100644 index 0000000..27ed3a1 --- /dev/null +++ b/src/ui/components/bookshelf/bookshelf.scss @@ -0,0 +1,216 @@ +$white: white; +$black: black; +$background: #dedede; + +$bookWidth: 40px; +$bookHeight: 200px; +$bookEdge: 2px; + +.bookshelf__wrapper { + width: 80%; + height: 100%; + margin: 0 auto; + overflow: hidden; + background-size: 10px 230px; + + .bookshelf__bookStack-wrapper { + width: 200px; + height: 100%; + display: inline-flex; + flex-flow: column nowrap; + list-style: none; + padding: 0; + + .bookshelf__bookStack-outOfStock { + background: #232323; + color: #fff; + height: 150px; + padding: 0; + margin: 50px 1px auto 1px; + display: flex; + flex-flow: column nowrap; + justify-content: space-around; + align-items: center; + font-size: 1.1em; + font-weight: 600; + line-height: 1.2; + letter-spacing: 1.25px; + border-radius: 6px; + } + + .bookshelf__bookstack-elem { + margin-inline-start: 0; + + .bookshelf__book-wrapper { + width: 100%; + height: 40px; + margin: 0; + padding: 0; + + .bookshelf__book-content { + height: $bookWidth; + width: $bookHeight; + + transform-origin: 0% 0%; + transform: rotate(0deg); + overflow: hidden; + + // * Centering content + display: flex; + flex-flow: column nowrap; + justify-content: center; + align-items: center; + + .bookshelf__book-title, + .bookshelf__book-subtitle { + font-size: 0.8em; + font-weight: 600; + + height: calc($bookWidth / 2); + width: $bookHeight; + + padding: 0; + margin: 0; + + // * Centering content + display: flex; + justify-content: center; + align-items: center; + text-align: center; + } + + .bookshelf__book-subtitle { + font-size: 0.6em; + letter-spacing: 1px; + font-weight: 400; + font-style: italic; + } + } + + .center-content { + display: flex; + justify-content: center; + align-items: center; + } + + // .bookshelf__book-title{ + // width: 140px; + // height: 40px; + // transform: rotate(0deg); + // margin-left: 29px; + // margin-top: 0; + // text-align: center; + // } + } + } + } + + .bookshelf__book-wrapper { + height: $bookHeight; + width: $bookWidth; + float: left; + margin: 20px 1px 10px 1px; + border-radius: 6px; + transition: transform 0.4s ease; + position: relative; + + .bookshelf__book-content { + width: $bookHeight; + + transform-origin: 0% 0%; + transform: rotate(90deg); + overflow: hidden; + + // * Centering content + display: flex; + flex-flow: column nowrap; + justify-content: center; + align-items: center; + + .bookshelf__book-title, + .bookshelf__book-subtitle { + font-size: 0.8em; + font-weight: 600; + + height: calc($bookWidth / 2); + width: $bookHeight; + + padding: 0; + margin: 0; + + // * Centering content + display: flex; + justify-content: center; + align-items: center; + text-align: center; + } + + .bookshelf__book-subtitle { + font-size: 0.6em; + letter-spacing: 1px; + font-weight: 400; + font-style: italic; + } + } + + &:hover { + transform: scale(1.05); + } + + .center-content { + display: flex; + justify-content: center; + align-items: center; + } + } + + .bookshelf__book-tilted { + float: left; + width: 72px; + + .bookshelf__book-wrapper { + --book-width: 40px !important; + width: 40px !important; + } + + &:hover .bookshelf__book-wrapper { + transform: translateY(-20px); + } + + & > .bookshelf__book-wrapper { + transform: translateY(-22px) translateX(13px) rotate(9deg); + } + } + + .bookshelf__book-onDisplay { + width: 150px; + height: 200px; + display: flex; + flex-flow: column wrap; + justify-content: space-between; + align-items: center; + text-align: center; + margin: 20px 2px 10px 2px; + position: relative; + + .bookshelf__book-content { + width: calc(100% - 11px); + margin-left: 11px; + transform: rotate(0deg); + overflow: visible; + + .bookshelf__book-title, + .bookshelf__book-subtitle { + line-height: 2; + margin-top: 16px; + width: 100%; + word-wrap: break-word; + } + } + + .bookshelf__book-author { + font-size: 0.8em; + margin-left: 13px; + } + } +} diff --git a/src/ui/components/bookshelf/designs/book/BookColoredSpine.svelte b/src/ui/components/bookshelf/designs/book/BookColoredSpine.svelte new file mode 100644 index 0000000..cf339e6 --- /dev/null +++ b/src/ui/components/bookshelf/designs/book/BookColoredSpine.svelte @@ -0,0 +1,49 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/book/BookDefault.svelte b/src/ui/components/bookshelf/designs/book/BookDefault.svelte new file mode 100644 index 0000000..cb329f0 --- /dev/null +++ b/src/ui/components/bookshelf/designs/book/BookDefault.svelte @@ -0,0 +1,36 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/book/BookDualTopBands.svelte b/src/ui/components/bookshelf/designs/book/BookDualTopBands.svelte new file mode 100644 index 0000000..5fef2ee --- /dev/null +++ b/src/ui/components/bookshelf/designs/book/BookDualTopBands.svelte @@ -0,0 +1,61 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/book/BookOnDisplay.svelte b/src/ui/components/bookshelf/designs/book/BookOnDisplay.svelte new file mode 100644 index 0000000..b0afa80 --- /dev/null +++ b/src/ui/components/bookshelf/designs/book/BookOnDisplay.svelte @@ -0,0 +1,23 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/book/BookSplitBands.svelte b/src/ui/components/bookshelf/designs/book/BookSplitBands.svelte new file mode 100644 index 0000000..5fef2ee --- /dev/null +++ b/src/ui/components/bookshelf/designs/book/BookSplitBands.svelte @@ -0,0 +1,61 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/stack/BookStackColoredSpine.svelte b/src/ui/components/bookshelf/designs/stack/BookStackColoredSpine.svelte new file mode 100644 index 0000000..920d50f --- /dev/null +++ b/src/ui/components/bookshelf/designs/stack/BookStackColoredSpine.svelte @@ -0,0 +1,40 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/stack/BookStackDefault.svelte b/src/ui/components/bookshelf/designs/stack/BookStackDefault.svelte new file mode 100644 index 0000000..b855299 --- /dev/null +++ b/src/ui/components/bookshelf/designs/stack/BookStackDefault.svelte @@ -0,0 +1,27 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/stack/BookStackDualTopBands.svelte b/src/ui/components/bookshelf/designs/stack/BookStackDualTopBands.svelte new file mode 100644 index 0000000..c7437f0 --- /dev/null +++ b/src/ui/components/bookshelf/designs/stack/BookStackDualTopBands.svelte @@ -0,0 +1,57 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/stack/BookStackSplitBands.svelte b/src/ui/components/bookshelf/designs/stack/BookStackSplitBands.svelte new file mode 100644 index 0000000..3f15d73 --- /dev/null +++ b/src/ui/components/bookshelf/designs/stack/BookStackSplitBands.svelte @@ -0,0 +1,57 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/ui/components/bookshelf/designs/tilted/BookTiltedDefault.svelte b/src/ui/components/bookshelf/designs/tilted/BookTiltedDefault.svelte new file mode 100644 index 0000000..590de09 --- /dev/null +++ b/src/ui/components/bookshelf/designs/tilted/BookTiltedDefault.svelte @@ -0,0 +1,47 @@ + + +
    + {@render children?.()} +
    + + diff --git a/src/utils/color.ts b/src/utils/color.ts index a76737c..9eca054 100644 --- a/src/utils/color.ts +++ b/src/utils/color.ts @@ -40,6 +40,16 @@ export class Color { return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a})`; } + get contrastColor(): Color { + return this.r * 0.299 + + this.g * 0.587 + + this.b * 0.114 + + (1 - this.a) * 255 > + 186 + ? new Color(0, 0, 0) + : new Color(255, 255, 255); + } + alpha(alpha: number): Color { return new Color(this.r, this.g, this.b, alpha); } @@ -56,6 +66,18 @@ export class Color { ); } + static fromCSSColor(color: string): Color { + const ctx = document.createElement("canvas").getContext("2d")!; + ctx.fillStyle = color; + const hexColor = ctx.fillStyle; + + return new Color( + parseInt(hexColor.slice(1, 3), 16), + parseInt(hexColor.slice(3, 5), 16), + parseInt(hexColor.slice(5, 7), 16) + ); + } + static getAll(): Color[] { return COLOR_NAMES.map((color) => Color.fromName(color)); }