Files
site-builder/craft/src/App.tsx
T
shadowdaoandClaude Sonnet 5.5 af460f23e6 feat(site-builder): precise drop indicator with target glow and empty-container label
Restyle Craft's insertion bar via the Editor indicator prop and mirror the
live placement onto the DOM (data-drop-target/-error/-empty, is-dragging).

Refs #43

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:38:22 -07:00

76 lines
2.6 KiB
TypeScript

import React from 'react';
import { Editor } from '@craftjs/core';
import { EditorShell } from './editor/EditorShell';
import { RenderNode } from './editor/RenderNode';
import { componentResolver } from './components/resolver';
import { WhpConfig } from './types';
import { EditorConfigProvider } from './state/EditorConfigContext';
import { SiteDesignProvider } from './state/SiteDesignContext';
import { CanvasTokenStyle } from './editor/CanvasTokenStyle';
import { SaveGuardProvider, useSaveGuard } from './state/SaveGuardContext';
import { NoticeProvider } from './state/NoticeContext';
import { ProjectExtrasProvider } from './state/ProjectExtrasContext';
import { CanvasOverlays } from './editor/CanvasOverlays';
import { PageProvider } from './state/PageContext';
import { SitesmithProvider, useSitesmithModal } from './state/SitesmithContext';
import { SitesmithModal } from './panels/sitesmith/SitesmithModal';
interface AppProps {
whpConfig: WhpConfig | null;
}
const SitesmithModalMount: React.FC = () => {
const { isOpen, target, close } = useSitesmithModal();
if (!isOpen) return null;
return <SitesmithModal target={target} onClose={close} />;
};
// Craft fires onNodesChange only when the serialized node tree changes (not on
// selection, hover or DOM registration), which is exactly "the canvas was edited".
export const SaveAwareEditor: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { markDirty } = useSaveGuard();
return (
<Editor
resolver={componentResolver}
enabled={true}
onRender={RenderNode}
onNodesChange={markDirty}
indicator={{
className: 'wsb-drop-line',
thickness: 3,
success: 'var(--color-accent)',
error: 'var(--color-danger)',
transition: '0.08s ease-out',
style: { borderRadius: 2, boxShadow: '0 0 0 1px rgba(0,0,0,.25)' },
}}
>
{children}
</Editor>
);
};
export const App: React.FC<AppProps> = ({ whpConfig }) => {
return (
<EditorConfigProvider config={whpConfig}>
<SaveGuardProvider>
<NoticeProvider>
<ProjectExtrasProvider>
<SiteDesignProvider>
<CanvasTokenStyle />
<SaveAwareEditor>
<PageProvider>
<SitesmithProvider>
<EditorShell />
<CanvasOverlays />
<SitesmithModalMount />
</SitesmithProvider>
</PageProvider>
</SaveAwareEditor>
</SiteDesignProvider>
</ProjectExtrasProvider>
</NoticeProvider>
</SaveGuardProvider>
</EditorConfigProvider>
);
};