[TAS-5149] ✨ Implement annotation feature for EPUB reader#643
[TAS-5149] ✨ Implement annotation feature for EPUB reader#643williamchong merged 17 commits intolikecoin:developfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Implements an annotation (highlights + notes) feature for the EPUB reader, including persistence via Firestore-backed APIs and new UI components for creating/editing/navigating annotations.
Changes:
- Added shared/server annotation types and Firestore utility functions for CRUD operations.
- Introduced
/api/books/:nftClassId/annotationsendpoints (list/create/update/delete). - Updated the EPUB reader UI to render highlights, show a selection menu + modal editor, and display an annotations list; added i18n strings and color constants.
Reviewed changes
Copilot reviewed 13 out of 15 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| shared/types/annotation.d.ts | Adds shared annotation type definitions (color, base fields, create/update shapes). |
| server/types/annotation.d.ts | Defines Firestore data shape for annotations. |
| server/utils/annotations.ts | Firestore CRUD utilities for annotations under user/book documents. |
| server/api/books/[nftClassId]/annotations/index.get.ts | Lists annotations for a user/book. |
| server/api/books/[nftClassId]/annotations/index.post.ts | Creates an annotation with basic validation. |
| server/api/books/[nftClassId]/annotations/[annotationId].post.ts | Updates annotation color/note. |
| server/api/books/[nftClassId]/annotations/[annotationId].delete.ts | Deletes an annotation. |
| constants/annotations.ts | Centralizes annotation color options and rgba mappings. |
| composables/use-annotations.ts | Client composable for fetching and mutating annotations via the new APIs. |
| components/AnnotationsList.vue | UI list for existing highlights/notes and navigation to a highlight. |
| components/AnnotationMenu.vue | Context menu for selection-based highlight color + “note” action. |
| components/AnnotationModal.vue | Modal UI for editing color and note, deleting highlights. |
| pages/reader/epub.vue | Integrates selection handling, highlight rendering, and annotation UI into the EPUB reader. |
| i18n/locales/en.json | Adds English strings for annotations UI. |
| i18n/locales/zh-Hant.json | Adds Traditional Chinese strings for annotations UI. |
2755eb5 to
1baa810
Compare
1baa810 to
83b6ac7
Compare
83b6ac7 to
4bc65b4
Compare
4bc65b4 to
9a3f098
Compare
03609fc to
ff39b68
Compare
| // Access via manager to get Contents array | ||
| const contents = rendition.value?.manager?.getContents() | ||
| const content = contents?.[0] | ||
| if (!content) { | ||
| isAnnotationMenuVisible.value = false | ||
| return | ||
| } | ||
|
|
||
| const cfiRange = content.cfiFromRange(range) | ||
| if (!cfiRange) { | ||
| isAnnotationMenuVisible.value = false | ||
| return | ||
| } | ||
|
|
||
| selectedText.value = text.slice(0, ANNOTATION_TEXT_MAX_LENGTH) | ||
| selectedCfi.value = cfiRange | ||
| selectedChapterTitle.value = activeNavItemLabel.value | ||
|
|
||
| const rect = range.getBoundingClientRect() | ||
| const iframe = renditionElement.value?.querySelector('iframe') | ||
| const iframeRect = iframe?.getBoundingClientRect() | ||
|
|
There was a problem hiding this comment.
handleTextSelection always uses contents?.[0] and the first iframe to compute the CFI range and menu position. In paginated/spread rendering there can be multiple Contents/iframes; this can produce an incorrect CFI and misplace the menu when the selection is in a different view. Prefer selecting the content/iframe that matches the viewWindow (e.g., match content.window === viewWindow or iframe.contentWindow === viewWindow).
commit 959d68f Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 17:35:05 2026 +0800 🎨 Update unused function param name commit ff39b68 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:51:03 2026 +0800 🎨 Use setHeaders instead of setResponseHeader commit 2745979 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:38:10 2026 +0800 🚸 Prevent system menu blocking annotation menu commit 9d36efc Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:37:56 2026 +0800 🐛 Fix annotation modal open when saving failed commit ab1ad96 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:33 2026 +0800 🎨 Sanitize annotations export filename commit 75f7eef Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:06 2026 +0800 🎨 Use UUID for temp annotation commit e2537e3 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:31:51 2026 +0800 🎨 Prevent memory leak commit 69bfe0b Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:29:49 2026 +0800 🥅 Guard annotation navigation commit 511a24e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:20:53 2026 +0800 🎨 Ensures annotations re-rendered when update commit 11a5734 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:44:15 2026 +0800 🔒 Truncate annotation text to max length on client side commit f6b262c Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:22:44 2026 +0800 🚸 Improve annotation UX commit a208d2e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 23:34:22 2026 +0800 🐛 Fix EventListener type mismatch in annotation highlight callback commit a360ab4 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 10:30:29 2026 +0800 🎨 Use typed Firestore collection commit 50f1949 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 12 22:52:15 2026 +0800 ✨ Support annotations export commit b5e85f8 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Tue Jan 27 15:41:25 2026 +0800 ✨ Implement annotation feature for EPUB reader
commit 959d68f Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 17:35:05 2026 +0800 🎨 Update unused function param name commit ff39b68 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:51:03 2026 +0800 🎨 Use setHeaders instead of setResponseHeader commit 2745979 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:38:10 2026 +0800 🚸 Prevent system menu blocking annotation menu commit 9d36efc Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:37:56 2026 +0800 🐛 Fix annotation modal open when saving failed commit ab1ad96 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:33 2026 +0800 🎨 Sanitize annotations export filename commit 75f7eef Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:06 2026 +0800 🎨 Use UUID for temp annotation commit e2537e3 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:31:51 2026 +0800 🎨 Prevent memory leak commit 69bfe0b Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:29:49 2026 +0800 🥅 Guard annotation navigation commit 511a24e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:20:53 2026 +0800 🎨 Ensures annotations re-rendered when update commit 11a5734 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:44:15 2026 +0800 🔒 Truncate annotation text to max length on client side commit f6b262c Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:22:44 2026 +0800 🚸 Improve annotation UX commit a208d2e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 23:34:22 2026 +0800 🐛 Fix EventListener type mismatch in annotation highlight callback commit a360ab4 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 10:30:29 2026 +0800 🎨 Use typed Firestore collection commit 50f1949 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 12 22:52:15 2026 +0800 ✨ Support annotations export commit b5e85f8 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Tue Jan 27 15:41:25 2026 +0800 ✨ Implement annotation feature for EPUB reader
| return annotation | ||
| } | ||
|
|
||
| async function saveAnnotation(annotationId: string, data: AnnotationCreateData): Promise<Annotation | null> { |
There was a problem hiding this comment.
Race condition potential: If saveAnnotation is called while a previous fetchAnnotations is still in progress (via fetchPromise), the local annotation will be removed on line 56 but the fetch might complete afterwards and not include the new annotation. This could lead to a lost annotation in the UI. Consider checking if a fetch is in progress before removing the annotation, or handle this case explicitly.
| async function saveAnnotation(annotationId: string, data: AnnotationCreateData): Promise<Annotation | null> { | |
| async function saveAnnotation(annotationId: string, data: AnnotationCreateData): Promise<Annotation | null> { | |
| // Ensure any in-flight fetchAnnotations completes before we mutate annotations | |
| if (fetchPromise.value) { | |
| await fetchPromise.value | |
| } |
| catch (error) { | ||
| if (error instanceof H3Error && error.statusCode === 404) { | ||
| throw error | ||
| } | ||
| console.error(`Failed to update annotation ${annotationId}:`, error) | ||
| throw createError({ | ||
| statusCode: 500, | ||
| message: 'FAILED_TO_UPDATE_ANNOTATION', | ||
| }) | ||
| } |
There was a problem hiding this comment.
Inconsistent error handling: The error handling here wraps specific error types (H3Error with 404) but re-throws them, which is correct. However, other endpoints like index.post.ts (lines 99-105) check for specific gRPC status codes. Consider documenting the error handling patterns or creating a shared error handling utility to ensure consistency across all annotation endpoints.
| setTimeout(() => { | ||
| editingAnnotation.value = null | ||
| isNewAnnotation.value = false | ||
| }, 300) |
There was a problem hiding this comment.
Modal state timing: The modal close and state cleanup use a 300ms timeout (lines 1306-1309, 1334-1337) to wait for the modal close animation. This hardcoded delay could cause issues if the modal's animation duration changes. Consider using a CSS transition event listener or defining the animation duration as a shared constant to ensure the timing stays synchronized.
| if (removeMouseUpListener) { | ||
| removeMouseUpListener() | ||
| } | ||
| removeMouseUpListener = useEventListener(view.window, 'mouseup', (event: MouseEvent) => { | ||
| // Delay for window.getSelection() reflects the final selection state | ||
| setTimeout(() => { | ||
| handleTextSelection(event, view.window) | ||
| }, 10) | ||
| }) | ||
|
|
||
| if (removeTouchEndListener) { | ||
| removeTouchEndListener() | ||
| } | ||
| removeTouchEndListener = useEventListener(view.window, 'touchend', (event: TouchEvent) => { | ||
| // Delay for touch selection to allow the browser's native selection UI (drag handles) to stabilize | ||
| setTimeout(() => { | ||
| const touch = event.changedTouches[0] | ||
| if (touch) { | ||
| const mouseEvent = { clientX: touch.clientX, clientY: touch.clientY } as MouseEvent | ||
| handleTextSelection(mouseEvent, view.window) | ||
| } | ||
| }, 300) | ||
| }) |
There was a problem hiding this comment.
Memory management: The cleanup in onBeforeUnmount is good, but the removeMouseUpListener and removeTouchEndListener are added in the displayed event handler (lines 799-821) which fires for each page/section loaded. If the user navigates through multiple pages before unmounting, multiple listeners could be registered without cleanup. The current implementation only stores the latest cleanup function, so previous listeners may leak. Consider removing the old listener before adding a new one, e.g., if (removeMouseUpListener) removeMouseUpListener() before line 802.
commit 959d68f Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 17:35:05 2026 +0800 🎨 Update unused function param name commit ff39b68 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:51:03 2026 +0800 🎨 Use setHeaders instead of setResponseHeader commit 2745979 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:38:10 2026 +0800 🚸 Prevent system menu blocking annotation menu commit 9d36efc Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:37:56 2026 +0800 🐛 Fix annotation modal open when saving failed commit ab1ad96 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:33 2026 +0800 🎨 Sanitize annotations export filename commit 75f7eef Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:06 2026 +0800 🎨 Use UUID for temp annotation commit e2537e3 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:31:51 2026 +0800 🎨 Prevent memory leak commit 69bfe0b Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:29:49 2026 +0800 🥅 Guard annotation navigation commit 511a24e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:20:53 2026 +0800 🎨 Ensures annotations re-rendered when update commit 11a5734 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:44:15 2026 +0800 🔒 Truncate annotation text to max length on client side commit f6b262c Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:22:44 2026 +0800 🚸 Improve annotation UX commit a208d2e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 23:34:22 2026 +0800 🐛 Fix EventListener type mismatch in annotation highlight callback commit a360ab4 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 10:30:29 2026 +0800 🎨 Use typed Firestore collection commit 50f1949 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 12 22:52:15 2026 +0800 ✨ Support annotations export commit b5e85f8 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Tue Jan 27 15:41:25 2026 +0800 ✨ Implement annotation feature for EPUB reader
commit 959d68f Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 17:35:05 2026 +0800 🎨 Update unused function param name commit ff39b68 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:51:03 2026 +0800 🎨 Use setHeaders instead of setResponseHeader commit 2745979 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:38:10 2026 +0800 🚸 Prevent system menu blocking annotation menu commit 9d36efc Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:37:56 2026 +0800 🐛 Fix annotation modal open when saving failed commit ab1ad96 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:33 2026 +0800 🎨 Sanitize annotations export filename commit 75f7eef Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:06 2026 +0800 🎨 Use UUID for temp annotation commit e2537e3 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:31:51 2026 +0800 🎨 Prevent memory leak commit 69bfe0b Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:29:49 2026 +0800 🥅 Guard annotation navigation commit 511a24e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:20:53 2026 +0800 🎨 Ensures annotations re-rendered when update commit 11a5734 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:44:15 2026 +0800 🔒 Truncate annotation text to max length on client side commit f6b262c Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:22:44 2026 +0800 🚸 Improve annotation UX commit a208d2e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 23:34:22 2026 +0800 🐛 Fix EventListener type mismatch in annotation highlight callback commit a360ab4 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 10:30:29 2026 +0800 🎨 Use typed Firestore collection commit 50f1949 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 12 22:52:15 2026 +0800 ✨ Support annotations export commit b5e85f8 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Tue Jan 27 15:41:25 2026 +0800 ✨ Implement annotation feature for EPUB reader
commit 959d68f Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 17:35:05 2026 +0800 🎨 Update unused function param name commit ff39b68 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:51:03 2026 +0800 🎨 Use setHeaders instead of setResponseHeader commit 2745979 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:38:10 2026 +0800 🚸 Prevent system menu blocking annotation menu commit 9d36efc Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:37:56 2026 +0800 🐛 Fix annotation modal open when saving failed commit ab1ad96 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:33 2026 +0800 🎨 Sanitize annotations export filename commit 75f7eef Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:06 2026 +0800 🎨 Use UUID for temp annotation commit e2537e3 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:31:51 2026 +0800 🎨 Prevent memory leak commit 69bfe0b Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:29:49 2026 +0800 🥅 Guard annotation navigation commit 511a24e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:20:53 2026 +0800 🎨 Ensures annotations re-rendered when update commit 11a5734 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:44:15 2026 +0800 🔒 Truncate annotation text to max length on client side commit f6b262c Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:22:44 2026 +0800 🚸 Improve annotation UX commit a208d2e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 23:34:22 2026 +0800 🐛 Fix EventListener type mismatch in annotation highlight callback commit a360ab4 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 10:30:29 2026 +0800 🎨 Use typed Firestore collection commit 50f1949 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 12 22:52:15 2026 +0800 ✨ Support annotations export commit b5e85f8 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Tue Jan 27 15:41:25 2026 +0800 ✨ Implement annotation feature for EPUB reader
commit 959d68f Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 17:35:05 2026 +0800 🎨 Update unused function param name commit ff39b68 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:51:03 2026 +0800 🎨 Use setHeaders instead of setResponseHeader commit 2745979 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:38:10 2026 +0800 🚸 Prevent system menu blocking annotation menu commit 9d36efc Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:37:56 2026 +0800 🐛 Fix annotation modal open when saving failed commit ab1ad96 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:33 2026 +0800 🎨 Sanitize annotations export filename commit 75f7eef Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:06 2026 +0800 🎨 Use UUID for temp annotation commit e2537e3 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:31:51 2026 +0800 🎨 Prevent memory leak commit 69bfe0b Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:29:49 2026 +0800 🥅 Guard annotation navigation commit 511a24e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:20:53 2026 +0800 🎨 Ensures annotations re-rendered when update commit 11a5734 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:44:15 2026 +0800 🔒 Truncate annotation text to max length on client side commit f6b262c Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:22:44 2026 +0800 🚸 Improve annotation UX commit a208d2e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 23:34:22 2026 +0800 🐛 Fix EventListener type mismatch in annotation highlight callback commit a360ab4 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 10:30:29 2026 +0800 🎨 Use typed Firestore collection commit 50f1949 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 12 22:52:15 2026 +0800 ✨ Support annotations export commit b5e85f8 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Tue Jan 27 15:41:25 2026 +0800 ✨ Implement annotation feature for EPUB reader
commit 959d68f Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 17:35:05 2026 +0800 🎨 Update unused function param name commit ff39b68 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:51:03 2026 +0800 🎨 Use setHeaders instead of setResponseHeader commit 2745979 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 16:38:10 2026 +0800 🚸 Prevent system menu blocking annotation menu commit 9d36efc Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:37:56 2026 +0800 🐛 Fix annotation modal open when saving failed commit ab1ad96 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:33 2026 +0800 🎨 Sanitize annotations export filename commit 75f7eef Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 15:00:06 2026 +0800 🎨 Use UUID for temp annotation commit e2537e3 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:31:51 2026 +0800 🎨 Prevent memory leak commit 69bfe0b Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:29:49 2026 +0800 🥅 Guard annotation navigation commit 511a24e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 14:20:53 2026 +0800 🎨 Ensures annotations re-rendered when update commit 11a5734 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:44:15 2026 +0800 🔒 Truncate annotation text to max length on client side commit f6b262c Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 26 10:22:44 2026 +0800 🚸 Improve annotation UX commit a208d2e Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 23:34:22 2026 +0800 🐛 Fix EventListener type mismatch in annotation highlight callback commit a360ab4 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Wed Feb 25 10:30:29 2026 +0800 🎨 Use typed Firestore collection commit 50f1949 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Thu Feb 12 22:52:15 2026 +0800 ✨ Support annotations export commit b5e85f8 Author: Ng Wing Tat, David <i@ngwingt.at> Date: Tue Jan 27 15:41:25 2026 +0800 ✨ Implement annotation feature for EPUB reader
| let body: AnnotationCreateData | ||
| try { | ||
| body = await readBody(event) | ||
| } |
There was a problem hiding this comment.
This handler types body as AnnotationCreateData but doesn’t import that type. If annotation types are module exports (as in shared/types/annotation.d.ts), this will fail typechecking. Import AnnotationCreateData (and any related types) explicitly or define them as ambient types under /types.
| const props = defineProps<{ | ||
| annotations: Annotation[] | ||
| }>() | ||
|
|
||
| const emit = defineEmits<{ | ||
| (e: 'navigate', annotation: Annotation): void | ||
| }>() |
There was a problem hiding this comment.
This component references Annotation and AnnotationColor in prop and function typing but doesn’t import them. Add explicit type imports from ~/shared/types/annotation (or declare these as ambient types under /types) to avoid TypeScript errors.
| const props = defineProps<{ | ||
| annotation?: Annotation | null | ||
| text: string | ||
| initialColor: AnnotationColor | ||
| isNewAnnotation?: boolean | ||
| }>() | ||
|
|
||
| const emit = defineEmits<{ | ||
| (e: 'save', data: { color: AnnotationColor, note: string }): void | ||
| (e: 'delete'): void | ||
| }>() |
There was a problem hiding this comment.
This component uses Annotation/AnnotationColor in props/emits typing without importing them. Unless these are ambient declarations, this will fail nuxt typecheck. Import the types from ~/shared/types/annotation or define them as ambient types under /types (consistent with other globally declared interfaces).
| export default function useAnnotations(params: { | ||
| nftClassId: Ref<string> | ComputedRef<string> | string | ||
| }) { | ||
| const { loggedIn: hasLoggedIn } = useUserSession() | ||
| const nftClassId = computed(() => toValue(params.nftClassId)) | ||
|
|
||
| const annotations = ref<Annotation[]>([]) | ||
| const isLoading = ref(false) | ||
| const hasFetched = ref(false) | ||
| const fetchPromise = ref<Promise<void> | null>(null) |
There was a problem hiding this comment.
This composable uses Annotation, AnnotationCreateData, and AnnotationUpdateData without importing them. Unless these are ambient/global types, this will break nuxt typecheck. Import the needed types from ~/shared/types/annotation, or provide a global types/annotation.d.ts ambient declaration that matches the rest of the repo’s type pattern.
| let body: AnnotationUpdateData | ||
| try { | ||
| body = await readBody(event) | ||
| } |
There was a problem hiding this comment.
This handler types body as AnnotationUpdateData but doesn’t import that type. Add an explicit import type { AnnotationUpdateData } from '~/shared/types/annotation' (or make the annotation types ambient under /types) so nuxt typecheck doesn’t fail.
| @@ -365,6 +411,20 @@ const isMobileTocOpen = computed({ | |||
|
|
|||
| const isPageLoading = ref(false) | |||
|
|
|||
| const isAnnotationMenuVisible = ref(false) | |||
| const annotationMenuPosition = ref({ x: 0, y: 0, yBottom: 0 }) | |||
| const selectedText = ref('') | |||
| const selectedCfi = ref('') | |||
| const selectedChapterTitle = ref('') | |||
| const isAnnotationModalOpen = ref(false) | |||
| const editingAnnotation = ref<Annotation | null>(null) | |||
| const isNewAnnotation = ref(false) | |||
| const pendingAnnotationColor = ref<AnnotationColor>('yellow') | |||
| const isAnnotationsListOpen = ref(false) | |||
| const isAnnotationClickInProgress = ref(false) | |||
| const pendingSavePromise = ref<Promise<Annotation | null> | null>(null) | |||
| const renderedHighlights = new Set<string>() | |||
There was a problem hiding this comment.
This page uses Annotation, AnnotationColor, and AnnotationCreateData types without importing them. Unless they are ambient/global, this will break typechecking. Import the types from ~/shared/types/annotation (preferred if keeping them as module exports), or move them to an ambient /types/annotation.d.ts to match the repo’s existing global-type convention.
| const ANNOTATION_COLOR_RGB: Record<AnnotationColor, string> = { | ||
| yellow: '202, 138, 4', | ||
| red: '220, 38, 38', | ||
| green: '22, 163, 74', | ||
| blue: '37, 99, 235', | ||
| } | ||
|
|
||
| /** | ||
| * Valid annotation color values for validation | ||
| */ | ||
| export const ANNOTATION_COLORS = Object.keys(ANNOTATION_COLOR_RGB) as AnnotationColor[] | ||
|
|
There was a problem hiding this comment.
AnnotationColor is referenced but not imported or declared as an ambient type. As written, this will fail TypeScript typechecking unless AnnotationColor is globally declared elsewhere. Either (a) move the annotation types into /types/*.d.ts using declare type/interface (to match existing global type patterns), or (b) add an explicit import type { AnnotationColor } from '~/shared/types/annotation' (and similarly for other annotation types) and use that import consistently.
Uh oh!
There was an error while loading. Please reload this page.