feat: enhance whiteboard and dock - #25
Conversation
…Shell to hide close button
…rovements - Added text styling options including weight, style, decoration, and alignment to the whiteboard. - Implemented a new composable `useFloatingDock` for managing dock position and drag functionality. - Refactored dock position handling in `WhiteboardShell.vue` to utilize the new composable. - Introduced `useDockModeConfig` to manage tool availability and controls based on dock mode. - Updated canvas drawing utilities to support new text properties and arrow styles. - Normalized drawing actions to include new properties for text and shapes. - Enhanced renderer to handle rounded rectangles and styled arrows. - Added local shortcuts for new tools and updated shortcut definitions. - Updated localization files to include new text styling options and shapes. - Refactored settings store to manage new text and shape properties.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (12)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (9)
📝 WalkthroughWalkthroughChangesCanvas editing and dock expansion
Project metadata and build configuration
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant FloatingDock
participant CanvasStage
participant useCanvasDrawing
participant CanvasRenderer
User->>FloatingDock: choose style or selection action
FloatingDock->>CanvasStage: emit control event
CanvasStage->>useCanvasDrawing: update selection or drawing action
useCanvasDrawing->>CanvasRenderer: redraw normalized action
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/utils/canvas/renderer.ts (1)
533-553: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftText bounds ignore wrapping, so selection/hit-testing drifts from what is rendered.
drawActionlays text out withwrapText(ctx, text, maxWidth), but these bounds measure raw\n-split lines. Any text that wraps renders taller (and narrower) than the box returned here, sohitTestText,hitTestAction,eraseAtPoint, and the selection rectangle all miss the wrapped continuation lines. Reuse the same wrap computation for both paths — extracting a sharedlayoutText(ctx, action)helper would keep the two in sync.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/canvas/renderer.ts` around lines 533 - 553, The text-bounds calculation near drawAction must use the same wrapping layout as rendering instead of measuring raw newline-separated lines. Extract or reuse a shared layoutText helper that applies wrapText with the action’s max width, then use its wrapped lines for width and height while preserving text alignment; update drawAction and the bounds path to consume this shared result.
🧹 Nitpick comments (11)
src/composables/useCanvasDrawing.ts (2)
906-933: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winRedundant group expansion, and
lastPointgoes stale when everything is locked.
getSelectedActions()already runsexpandSelectionWithGroups, so themoveIdsloop on Lines 911-920 re-expands groups a second time — it can be dropped. Separately, the early return on Line 925 (all selected items locked) skips thedragState.lastPoint = pointupdate, so the accumulated delta is applied in one jump if the pointer keeps moving and an item later becomes movable.♻️ Proposed fix
- const moveIds = new Set<string>(); - selected.forEach((entry) => { - moveIds.add(entry.id); - if (!entry.groupId) return; - actions.value.forEach((candidate) => { - if (candidate.groupId === entry.groupId) { - moveIds.add(candidate.id); - } - }); - }); - - const movable = actions.value.filter( - (entry) => moveIds.has(entry.id) && !entry.locked, - ); - if (movable.length === 0) return; - const lastPoint = dragState.value.lastPoint; if (!lastPoint) return; + const movable = selected.filter((entry) => !entry.locked); const deltaX = point.x - lastPoint.x; const deltaY = point.y - lastPoint.y; movable.forEach((entry) => { entry.points = translatePoints(entry.points, deltaX, deltaY); });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/composables/useCanvasDrawing.ts` around lines 906 - 933, Update updateSelection to use the IDs returned by getSelectedActions directly, removing the redundant group expansion loop. Ensure dragState.value.lastPoint is updated to the current point before returning when movable is empty, so pointer movement over fully locked selections does not accumulate stale deltas.
625-667: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy liftLock/group/ungroup mutate actions without a history entry.
toggleSelectedLock,groupSelectedActions, andungroupSelectedActionsmutatelocked/groupIdin place and never push tohistoryStack, soCtrl+Zcannot revert them. Worse, undoing an earlieraddafter a group operation restores stale membership, since group ids were rewritten outside the history model. Consider a third history entry type (e.g.{ type: "mutate"; before: Array<{id, locked, groupId}> }).Also,
groupSelectedActionsreuses the first pre-existing group id found (Line 646), which silently merges two distinct existing groups into one; a fresh id would be less surprising.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/composables/useCanvasDrawing.ts` around lines 625 - 667, Update toggleSelectedLock, groupSelectedActions, and ungroupSelectedActions to record their in-place locked/groupId changes as a dedicated mutate history entry containing the affected actions’ prior state, so Ctrl+Z restores those values and earlier add undo cannot resurrect stale group membership. Only append history when a mutation actually occurs, preserving existing no-op returns. In groupSelectedActions, always assign a fresh group id instead of reusing any pre-existing selected group id.src/components/shared/CanvasStage.vue (1)
318-321: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueFont string duplicates
buildFontinsrc/utils/canvas/renderer.ts.The mirror/measurement font here must match the canvas font used for rendering; keeping two literal templates invites drift. Export
buildFont(or a smallformatCanvasFont(style, weight, size, family)helper insrc/utils/canvas/) and call it from both.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/shared/CanvasStage.vue` around lines 318 - 321, Update the font construction in CanvasStage’s mirror/measurement logic to reuse the shared buildFont or formatting helper from the canvas renderer utilities instead of maintaining a duplicate template. Export the shared formatter as needed, then call it from both CanvasStage and the renderer so measurement and rendering always use identical font strings.src/types/drawing.ts (1)
46-51: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider exporting alias types for the repeated unions.
"normal" | "bold","none" | "underline","left" | "center" | "right", and the arrow-style union are re-declared verbatim insrc/utils/canvas/normalizer.ts,src/composables/useCanvasDrawing.ts,src/components/shared/CanvasStage.vue, and both shells. ExportingTextWeight,TextStyle,TextDecoration,TextAlign, andArrowStylefrom here keeps them in sync.♻️ Proposed alias types
+export type TextWeight = "normal" | "bold"; +export type TextStyle = "normal" | "italic"; +export type TextDecoration = "none" | "underline"; +export type TextAlign = "left" | "center" | "right"; +export type ArrowStyle = "simple" | "filled" | "double" | "thick" | "stealth"; + export type DrawAction = {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/types/drawing.ts` around lines 46 - 51, Define and export shared alias types named TextWeight, TextStyle, TextDecoration, TextAlign, and ArrowStyle in the drawing types module, then update the repeated union declarations in the normalizer, useCanvasDrawing, CanvasStage, and both shells to import and reuse these aliases.src/utils/canvas/normalizer.ts (1)
55-86: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winNormalization skips the fields most likely to be malformed.
The helpers defensively accept
unknown, which implies this runs on untrusted/persisted data (replaceActionsfeeds it straight into the render loop), yetid,tool,color, andcompositeare spread through unvalidated. An unknowntoolsilently falls throughdrawActiontogetPointsBounds, and a boguscompositestring assigned toctx.globalCompositeOperationis ignored by the browser but leaves the action permanently mis-typed. Also consider typing the parameter asunknown(orPartial<DrawAction>) so callers with raw JSON don't have to cast.Minor side note: text-only fields (
fontSize,fontWeight,textAlign, …) andarrowStyleare now stamped onto every pen/rect/ellipse action, which inflates persisted payloads. Gating them onaction.toolwould keep the model lean.♻️ Sketch
-export function normalizeDrawAction(action: DrawAction): DrawAction { +const TOOL_IDS = new Set<ToolId>([...]); + +export function normalizeDrawAction(input: unknown): DrawAction { + const action = (input ?? {}) as DrawAction; + const tool = TOOL_IDS.has(action.tool) ? action.tool : "pen"; const points = normalizePoints(action.points);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/canvas/normalizer.ts` around lines 55 - 86, Update normalizeDrawAction to accept raw or partial input and validate/default id, tool, color, and composite alongside the existing normalized fields, ensuring unknown tool and composite values cannot reach rendering. Preserve a valid DrawAction shape for untrusted persisted data, reusing existing normalization conventions where applicable. Only include text-specific fields and arrowStyle when action.tool supports them so unrelated actions are not inflated.src/components/overlay/OverlayShell.vue (1)
96-106: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftPosition ownership is now split between the composable and this component.
useFloatingDockownsdockPositionand watchessourcePosition(overlayDockPosition), yetcalculateInitialPosition(Line 256-264) writesdockPosition.valuewithout persisting it — the next store write tooverlayDockPositionreverts that value through the composable's watcher.recalculateDockPosition/resetAndRecalculatealso re-implement clamping that already exists insidehandleDockDrag. Moving the viewport-resize recalibration intouseFloatingDockwould give both shells the same behaviour and remove the dual ownership.As per coding guidelines: "Prefer composables for reusable logic in the frontend".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/overlay/OverlayShell.vue` around lines 96 - 106, Move viewport-resize recalibration from OverlayShell’s calculateInitialPosition, recalculateDockPosition, and resetAndRecalculate into useFloatingDock, making the composable the sole owner of dockPosition and its persistence. Reuse handleDockDrag’s existing clamping and ensure recalculated positions are persisted so sourcePosition updates cannot revert them. Update both dock consumers to use the shared composable behavior and remove the component-level duplicate logic.Source: Coding guidelines
src/components/shared/FloatingDock.vue (1)
44-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winImport
DockModeinstead of re-declaring the union.
mode?: "overlay" | "whiteboard"duplicatesuseDockModeConfig.ts's exportedDockModetype. If a mode is ever added there, this prop type won't be updated automatically and the mismatch would only surface indirectly.♻️ Reuse the shared type
-import { useDockModeConfig } from "../../composables/useDockModeConfig"; +import { useDockModeConfig } from "../../composables/useDockModeConfig"; +import type { DockMode } from "../../composables/useDockModeConfig"; ... const props = defineProps<{ - mode?: "overlay" | "whiteboard"; + mode?: DockMode;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/shared/FloatingDock.vue` around lines 44 - 46, Update FloatingDock’s props definition to import and use the exported DockMode type from useDockModeConfig.ts instead of re-declaring the "overlay" | "whiteboard" union for mode, so it stays synchronized with the shared mode definition.src/composables/useFloatingDock.ts (1)
25-45: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winNo
resizelistener — dock position/tooltip placement can go stale after a window resize.
dockTooltipPlacementandapplyPositionForOrientationboth readglobalThis.innerWidth/innerHeight, but nothing recomputes them when the window resizes (only drag/orientation changes trigger updates). After a resize, the dock can remain positioned for the old viewport size, and the tooltip placement heuristic can be wrong until the next drag.♻️ Add a resize listener
onBeforeUnmount(() => { globalThis.removeEventListener("pointermove", handleDockDrag); globalThis.removeEventListener("pointerup", stopDockDrag); + globalThis.removeEventListener("resize", applyPositionForOrientation); }); + + globalThis.addEventListener("resize", applyPositionForOrientation);Also applies to: 47-71, 121-124
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/composables/useFloatingDock.ts` around lines 25 - 45, Add a window resize listener in the useFloatingDock lifecycle so it invokes applyPositionForOrientation and refreshes dockTooltipPlacement after viewport dimensions change. Register the listener on mount and remove the same handler on unmount, preserving existing drag and orientation behavior.src/stores/settings.ts (2)
277-281: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDash-pattern normalization (filter finite/non-negative values, then round) is implemented independently in three places. Extract one shared helper so the algorithm can't drift between the store and the dock component.
src/stores/settings.ts#L277-L281: move the filter/round logic insetDashPatterninto a sharednormalizeDashPattern(pattern: number[]): number[]helper (exported from this file or a shared utils module).src/stores/settings.ts#L424-L428: call the same shared helper instead of re-implementing the filter/round inline inapplySettings.src/components/shared/FloatingDock.vue#L175-L179: drop the localnormalizeDashPatternand import the shared helper (e.g. from the settings store or a canvas normalizer utility) instead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/stores/settings.ts` around lines 277 - 281, Extract the shared normalizeDashPattern(pattern: number[]): number[] helper from the inline logic in src/stores/settings.ts lines 277-281, preserving finite/non-negative filtering and rounding. Update src/stores/settings.ts lines 424-428 to call it, and remove the local helper in src/components/shared/FloatingDock.vue lines 175-179 so that component imports and uses the shared implementation.
18-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider centralizing the text/arrow-style literal unions.
"normal" | "bold","left" | "center" | "right","simple" | "filled" | "double" | "thick" | "stealth", etc. are declared repeatedly (this file'sSettingstype, refs, setter params, guards) and again insrc/types/overlay.ts'sOverlayPayloadandFloatingDock.vue. A shared exported type (e.g. insrc/types/drawing.ts) would avoid drift if a new style value is ever added.
src/types/drawing.tsisn't included in this review batch — please confirm whether it already exports these unions (it's listed as part of the "Drawing contracts and normalization" layer) before extracting a new one.Also applies to: 74-84
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/stores/settings.ts` around lines 18 - 23, Check src/types/drawing.ts first and reuse any existing exported text and arrow-style unions; only define shared exports there if they are absent. Update Settings, its refs, setter parameters, and guards to consume those types, then replace duplicate literals in OverlayPayload and FloatingDock.vue with the same shared definitions so all style values remain synchronized.src/composables/useDockModeConfig.ts (1)
8-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
overlayandwhiteboardconfigs are currently identical.Both branches of
toolsByModeandcontrolsByModelist the exact same tools/flags. If this is intentional scaffolding for future divergence, fine — but as written the two branches must be manually kept in sync, and nothing currently enforces that. Consider a single shared config object (with per-mode overrides only where they actually differ) until real per-mode differences exist.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/composables/useDockModeConfig.ts` around lines 8 - 52, Consolidate the identical overlay and whiteboard entries in toolsByMode and controlsByMode into shared configuration data, avoiding duplicate tool lists and control flags that can drift out of sync. Preserve both DockMode keys and the current behavior, while leaving a clear path for future per-mode overrides.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.oxlintrc.json:
- Line 16: Remove the trailing // comment and any associated empty override
block from .oxlintrc.json so it remains valid JSON; only rename the
configuration to .oxlintrc.jsonc if comments are intentionally required.
In `@src/App.vue`:
- Line 63: Update the conditional rendering around ZoomShell and the v-else
AppShell in App.vue so zoom mode does not fall through to AppShell while
settingsReady is false. Add an explicit zoom loading/empty branch or exclude
isZoom from the AppShell fallback, while preserving ZoomShell rendering once
settingsReady and zoomMotor === 'dxgi'.
In `@src/components/app/AppShell.vue`:
- Around line 355-363: Normalize the dashPattern value before spreading it in
the overlay-toolbar update handler, using an empty array when
payload.dashPattern is missing. Update the setDashPattern call in the
AppShell.vue flow and match the existing handling in WhiteboardShell.vue; leave
the other setting defaults unchanged.
In `@src/components/overlay/OverlayShell.vue`:
- Around line 108-122: Guard the optional dashPattern field before spreading it
in both applyPayload implementations: update
src/components/overlay/OverlayShell.vue lines 108-122 and
src/components/whiteboard/WhiteboardShell.vue lines 176-184 to use an
empty-array fallback when payload.dashPattern is absent, preserving
synchronization for older or partial payloads.
- Around line 216-224: The group toggle handlers incorrectly use
groupSelection()'s return value to decide whether to ungroup. In
src/components/overlay/OverlayShell.vue lines 216-224 and
src/components/whiteboard/WhiteboardShell.vue lines 220-228, use the current
fully-grouped selection state exposed by useCanvasDrawing: call
ungroupSelection() when already grouped, otherwise call groupSelection(),
keeping both handlers identical or sharing the implementation.
In `@src/components/shared/CanvasStage.vue`:
- Around line 95-142: Update handleSharedEditHotkeys to return early when the
keyboard event target is an input, textarea, select, or contenteditable element,
in addition to the existing textInput.visible guard. Keep canvas hotkeys active
for other targets while preventing Ctrl+C/V/D/L/G from hijacking focused
form-field editing.
In `@src/components/shared/FloatingDock.vue`:
- Around line 415-419: Add outside-interaction handling for the more-options
menu controlled by moreOptionsOpen: register a document-level pointerdown
handler that closes the menu when the target is outside the menu and its toggle
button, while preserving the existing `@pointerdown.stop` behavior inside
more-options-overlay. Remove the handler during component cleanup and keep
toggleMoreOptions responsible for button toggling.
- Around line 173-230: Extract the line-style and shape-style business logic
from FloatingDock into a dedicated composable such as useLineStyleControls or
useShapeStyleControls. Move dash preset normalization, width-based pattern
generation and inference, nextDashPattern, border-radius cycling, and
arrow-style cycling into the composable, while keeping store access and reactive
state behavior intact. Update FloatingDock to consume the composable’s returned
state and handlers so the component remains focused on UI rendering and events.
- Around line 415-552: Update every icon-only button in the moreOptionsOpen
overlay, including the dash-style, lock, group, smoothing, auto-erase,
corner-radius, arrow-style, and text formatting/alignment controls, to provide
an accessible aria-label using the corresponding translated label. Extend the
tooltip styling or behavior so tooltip text is also shown when a button receives
:focus-visible, preserving the existing hover behavior.
In `@src/locales/es.json`:
- Around line 16-41: Correct the Spanish translations in the locale entries
around moreOptions, strokeDash, lockSelection, toggleGroupSelection, and
dashOptions.solid by adding the appropriate accents and using natural Spanish
terminology, including “Más”, “línea”, “selección”, and “Sólida”.
In `@src/utils/canvas/renderer.ts`:
- Around line 439-453: Update the underline rendering in the adjustedAction
text-decoration path to temporarily clear the line dash inherited from
applyStyle and restore the prior lineWidth after stroking, preserving
surrounding canvas state. Also correct the maxWidth calculation in the nearby
text wrapping logic to account for the canvas transform’s pan translation as
well as its scale, so wrapping remains aligned after panning.
- Around line 201-206: Update drawTailHead so its neighbor-point selection is
intentional rather than using identical ternary branches: mirror the existing
head-side smoothing behavior for arrows with more than two points, while
retaining the appropriate fallback for shorter arrows. Use the selected neighbor
when calculating tailAngle and preserve the existing missing-point guard.
---
Outside diff comments:
In `@src/utils/canvas/renderer.ts`:
- Around line 533-553: The text-bounds calculation near drawAction must use the
same wrapping layout as rendering instead of measuring raw newline-separated
lines. Extract or reuse a shared layoutText helper that applies wrapText with
the action’s max width, then use its wrapped lines for width and height while
preserving text alignment; update drawAction and the bounds path to consume this
shared result.
---
Nitpick comments:
In `@src/components/overlay/OverlayShell.vue`:
- Around line 96-106: Move viewport-resize recalibration from OverlayShell’s
calculateInitialPosition, recalculateDockPosition, and resetAndRecalculate into
useFloatingDock, making the composable the sole owner of dockPosition and its
persistence. Reuse handleDockDrag’s existing clamping and ensure recalculated
positions are persisted so sourcePosition updates cannot revert them. Update
both dock consumers to use the shared composable behavior and remove the
component-level duplicate logic.
In `@src/components/shared/CanvasStage.vue`:
- Around line 318-321: Update the font construction in CanvasStage’s
mirror/measurement logic to reuse the shared buildFont or formatting helper from
the canvas renderer utilities instead of maintaining a duplicate template.
Export the shared formatter as needed, then call it from both CanvasStage and
the renderer so measurement and rendering always use identical font strings.
In `@src/components/shared/FloatingDock.vue`:
- Around line 44-46: Update FloatingDock’s props definition to import and use
the exported DockMode type from useDockModeConfig.ts instead of re-declaring the
"overlay" | "whiteboard" union for mode, so it stays synchronized with the
shared mode definition.
In `@src/composables/useCanvasDrawing.ts`:
- Around line 906-933: Update updateSelection to use the IDs returned by
getSelectedActions directly, removing the redundant group expansion loop. Ensure
dragState.value.lastPoint is updated to the current point before returning when
movable is empty, so pointer movement over fully locked selections does not
accumulate stale deltas.
- Around line 625-667: Update toggleSelectedLock, groupSelectedActions, and
ungroupSelectedActions to record their in-place locked/groupId changes as a
dedicated mutate history entry containing the affected actions’ prior state, so
Ctrl+Z restores those values and earlier add undo cannot resurrect stale group
membership. Only append history when a mutation actually occurs, preserving
existing no-op returns. In groupSelectedActions, always assign a fresh group id
instead of reusing any pre-existing selected group id.
In `@src/composables/useDockModeConfig.ts`:
- Around line 8-52: Consolidate the identical overlay and whiteboard entries in
toolsByMode and controlsByMode into shared configuration data, avoiding
duplicate tool lists and control flags that can drift out of sync. Preserve both
DockMode keys and the current behavior, while leaving a clear path for future
per-mode overrides.
In `@src/composables/useFloatingDock.ts`:
- Around line 25-45: Add a window resize listener in the useFloatingDock
lifecycle so it invokes applyPositionForOrientation and refreshes
dockTooltipPlacement after viewport dimensions change. Register the listener on
mount and remove the same handler on unmount, preserving existing drag and
orientation behavior.
In `@src/stores/settings.ts`:
- Around line 277-281: Extract the shared normalizeDashPattern(pattern:
number[]): number[] helper from the inline logic in src/stores/settings.ts lines
277-281, preserving finite/non-negative filtering and rounding. Update
src/stores/settings.ts lines 424-428 to call it, and remove the local helper in
src/components/shared/FloatingDock.vue lines 175-179 so that component imports
and uses the shared implementation.
- Around line 18-23: Check src/types/drawing.ts first and reuse any existing
exported text and arrow-style unions; only define shared exports there if they
are absent. Update Settings, its refs, setter parameters, and guards to consume
those types, then replace duplicate literals in OverlayPayload and
FloatingDock.vue with the same shared definitions so all style values remain
synchronized.
In `@src/types/drawing.ts`:
- Around line 46-51: Define and export shared alias types named TextWeight,
TextStyle, TextDecoration, TextAlign, and ArrowStyle in the drawing types
module, then update the repeated union declarations in the normalizer,
useCanvasDrawing, CanvasStage, and both shells to import and reuse these
aliases.
In `@src/utils/canvas/normalizer.ts`:
- Around line 55-86: Update normalizeDrawAction to accept raw or partial input
and validate/default id, tool, color, and composite alongside the existing
normalized fields, ensuring unknown tool and composite values cannot reach
rendering. Preserve a valid DrawAction shape for untrusted persisted data,
reusing existing normalization conventions where applicable. Only include
text-specific fields and arrowStyle when action.tool supports them so unrelated
actions are not inflated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 5df6802f-733d-4ede-986b-cb9beaf7a008
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (32)
.oxlintrc.jsonLICENSE.mddocs/pages/features/live-draw.mddocs/pages/features/whiteboard.mddocs/pages/reference/settings.mddocs/pages/reference/shortcuts.mdpackage.jsonsrc/App.vuesrc/components/app/AppShell.vuesrc/components/app/panels/HotkeysPanel.vuesrc/components/overlay/OverlayShell.vuesrc/components/shared/CanvasStage.vuesrc/components/shared/FloatingDock.vuesrc/components/whiteboard/WhiteboardShell.vuesrc/composables/useCanvasDrawing.tssrc/composables/useCursorHighlightWindow.tssrc/composables/useDockModeConfig.tssrc/composables/useFloatingDock.tssrc/composables/useLocalShortcuts.tssrc/composables/useOverlayWindow.tssrc/composables/useSpotlightWindow.tssrc/constants/shortcuts-local.tssrc/locales/en.jsonsrc/locales/es.jsonsrc/stores/settings.tssrc/types/drawing.tssrc/types/overlay.tssrc/types/settings.tssrc/types/tools.tssrc/utils/canvas/normalizer.tssrc/utils/canvas/renderer.tstsconfig.json
| "moreOptions": "Mas opciones", | ||
| "strokeDash": "Estilo de linea", | ||
| "lockSelection": "Bloquear/Desbloquear seleccion", | ||
| "toggleGroupSelection": "Agrupar/Desagrupar seleccion", | ||
| "dashOptions": { | ||
| "solid": "Solida", | ||
| "dashed": "Guiones", | ||
| "dotted": "Punteada" | ||
| }, | ||
| "text": { | ||
| "bold": "Negrita", | ||
| "italic": "Cursiva", | ||
| "underline": "Subrayado", | ||
| "alignLeft": "Alinear a la izquierda", | ||
| "alignCenter": "Centrar", | ||
| "alignRight": "Alinear a la derecha" | ||
| }, | ||
| "shapes": { | ||
| "cornerRadius": "Radio de esquina", | ||
| "arrowStyle": "Estilo de flecha", | ||
| "arrowStyles": { | ||
| "simple": "Simple", | ||
| "filled": "Rellena", | ||
| "double": "Doble", | ||
| "thick": "Gruesa", | ||
| "stealth": "Sigilo" |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix missing Spanish accents and terminology in the new labels.
Several user-facing translations are missing diacritics or use awkward terminology, including Mas, linea, seleccion, and Solida. Please correct these before release.
Proposed fix
- "moreOptions": "Mas opciones",
- "strokeDash": "Estilo de linea",
- "lockSelection": "Bloquear/Desbloquear seleccion",
- "toggleGroupSelection": "Agrupar/Desagrupar seleccion",
+ "moreOptions": "Más opciones",
+ "strokeDash": "Estilo de línea",
+ "lockSelection": "Bloquear/desbloquear selección",
+ "toggleGroupSelection": "Agrupar/desagrupar selección",
...
- "solid": "Solida",
- "dashed": "Guiones",
+ "solid": "Sólida",
+ "dashed": "Discontinua",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "moreOptions": "Mas opciones", | |
| "strokeDash": "Estilo de linea", | |
| "lockSelection": "Bloquear/Desbloquear seleccion", | |
| "toggleGroupSelection": "Agrupar/Desagrupar seleccion", | |
| "dashOptions": { | |
| "solid": "Solida", | |
| "dashed": "Guiones", | |
| "dotted": "Punteada" | |
| }, | |
| "text": { | |
| "bold": "Negrita", | |
| "italic": "Cursiva", | |
| "underline": "Subrayado", | |
| "alignLeft": "Alinear a la izquierda", | |
| "alignCenter": "Centrar", | |
| "alignRight": "Alinear a la derecha" | |
| }, | |
| "shapes": { | |
| "cornerRadius": "Radio de esquina", | |
| "arrowStyle": "Estilo de flecha", | |
| "arrowStyles": { | |
| "simple": "Simple", | |
| "filled": "Rellena", | |
| "double": "Doble", | |
| "thick": "Gruesa", | |
| "stealth": "Sigilo" | |
| "moreOptions": "Más opciones", | |
| "strokeDash": "Estilo de línea", | |
| "lockSelection": "Bloquear/desbloquear selección", | |
| "toggleGroupSelection": "Agrupar/desagrupar selección", | |
| "dashOptions": { | |
| "solid": "Sólida", | |
| "dashed": "Discontinua", | |
| "dotted": "Punteada" | |
| }, | |
| "text": { | |
| "bold": "Negrita", | |
| "italic": "Cursiva", | |
| "underline": "Subrayado", | |
| "alignLeft": "Alinear a la izquierda", | |
| "alignCenter": "Centrar", | |
| "alignRight": "Alinear a la derecha" | |
| }, | |
| "shapes": { | |
| "cornerRadius": "Radio de esquina", | |
| "arrowStyle": "Estilo de flecha", | |
| "arrowStyles": { | |
| "simple": "Simple", | |
| "filled": "Rellena", | |
| "double": "Doble", | |
| "thick": "Gruesa", | |
| "stealth": "Sigilo" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/locales/es.json` around lines 16 - 41, Correct the Spanish translations
in the locale entries around moreOptions, strokeDash, lockSelection,
toggleGroupSelection, and dashOptions.solid by adding the appropriate accents
and using natural Spanish terminology, including “Más”, “línea”, “selección”,
and “Sólida”.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation