Replace hand-rolled binding resolution in dropdown-shortcut and
keyboard-shortcut-from-config with calls to dh/shortcut-binding,
removing direct dependency on shortcut-config/all-built-in-keyboard-shortcuts
and state/custom-shortcuts. Remove unused shortcut-config require.
Return focus to trigger button when filter popover closes, matching
the pattern already used by the customize popover.
Add min-width to active keystroke filter button to prevent width
jitter when toggling between label and key-badge states.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract key handler and conflict resolution logic from the ~390-line
customize-shortcut-dialog-inner into testable top-level defn- functions:
- customize-key-handler: key event state machine (~70 lines)
- compute-override-plan: pure conflict resolution for reassign
- compute-reset-plan: pure conflict resolution for reset-to-default
- matches-default-binding?: canonical default-binding comparison
Add persist-user-shortcuts-batch! to core.cljs to atomically persist
multiple binding changes in a single config read-modify-write cycle,
fixing a race condition where sequential persist-user-shortcut! calls
clobbered each other (config-handler/set-config! updates state async
via save-file! promise chain, so the second call reads stale data).
Fix reset-fn! to strip conflicting bindings before restoring defaults,
preventing error notifications from goog.ui.KeyboardShortcutHandler
duplicate key registration. Auto-close the customize popup 300ms after
reset so it doesn't float over a now-empty filtered list.
Clear user overrides (persist nil) when conflict stripping leaves a
binding that matches the action's default, so actions correctly
disappear from the "Custom" filter tab.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the Reassign button (or any focused element inside the feedback
banner) was removed from the DOM during a rec-state transition, browser
focus fell to document.body. The popover's scoped KeyHandler only
receives events that traverse its DOM subtree, so it went deaf to
subsequent keypresses — the user saw row flash animations instead of
conflict detection.
Two fixes:
1. Add a use-effect that re-focuses the popover element whenever
rec-state changes and focus has drifted outside the popover.
2. After refresh! reinstalls global shortcut handlers, re-suppress
them if a scoped key handler is still active (refcount > 0),
preventing the 50ms window where global handlers could intercept
keypresses meant for the popover.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ARIA live regions to feedback banners (role=alert/status)
- Add role=dialog and aria-label to customize popover
- Add aria-pressed to filter pill buttons
- Remove disabled rows from tab order
- Return focus to trigger on popover close
- Add shortcut-badge-in to prefers-reduced-motion
- Remove dead shortcut-conflicts-display component
- Replace js/console.warn with lambdaisland.glogi
- Merge duplicate cond branches in key handler
- Add missing :shortcut-id to left sidebar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
highlight-row! was looking for .shui-shortcut-row but keymap rows use
.shortcut-row, so the row highlight silently failed. Widen the selector
and add a visible background style for keymap rows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When browsing Settings > Keymap, shortcut keypresses now trigger the
visual animation but skip action execution, preventing overlays like
the command palette from opening on top of the settings modal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ui/dropdown-shortcut helper that renders shui shortcut with glow
style inside dropdown menus, accepting config keywords or raw bindings
- Replace all plain-text shortcut hints in context menus (content.cljs,
block.cljs, left_sidebar.cljs) with the new shui-based component
- Add :shortcut-id to render-keyboard-shortcut calls in settings.cljs
and container.cljs so shortcut press animations trigger correctly
- Fix cond-> form corruption in settings.cljs (misplaced closing brace)
- Clean up unused requires (shortcut-utils in block.cljs, shortcut-dh
and shortcut-utils in left_sidebar.cljs)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove preventDefault from bubble-phase blocker so goog.events.KeyHandler
can resolve character keys via keypress — fixes plain letter key recording
- Add handlers-co-active? predicate to distinguish editing-only vs
non-editing-only handler groups, preventing false blocking conflicts
between mutually exclusive runtime contexts
- Restrict cross-handler conflicts to exact key matches only — chord prefix
matches (e.g., mod+c vs mod+c mod+s) live on separate handler instances
- Exclude internal-only :shortcut.handler/misc from conflict detection
- Quote each conflicting shortcut name individually in feedback banners
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The settings article has a fixed CSS width (44rem) for dialog intrinsic
sizing, but when the viewport constrains the dialog, the inner flex
container overflows and gets clipped. CSS percentages resolve against
the declared width, not the rendered width, so a JS solution is needed.
A ResizeObserver on the dialog element measures its actual clientWidth,
subtracts the aside (only in row layout), and sets an explicit max-width
on the shortcut container. Also makes inner elements flexible: removes
flex-shrink-0 and min-width constraints on keystroke buttons, adds
flex-wrap to toolbar and shortcut rows, and adds min-width: 0 to
shortcut badge containers in shui.css.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add :group-global? true to get-conflicts-by-keys call so conflicts
from other global handlers (undo, redo) are detected when recording
- Add canonicalize-binding utility for order-independent binding comparison
- Fix name-with-meta modifier order to produce canonical ctrl+alt+meta+shift
- Fix override-fn! to use canonicalized comparison when removing conflicting
bindings, preventing silent failures from modifier order mismatches
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Flatten nested for-loops in conflicts list into a single binding form
and add missing React key on section elements. Simplify keyname to
single-arity by treating esc as a modifier-like key to always ignore.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract use-scoped-key-handler hook to deduplicate KeyHandler lifecycle
boilerplate between filter and customize popovers
- Add bubble-phase event blocker to prevent modifier combos (Cmd+K, Cmd+C)
from triggering global actions during shortcut recording
- Clamp global-listener-refcount to zero on cleanup for React strict mode
- Log shortcut-press animation errors instead of silently swallowing them
- Remove 5 orphaned i18n keys from old UI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add two-phase dismiss: transient banners fade out via CSS animation
(opacity + height collapse) instead of vanishing instantly
- Introduce render-state derived value so UI elements (placeholder,
remove buttons, toolbar) stay visible during banner dismiss
- Track previous rec-state in a ref for dismiss animation color variant
- Add shortcut-fade-out keyframe with prefers-reduced-motion override
- Rebalance auto-dismiss timings: unify all undo-carrying banners at 6s
(reassigned was dangerously short at 3s, removed/reset too long at 10s),
trim simple success to 2.5s, bump conflict-same to 3.5s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ^{:key} metadata to fragment in shortcut-keymap-x for loop
- Normalize "cmd"/"command" → "meta" and "opt"/"option" → "alt" in
normalize-binding so cmdk shortcut-press! calls match rendered
data-shortcut-binding attributes
- Remove onCloseAutoFocus preventDefault from both popovers so Radix
returns focus to the trigger button on close
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace 24 hardcoded English UI strings with (t :keymap/...) translation
calls and add corresponding keys to en.edn. Thread a :chord-separator
prop through the shui shortcut component so chord sequence "then" text
is translatable without adding i18n awareness to the presentation layer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add chord-sequence-keys component to shui shortcut for multi-step
bindings (e.g. ⌘C then ⌘R) that were previously truncated to just
the first key. Detects nested binding groups and renders each combo
with a "then" separator and proper glow styling.
- Update normalize-binding to handle chord sequences by joining groups
with spaces instead of flattening into a single combo string.
- Cap keystroke recording at 5 keys to prevent app crashes from
excessively long bindings being persisted to localStorage.
- Add try/catch around localStorage shortcut reads for resilience
against corrupt data on startup.
- Fix vertical centering of shortcut badges using display:contents
wrappers and removing padding-top from label-wrap/action-wrap.
- Style Reset button with accent color and underline-on-hover.
- Add white-space:nowrap to button reset block to prevent text wrapping.
- Use gap instead of margin for shortcut-input-binding spacing.
- Minor CSS refinements: search input padding, keystroke border color,
empty state sizing, toolbar action specificity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The inner glow uses white-on-top / black-on-bottom to simulate 3D keycap lighting.
Theme variables would swap these in dark mode, destroying the effect. Row-pressed
highlight still uses theme variable (accent tint, not physical light).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract animate-element!/highlight-row! helpers in shortcut-press! (was 4x duplication)
- Extract matches-keystroke? predicate (was duplicated in count + render)
- Replace <a> tags with <button> for all interactive elements (remove, clear, reset, undo, toggle, refresh)
- Add aria-label to icon-only buttons for screen reader support
- Add button reset CSS for elements changed from <a> to <button>
- Replace hardcoded rgba colors in CSS glow/shadow/row-pressed with theme variables
- Define press-animation-ms constant (was magic number 160)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace boolean *global-listener-setup? with refcount *global-listener-refcount
to prevent concurrent popovers from breaking global shortcut suppression
- Fix unused binding custom? → _custom? in shortcut list
- Fix _state → state in cmdk/core.cljs (was actually used, underscore was wrong)
- Merge redundant let expression in ui.cljs autocomplete
- Remove stale :tiled false prop from cmdk hint
- Add tabIndex, role="button", and Enter/Space keyboard activation to shortcut rows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensure shortcut component and shui shortcut badges work across both
Radix and legacy Logseq color themes by adding proper fallback chains:
- shortcut.css: Add --lx-* → --rx-* fallbacks for gray scale (08-12),
--lx-* → --ls-* → --rx-* for background steps (01-04, 06), use
opacity-based row dimming instead of color-based for theme-agnostic
muting, and use --color-level-6 for icon link color
- shui.css: Add --rx-* fallbacks to bare --lx-* variables on shortcut
key badges (background, border, text color, separator)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move search bar to the left as the primary, widest element (flex-grow)
- Add magnifying glass icon inside search bar matching other search inputs
- Replace static "Total shortcuts 123" with contextual status line
(e.g. "15 shortcuts", "8 custom shortcuts", "No matching shortcuts")
- Reorder toolbar: search first, then fold/refresh/keystroke/filter icons
- Add tooltips to keystroke and category filter icons
- Fix singular/plural grammar in status text
- Make header sticky on scroll with category headers nesting below
- Remove double scrollbar by delegating scroll to settings article
- Style focus ring to match form-select pattern (ring-2 ring-ring)
- Fix vertical centering of search icon and clear button (mt-0, translateY)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move undo notifications from bottom-right shui toasts into the popover's
existing feedback banner system, keeping the user's focus in one place.
Add subtle background colors to success and muted feedback variants for
visual consistency with error and warning banners.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch from items-center to items-start so multi-line rows keep the
label top-aligned instead of vertically centered against wrapped badges.
Add 1px top padding to label-wrap and action-wrap to simulate centering
in single-line rows, plus 2px on status labels (Unset/Custom/Disabled)
for optical balance.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces the old ui/dropdown-based filter with shui/popup-show! (Radix Popover),
matching the V3 shortcut recording popover's architecture. Adds key sequence
accumulation with 400ms debounce, keyboard-driven removal (Backspace/Esc),
shimmer placeholder, and proper Esc isolation so it only closes the filter
popup without dismissing the parent Settings dialog.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace old <code> tag shortcut rendering with proper shui/shortcut key
badges, add flex-wrap layout for multiple bindings, styled status labels
for "Custom:" and "Unset", and filter platform-inactive shortcuts from
the data layer to prevent empty rows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite the shortcut customization UI from a modal dialog to an inline
popover with a state machine (idle → recording → accepted/conflict).
Add cross-context conflict awareness with amber warnings for non-blocking
conflicts across handler groups, while keeping red blocking conflicts for
same-context collisions. Redesign Esc/Backspace semantics for consistency:
Esc always closes, Backspace always removes. Add Radix tooltip on Reassign
button and polish spacing, animations, and feedback banners.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused `interactive?` prop from shortcut component and all call sites
- Trigger `shortcut-press!` animation when shortcuts are invoked
- Update shortcut settings UI to use `shui/shortcut` instead of raw `<code>` elements
- Fix shortcut key min-width (fit-content → 20px) for consistent sizing
- Pass raw-binding through `render-keyboard-shortcut` for data attribute matching
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the single-style shortcut renderer with a new component
supporting combo (simultaneous keys), separate (sequential keys),
and compact (text-only) display styles with auto-detection.
- Add shortcut-press! for triggering key press animations via DOM
- Add CSS for all 3 styles with glow effects and reduced-motion support
- Update CMD+K to use v2 styles and press animations on Enter/Cmd+C
- Add accessibility defaults (interactive?/aria-hidden?) to consumers
- Remove old v1 namespace, consolidate under logseq.shui.shortcut
- Remove unused size/theme/animate-on-press? params from API
* fix(lint): make worker/frontend separation lint work on Windows
* chore: update cljs:electron-watch script to include test flag
* chore: remove dead root dependencies
* chore(deps): converge better-sqlite3 to 12.6.2 across deps packages
* chore(deps): converge fs-extra to ^11.3.0 across package roots
* fix(test): correct parameters for create-if-not-exists function
* chore(deps): converge cljs-bean to 1.9.0 across deps roots
* fix(tests): escape regex in cljs:run-test script
* chore: pin root packageManager to yarn 1.22.22
* chore(build): replace del with fs.rmSync in gulp clean
* chore(build): replace npm-run-all with npm-run-all2
* chore(security): upgrade dompurify and unify sanitizer path
* chore(observability): upgrade web sentry to 8.x
* chore: remove unused react-draggable dependencies
* chore(ci): fix windows release artifact collection
* fix(build): create static dir before gulp clean scans it
* fix: update nbb-logseq dependency to version feat-db-v33
* fix(test): move start-time initialization after clone repo
* fix(deps): update nbb dependencies and adjust test script paths to compatible with windows path delimiter
* chore(deps): remove dead meander dependency
---------
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>