diff --git a/artifacts/2026-02-15/badge.md b/artifacts/2026-02-15/badge.md new file mode 100644 index 000000000..c130c785b --- /dev/null +++ b/artifacts/2026-02-15/badge.md @@ -0,0 +1,20 @@ +# Cover Size Badge Specification + +## Overview +A new badge is displayed on book covers to indicate the resolution of the cover image. This helps users identifying high-quality covers (e.g., Audible's 2400x2400 format). + +## Logic +The badge is determined client-side once the image has loaded, using the `naturalWidth` and `naturalHeight` properties of the `HTMLImageElement`. + +### Size Tiers +| Tier | Criteria | Label | Color | +| :--- | :--- | :--- | :--- | +| **Big** | Width or Height >= 2400px | BIG | Success (Green) | +| **Medium** | Width or Height >= 1200px | MED | Info (Blue) | +| **Small** | Width or Height < 1200px | SML | Warning (Yellow) | + +## Implementation Details +- **Component**: `BookCover.vue` (and other cover components as needed). +- **Detection**: `imageLoaded` event captures dimensions. +- **UI**: Absolute positioned badge in the bottom-right corner. +- **Responsiveness**: Font size and padding scale with the `sizeMultiplier` of the cover component. diff --git a/artifacts/2026-02-17/badge.md b/artifacts/2026-02-17/badge.md new file mode 100644 index 000000000..cc2a632c7 --- /dev/null +++ b/artifacts/2026-02-17/badge.md @@ -0,0 +1,37 @@ +# Cover Size Badge Specification + +## Overview +Indicates the size tier of a book cover image directly on the cover in various views. This helps users quickly identify high-quality (Audible-grade) covers vs. lower resolution ones. + +## Size Tiers +The badge uses the following logic based on the image's natural dimensions (Width or Height): + +| Tier | Condition | Text | Color | +| :--- | :--- | :--- | :--- | +| **BIG** | Width or Height >= 1200px | BIG | Green (`bg-success`) | +| **MED** | Width or Height >= 450px | MED | Blue (`bg-info`) | +| **SML** | Width or Height < 450px | SML | Yellow (`bg-warning`) | + +## Implementation Details +The detection is performed server-side and stored in the database to ensure accuracy regardless of thumbnail sizes. + +### Dimension Detection +- `coverWidth` and `coverHeight` columns added to `books` and `podcasts` tables. +- A `beforeSave` hook on `Book` and `Podcast` models detects dimensions using `ffprobe` when `coverPath` changes. +- A database migration (`v2.32.7-add-cover-dimensions.js`) populates existing items. + +### Components Impacted +1. **`BookCover.vue`**: Used in detail views and some table rows (e.g., Collections). +2. **`LazyBookCard.vue`**: Used in main library bookshelf views, home page shelves, and search results. + +### Logic +- USE `media.coverWidth` and `media.coverHeight` (from the server) as the primary source. +- FALLBACK to `naturalWidth` and `naturalHeight` from the image's `@load` event if server data is unavailable. +- COMPUTE the badge tier based on the rules above. +- RENDER a small, absolute-positioned badge in the bottom-right corner of the cover. + +### UI Styling +- **Position**: Bottom-right of the cover image. +- **Font Size**: Scales with the `sizeMultiplier` (default `0.6rem`). +- **Pointer Events**: `none` (to avoid interfering with clicks). +- **Z-Index**: `20` (to stay above the cover and some overlays). diff --git a/client/components/cards/LazyBookCard.vue b/client/components/cards/LazyBookCard.vue index 7c40cbac2..54747d07c 100644 --- a/client/components/cards/LazyBookCard.vue +++ b/client/components/cards/LazyBookCard.vue @@ -122,6 +122,11 @@ folder_open + + +
{{ titleCleaned }}
@@ -52,7 +57,9 @@ export default { loading: true, imageFailed: false, showCoverBg: false, - imageReady: false + imageReady: false, + naturalWidth: 0, + naturalHeight: 0 } }, watch: { @@ -133,6 +140,18 @@ export default { }, resolution() { return `${this.naturalWidth}x${this.naturalHeight}px` + }, + coverBadge() { + const width = this.media?.coverWidth || this.naturalWidth + const height = this.media?.coverHeight || this.naturalHeight + if (!width || !height) return null + if (width >= 1200 || height >= 1200) { + return { text: 'BIG', color: 'bg-success' } + } + if (width >= 450 || height >= 450) { + return { text: 'MED', color: 'bg-info' } + } + return { text: 'SML', color: 'bg-warning' } } }, methods: { @@ -154,6 +173,8 @@ export default { if (this.$refs.cover && this.cover !== this.placeholderUrl) { var { naturalWidth, naturalHeight } = this.$refs.cover + this.naturalWidth = naturalWidth + this.naturalHeight = naturalHeight var aspectRatio = naturalHeight / naturalWidth var arDiff = Math.abs(aspectRatio - this.bookCoverAspectRatio) diff --git a/client/components/modals/libraries/LibraryTools.vue b/client/components/modals/libraries/LibraryTools.vue index 44875b663..16d89625a 100644 --- a/client/components/modals/libraries/LibraryTools.vue +++ b/client/components/modals/libraries/LibraryTools.vue @@ -49,6 +49,18 @@{{ $strings.LabelUpdateCoverDimensions }}
+{{ $strings.LabelUpdateCoverDimensionsHelp }}
+