feat(builder): items 10+12+13 — scope canvas guides, Show Guides toggle, Layers panel hover/icons, topbar unification
Item 10: dashed canvas "guide" outlines were applied via blanket tag
selectors (div/section/header/...), so a finished section showed 3-4
nested dashed boxes. RenderNode.tsx (the <Editor onRender> override) now
tags each Craft.js droppable container's real DOM node with a
`data-craft-node` attribute (node.data.isCanvas, excluding ROOT), and
editor.css's guide rules target that attribute instead — a component's own
internal wrapper markup is no longer mistaken for a drop target. Added a
"Show guides" topbar toggle (default ON, persisted to localStorage),
state lifted in EditorShell.tsx (mirrors how `device` is already lifted),
flips `.guides-off` on Canvas.tsx's `.canvas-device-frame`.
Item 12: Layers panel rows get per-type FA icons (keyed off the same
craft.displayName used for the row label, seeded from BlocksPanel's
choices), indent-guide lines connecting nested rows, and row hover
highlights the matching canvas element (`data-layer-hovered`, written
directly to the node's DOM via `query.node(id).get().dom` — NOT via
`actions.setNodeEvent`, which is stripped from useEditor()'s public
`actions` at runtime, not just in its TS type, and threw when called).
Along the way, Craft.js's own connect() was found to already wire mouse
hover to the same `hovered` node event internally (previously invisible
because the matching CSS was dead) — RenderNode now also mirrors that
onto `data-craft-hovered` for a real-mouse-hover canvas highlight, and
both hover attributes plus the guide attribute are suppressed under
`.guides-off` so the toggle stays airtight.
Item 13: unified the topbar to one button radius (`.topbar-btn` 20px pill
-> var(--radius-md)), demoted Code/Preview to icon-only with
`data-tooltip`. Fixed a latent bug the new tooltips exposed: `[data-tooltip]`
tooltips render above their trigger, but the topbar has no room above it
(`body { overflow: hidden }`) — added a `.topbar` override to render
those below instead.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,8 +9,34 @@ import { useContextMenu } from '../hooks/useContextMenu';
|
||||
import { useKeyboardShortcuts } from '../hooks/useKeyboardShortcuts';
|
||||
import { DeviceMode } from '../types';
|
||||
|
||||
const SHOW_GUIDES_STORAGE_KEY = 'craft-show-guides';
|
||||
|
||||
function loadShowGuides(): boolean {
|
||||
try {
|
||||
const stored = window.localStorage.getItem(SHOW_GUIDES_STORAGE_KEY);
|
||||
return stored === null ? true : stored === '1';
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export const EditorShell: React.FC = () => {
|
||||
const [device, setDevice] = useState<DeviceMode>('desktop');
|
||||
// Item 10: canvas dashed "guide" outlines toggle -- default ON, persisted
|
||||
// so the choice survives a reload. Lifted here (rather than owned by
|
||||
// TopBar or Canvas alone) because the toggle button lives in TopBar but
|
||||
// the `.guides-off` class it drives is applied to Canvas's
|
||||
// `.canvas-device-frame`, mirroring how `device` is already lifted for
|
||||
// the same reason.
|
||||
const [showGuides, setShowGuidesState] = useState<boolean>(loadShowGuides);
|
||||
const setShowGuides = useCallback((next: boolean) => {
|
||||
setShowGuidesState(next);
|
||||
try {
|
||||
window.localStorage.setItem(SHOW_GUIDES_STORAGE_KEY, next ? '1' : '0');
|
||||
} catch {
|
||||
// Storage unavailable (private browsing, etc.) -- in-memory state still works.
|
||||
}
|
||||
}, []);
|
||||
const { menuState, show: showMenu, hide: hideMenu } = useContextMenu();
|
||||
const { query } = useEditor();
|
||||
|
||||
@@ -34,11 +60,16 @@ export const EditorShell: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="editor-app">
|
||||
<TopBar device={device} onDeviceChange={setDevice} />
|
||||
<TopBar
|
||||
device={device}
|
||||
onDeviceChange={setDevice}
|
||||
showGuides={showGuides}
|
||||
onToggleGuides={() => setShowGuides(!showGuides)}
|
||||
/>
|
||||
<div className="editor-container">
|
||||
<LeftPanel />
|
||||
<div onContextMenu={handleContextMenu} style={{ flex: 1, display: 'flex', minWidth: 0 }}>
|
||||
<Canvas device={device} />
|
||||
<Canvas device={device} showGuides={showGuides} />
|
||||
</div>
|
||||
<RightPanel />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user