Live-pass feedback: the wide "Take a note…" bar showed through behind the
compose modal and felt redundant. Per operator choice, remove the bar and
make capture header-button + keyboard driven.
- Removed the board's inline "Take a note…" trigger bar.
- AppShell gains a "+ New" header button (next to search) — navigates to the
board if needed, then opens the compose modal. The `c` shortcut now does
the same (unified with newNote()).
- Type-to-compose: on the board with no card focused, any other single
printable key opens a new note SEEDED with that key (AppShell onKeydown
fall-through, after the reserved / c ? g shortcuts). Seed travels via
ui.composeSeed → NoteEditor's new `initialBody` prop; caret placed at end.
- Two-mode board keyboard (BoardView): RESTING = arrows enter browse, letters
type-to-compose; BROWSING (a card focused) = j/k move, e/x/# act, Enter
opens, Esc exits to resting. ui.boardCardFocused tells the global handler
to stand down while browsing so it doesn't swallow card keys.
- Updated the shortcuts help + the empty-state copy ("Hit + New — or just
start typing").
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
67 lines
1.7 KiB
TypeScript
67 lines
1.7 KiB
TypeScript
import { defineStore } from "pinia";
|
|
import { ref } from "vue";
|
|
|
|
interface ToastAction {
|
|
label: string;
|
|
run: () => void;
|
|
}
|
|
|
|
interface Toast {
|
|
id: number;
|
|
message: string;
|
|
action?: ToastAction;
|
|
}
|
|
|
|
// Cross-component UI signals that don't belong to any single view (e.g. a
|
|
// global shortcut in the app shell asking the board to act).
|
|
export const useUiStore = defineStore("ui", () => {
|
|
// Bumped to ask the board to open the compose modal; composeSeed is the initial
|
|
// body (a single char for type-to-compose, or "" for the + button / `c`).
|
|
const composeTick = ref(0);
|
|
const composeSeed = ref("");
|
|
function requestCompose(seed = "") {
|
|
composeSeed.value = seed;
|
|
composeTick.value++;
|
|
}
|
|
// The board publishes whether a card is keyboard-focused (browse mode), so the
|
|
// global handler knows NOT to type-to-compose while browsing cards.
|
|
const boardCardFocused = ref(false);
|
|
|
|
// Transient undo toast (e.g. after trash/archive).
|
|
const toast = ref<Toast | null>(null);
|
|
let toastTimer: ReturnType<typeof setTimeout> | undefined;
|
|
let toastSeq = 0;
|
|
|
|
function showToast(message: string, action?: ToastAction) {
|
|
toastSeq += 1;
|
|
const id = toastSeq;
|
|
toast.value = { id, message, action };
|
|
clearTimeout(toastTimer);
|
|
toastTimer = setTimeout(() => {
|
|
if (toast.value?.id === id) toast.value = null;
|
|
}, 5000);
|
|
}
|
|
|
|
function dismissToast() {
|
|
clearTimeout(toastTimer);
|
|
toast.value = null;
|
|
}
|
|
|
|
function runToastAction() {
|
|
const run = toast.value?.action?.run;
|
|
dismissToast();
|
|
run?.();
|
|
}
|
|
|
|
return {
|
|
composeTick,
|
|
composeSeed,
|
|
requestCompose,
|
|
boardCardFocused,
|
|
toast,
|
|
showToast,
|
|
dismissToast,
|
|
runToastAction,
|
|
};
|
|
});
|