T8/Phase 6: OSS component swap polish

- Calendar: react-big-calendar w/ withDragAndDrop, date-fns localizer, custom event renderer (color tokens), custom toolbar, responsive (agenda on mobile), now indicator
- Graph: react-force-graph-2d w/ custom node/link canvas renderers, hover highlighting, search-to-fly, filter panel (entity + relationship types), ResizeObserver, 500-node cap, zoom controls
- Command palette: cmdk polish (recent items, @mention filter, settings/logout actions, mobile full-screen)
- Shortcuts: @github/hotkey for g+letter nav, n+letter create, ?, /, c; Cmd+K for palette
- README.md added with architecture, page list, shortcuts, dev guide
- Bundle: 369 KB gzipped (under 1.5 MB budget)
This commit is contained in:
Hermes
2026-08-01 02:34:37 +00:00
parent c18d7e9abe
commit ef163a9d6f
6 changed files with 745 additions and 221 deletions
+76 -51
View File
@@ -1,17 +1,69 @@
import { useEffect } from "react";
import { useEffect, useRef } from "react";
import { useNavigate } from "@tanstack/react-router";
import { useKeyboardShortcutsStore } from "@/lib/stores/use-keyboard-shortcuts-store";
import { install, uninstall } from "@github/hotkey";
export function useKeyboardShortcuts() {
const navigate = useNavigate();
const { enabled } = useKeyboardShortcutsStore();
const containerRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (!enabled) return;
let pendingKey = "";
let pendingTimeout: ReturnType<typeof setTimeout>;
// Create a hidden container for @github/hotkey installs
const container = document.createElement("div");
container.setAttribute("aria-hidden", "true");
container.style.display = "none";
document.body.appendChild(container);
containerRef.current = container;
// Helper: install a hotkey on a synthetic element
const addHotkey = (hotkey: string, handler: () => void) => {
const el = document.createElement("span");
el.setAttribute("data-hotkey", hotkey);
el.addEventListener("hotkey-fire", (e: Event) => {
e.preventDefault();
handler();
});
container.appendChild(el);
install(el, hotkey);
return el;
};
// g+letter navigation sequences
const navMap: Record<string, string> = {
"g d": "/",
"g t": "/tasks",
"g h": "/habits",
"g p": "/projects",
"g n": "/notes",
"g c": "/calendar",
"g g": "/graph",
"g s": "/settings",
};
for (const [seq, path] of Object.entries(navMap)) {
addHotkey(seq, () => {
navigate({ to: path });
});
}
// n+letter new-entity sequences
const newMap: Record<string, string> = {
"n t": "/tasks",
"n h": "/habits",
"n p": "/projects",
"n n": "/notes",
};
for (const [seq, path] of Object.entries(newMap)) {
addHotkey(seq, () => {
navigate({ to: path });
});
}
// Global keydown handler for single-key shortcuts and Cmd+K
const handleKeyDown = (e: KeyboardEvent) => {
// Never override native behavior inside controls or modal UI
const target = e.target as HTMLElement;
@@ -19,7 +71,6 @@ export function useKeyboardShortcuts() {
target.tagName === "INPUT" ||
target.tagName === "TEXTAREA" ||
target.tagName === "SELECT" ||
target.tagName === "BUTTON" ||
target.isContentEditable ||
target.closest('[role="dialog"], [role="menu"], [role="listbox"], [role="combobox"]')
) {
@@ -33,61 +84,35 @@ export function useKeyboardShortcuts() {
return;
}
// ? — show shortcuts help
if (e.key === "?" && !e.metaKey && !e.ctrlKey && !e.altKey) {
e.preventDefault();
document.dispatchEvent(new CustomEvent("open-shortcuts-help"));
return;
}
// / — focus search (when not in an input)
if (e.key === "/" && !e.metaKey && !e.ctrlKey && !e.altKey) {
e.preventDefault();
document.dispatchEvent(new CustomEvent("open-command-palette"));
return;
}
// Ignore if modifier keys are pressed
// Single-key shortcuts (no modifiers)
if (e.metaKey || e.ctrlKey || e.altKey) return;
const key = e.key.toLowerCase();
// Handle two-key combos (G then letter)
if (pendingKey) {
clearTimeout(pendingTimeout);
pendingKey = "";
const navMap: Record<string, string> = {
d: "/",
t: "/tasks",
h: "/habits",
p: "/projects",
n: "/notes",
c: "/calendar",
g: "/graph",
s: "/settings",
};
if (navMap[key]) {
switch (e.key) {
case "?":
e.preventDefault();
navigate({ to: navMap[key] });
}
return;
}
// Single key shortcuts
switch (key) {
case "g":
pendingKey = "g";
pendingTimeout = setTimeout(() => {
pendingKey = "";
}, 1000);
document.dispatchEvent(new CustomEvent("open-shortcuts-help"));
break;
case "/":
e.preventDefault();
document.dispatchEvent(new CustomEvent("open-command-palette"));
break;
case "c":
e.preventDefault();
document.dispatchEvent(new CustomEvent("open-command-palette"));
break;
}
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
// Cleanup
return () => {
document.removeEventListener("keydown", handleKeyDown);
for (const child of container.children) {
uninstall(child as HTMLElement);
}
document.body.removeChild(container);
containerRef.current = null;
};
}, [navigate, enabled]);
}