made system changes
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
'use client';
|
||||
|
||||
import { useCanvas } from '@/store/canvas';
|
||||
|
||||
interface ArtboardProps {
|
||||
id: string;
|
||||
label: string;
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export function Artboard({ id, label, x, y, width, height }: ArtboardProps) {
|
||||
const { selectedArtboardId, selectArtboard } = useCanvas();
|
||||
const selected = selectedArtboardId === id;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ position: 'absolute', top: y, left: x }}
|
||||
onClick={(e) => { e.stopPropagation(); selectArtboard(id); }}
|
||||
>
|
||||
{/* Label above artboard */}
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: -22,
|
||||
left: 0,
|
||||
fontSize: 11,
|
||||
fontFamily: 'monospace',
|
||||
color: selected ? '#0F52BA' : 'rgba(255,255,255,0.4)',
|
||||
userSelect: 'none',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
|
||||
{/* Artboard frame */}
|
||||
<div
|
||||
style={{
|
||||
width,
|
||||
height,
|
||||
background: '#fff',
|
||||
borderRadius: 8,
|
||||
boxShadow: selected
|
||||
? '0 0 0 2px #0F52BA, 0 8px 40px rgba(0,0,0,0.5)'
|
||||
: '0 4px 24px rgba(0,0,0,0.4)',
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
cursor: 'default',
|
||||
}}
|
||||
>
|
||||
{/* Selection handles */}
|
||||
{selected && (
|
||||
<>
|
||||
<Handle pos={{ top: -3, left: -3 }} />
|
||||
<Handle pos={{ top: -3, right: -3 }} />
|
||||
<Handle pos={{ bottom: -3, left: -3 }} />
|
||||
<Handle pos={{ bottom: -3, right: -3 }} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Placeholder content */}
|
||||
<div style={{ padding: 20 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 14 }}>
|
||||
<div style={{ fontSize: 11, fontWeight: 600, color: '#111', letterSpacing: '-0.01em' }}>
|
||||
Revenue Overview
|
||||
</div>
|
||||
<div style={{ fontSize: 9, background: '#ecfdf5', color: '#059669', padding: '2px 6px', borderRadius: 99, fontWeight: 600, fontFamily: 'monospace' }}>
|
||||
Live
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 22, fontWeight: 800, color: '#0c0c10', letterSpacing: '-0.04em', lineHeight: 1, marginBottom: 5 }}>
|
||||
$12,450
|
||||
</div>
|
||||
<div style={{ fontSize: 10, color: '#16a34a', fontWeight: 500, marginBottom: 12 }}>
|
||||
↑ +2.4% vs last month
|
||||
</div>
|
||||
<div style={{ height: 3, background: '#f0f0f0', borderRadius: 99, overflow: 'hidden', marginBottom: 12 }}>
|
||||
<div style={{ height: '100%', width: '68%', background: 'linear-gradient(90deg,#0F52BA,#4d84e0)', borderRadius: 99 }} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
<Chip>Q4 2024</Chip>
|
||||
<Chip>MRR</Chip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Handle({ pos }: { pos: React.CSSProperties }) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
width: 7,
|
||||
height: 7,
|
||||
background: '#fff',
|
||||
border: '2px solid #0F52BA',
|
||||
borderRadius: 2,
|
||||
zIndex: 10,
|
||||
...pos,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Chip({ children }: { children: string }) {
|
||||
return (
|
||||
<span style={{ fontSize: 9, background: '#f5f5f5', color: '#666', padding: '3px 7px', borderRadius: 99 }}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
'use client';
|
||||
|
||||
import { useRef, useEffect, useCallback } from 'react';
|
||||
import { useViewport } from '@/store/viewport';
|
||||
import { useCanvas } from '@/store/canvas';
|
||||
import { Artboard } from './Artboard';
|
||||
|
||||
const ARTBOARDS = [
|
||||
{ id: 'dashboard-card', label: 'DashboardCard', x: 120, y: 120, width: 280, height: 200 },
|
||||
{ id: 'user-profile', label: 'UserProfile', x: 480, y: 120, width: 240, height: 280 },
|
||||
{ id: 'nav-sidebar', label: 'NavSidebar', x: 120, y: 400, width: 200, height: 360 },
|
||||
{ id: 'data-table', label: 'DataTable', x: 400, y: 420, width: 420, height: 300 },
|
||||
];
|
||||
|
||||
export function Canvas() {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const panX = useViewport((s) => s.panX);
|
||||
const panY = useViewport((s) => s.panY);
|
||||
const zoom = useViewport((s) => s.zoom);
|
||||
const { activeTool, selectArtboard } = useCanvas();
|
||||
|
||||
const isPanning = useRef(false);
|
||||
const lastPos = useRef({ x: 0, y: 0 });
|
||||
const spaceDown = useRef(false);
|
||||
|
||||
// Wheel: pan or zoom
|
||||
useEffect(() => {
|
||||
const el = containerRef.current;
|
||||
if (!el) return;
|
||||
const onWheel = (e: WheelEvent) => {
|
||||
e.preventDefault();
|
||||
const { zoom, panX, panY, setPan, setZoom } = useViewport.getState();
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
const ox = e.clientX - rect.left;
|
||||
const oy = e.clientY - rect.top;
|
||||
setZoom(zoom * (e.deltaY > 0 ? 0.92 : 1.09), ox, oy);
|
||||
} else {
|
||||
setPan(panX - e.deltaX, panY - e.deltaY);
|
||||
}
|
||||
};
|
||||
el.addEventListener('wheel', onWheel, { passive: false });
|
||||
return () => el.removeEventListener('wheel', onWheel);
|
||||
}, []);
|
||||
|
||||
// Space key: temporary pan mode
|
||||
useEffect(() => {
|
||||
const down = (e: KeyboardEvent) => { if (e.code === 'Space' && e.target === document.body) spaceDown.current = true; };
|
||||
const up = (e: KeyboardEvent) => { if (e.code === 'Space') spaceDown.current = false; };
|
||||
window.addEventListener('keydown', down);
|
||||
window.addEventListener('keyup', up);
|
||||
return () => { window.removeEventListener('keydown', down); window.removeEventListener('keyup', up); };
|
||||
}, []);
|
||||
|
||||
const onMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
const startPan = e.button === 1 || spaceDown.current || activeTool === 'pan';
|
||||
if (startPan) {
|
||||
e.preventDefault();
|
||||
isPanning.current = true;
|
||||
lastPos.current = { x: e.clientX, y: e.clientY };
|
||||
} else if (e.target === e.currentTarget) {
|
||||
selectArtboard(null);
|
||||
}
|
||||
}, [activeTool, selectArtboard]);
|
||||
|
||||
const onMouseMove = useCallback((e: React.MouseEvent) => {
|
||||
if (!isPanning.current) return;
|
||||
const dx = e.clientX - lastPos.current.x;
|
||||
const dy = e.clientY - lastPos.current.y;
|
||||
lastPos.current = { x: e.clientX, y: e.clientY };
|
||||
const { panX, panY, setPan } = useViewport.getState();
|
||||
setPan(panX + dx, panY + dy);
|
||||
}, []);
|
||||
|
||||
const onMouseUp = useCallback(() => { isPanning.current = false; }, []);
|
||||
|
||||
const gridSize = Math.max(8, 22 * zoom);
|
||||
const cursor = activeTool === 'pan' || isPanning.current ? 'grab' : 'default';
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
style={{ gridColumn: 2, gridRow: 2, position: 'relative', overflow: 'hidden', background: '#111115', cursor }}
|
||||
onMouseDown={onMouseDown}
|
||||
onMouseMove={onMouseMove}
|
||||
onMouseUp={onMouseUp}
|
||||
>
|
||||
{/* Dot grid — shifts with pan, scales with zoom */}
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
backgroundImage: 'radial-gradient(circle, rgba(255,255,255,0.07) 1px, transparent 1px)',
|
||||
backgroundSize: `${gridSize}px ${gridSize}px`,
|
||||
backgroundPosition: `${panX % gridSize}px ${panY % gridSize}px`,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Transform layer */}
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
transform: `matrix(${zoom},0,0,${zoom},${panX},${panY})`,
|
||||
transformOrigin: '0 0',
|
||||
}}
|
||||
>
|
||||
{ARTBOARDS.map((ab) => (
|
||||
<Artboard key={ab.id} {...ab} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
'use client';
|
||||
|
||||
import { Toolbar } from './Toolbar';
|
||||
import { ArtboardNavigator } from '../navigator/ArtboardNavigator';
|
||||
import { Canvas } from '../canvas/Canvas';
|
||||
import { Inspector } from '../inspector/Inspector';
|
||||
|
||||
export function AppChrome() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateRows: '40px 1fr',
|
||||
gridTemplateColumns: '240px 1fr 320px',
|
||||
height: '100dvh',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<Toolbar />
|
||||
<ArtboardNavigator />
|
||||
<Canvas />
|
||||
<Inspector />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
ToolbarButton,
|
||||
ToolbarDivider,
|
||||
Tooltip,
|
||||
Badge,
|
||||
} from '@fluentui/react-components';
|
||||
import {
|
||||
CursorClickRegular,
|
||||
HandLeftRegular,
|
||||
SquareRegular,
|
||||
SelectObjectRegular,
|
||||
DataTrendingRegular,
|
||||
CircleHintHalfVerticalRegular,
|
||||
ZoomInRegular,
|
||||
ZoomOutRegular,
|
||||
} from '@fluentui/react-icons';
|
||||
import { useCanvas, type Tool } from '@/store/canvas';
|
||||
import { useViewport } from '@/store/viewport';
|
||||
|
||||
export function Toolbar() {
|
||||
const { activeTool, setActiveTool } = useCanvas();
|
||||
const zoom = useViewport((s) => s.zoom);
|
||||
const setZoom = useViewport((s) => s.setZoom);
|
||||
const reset = useViewport((s) => s.reset);
|
||||
|
||||
const ap = (id: Tool): 'primary' | 'subtle' => activeTool === id ? 'primary' : 'subtle';
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
gridColumn: '1 / -1',
|
||||
gridRow: 1,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
borderBottom: '1px solid rgba(0,0,0,0.08)',
|
||||
background: '#fff',
|
||||
paddingInline: 8,
|
||||
gap: 2,
|
||||
height: 40,
|
||||
}}
|
||||
>
|
||||
{/* Wordmark */}
|
||||
<span
|
||||
style={{
|
||||
fontFamily: 'system-ui, sans-serif',
|
||||
fontWeight: 800,
|
||||
fontSize: '0.9375rem',
|
||||
color: '#0F52BA',
|
||||
letterSpacing: '-0.04em',
|
||||
padding: '0 8px',
|
||||
marginRight: 4,
|
||||
userSelect: 'none',
|
||||
}}
|
||||
>
|
||||
Om
|
||||
</span>
|
||||
|
||||
<ToolbarDivider />
|
||||
|
||||
{/* Select */}
|
||||
<Tooltip content="Select V" relationship="label">
|
||||
<ToolbarButton appearance={ap('select')} icon={<CursorClickRegular />} onClick={() => setActiveTool('select')} />
|
||||
</Tooltip>
|
||||
{/* Pan */}
|
||||
<Tooltip content="Pan H" relationship="label">
|
||||
<ToolbarButton appearance={ap('pan')} icon={<HandLeftRegular />} onClick={() => setActiveTool('pan')} />
|
||||
</Tooltip>
|
||||
{/* Artboard */}
|
||||
<Tooltip content="New Artboard A" relationship="label">
|
||||
<ToolbarButton appearance={ap('artboard')} icon={<SquareRegular />} onClick={() => setActiveTool('artboard')} />
|
||||
</Tooltip>
|
||||
{/* Zone */}
|
||||
<Tooltip content="Completion Zone Z" relationship="label">
|
||||
<ToolbarButton appearance={ap('zone')} icon={<SelectObjectRegular />} onClick={() => setActiveTool('zone')} />
|
||||
</Tooltip>
|
||||
|
||||
<ToolbarDivider />
|
||||
|
||||
{/* View tools */}
|
||||
<Tooltip content="Intent Diff" relationship="label">
|
||||
<ToolbarButton appearance="subtle" icon={<DataTrendingRegular />} />
|
||||
</Tooltip>
|
||||
<Tooltip content="Origin Graph" relationship="label">
|
||||
<ToolbarButton appearance="subtle" icon={<CircleHintHalfVerticalRegular />} />
|
||||
</Tooltip>
|
||||
|
||||
{/* Right — zoom + live status */}
|
||||
<div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 4, paddingInline: 4 }}>
|
||||
<Tooltip content="Zoom out" relationship="label">
|
||||
<ToolbarButton appearance="subtle" icon={<ZoomOutRegular />} onClick={() => setZoom(zoom * 0.8)} />
|
||||
</Tooltip>
|
||||
<button
|
||||
onClick={reset}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: '1px solid rgba(0,0,0,0.1)',
|
||||
borderRadius: 4,
|
||||
padding: '2px 8px',
|
||||
fontSize: '0.6875rem',
|
||||
fontFamily: 'monospace',
|
||||
color: 'rgba(0,0,0,0.5)',
|
||||
cursor: 'pointer',
|
||||
minWidth: 46,
|
||||
}}
|
||||
>
|
||||
{Math.round(zoom * 100)}%
|
||||
</button>
|
||||
<Tooltip content="Zoom in" relationship="label">
|
||||
<ToolbarButton appearance="subtle" icon={<ZoomInRegular />} onClick={() => setZoom(zoom * 1.25)} />
|
||||
</Tooltip>
|
||||
|
||||
<ToolbarDivider />
|
||||
|
||||
<Badge color="success" size="extra-small" />
|
||||
<span style={{ fontSize: '0.6875rem', fontFamily: 'monospace', color: 'rgba(0,0,0,0.4)', paddingRight: 4 }}>
|
||||
Live
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
'use client';
|
||||
|
||||
import { TabList, Tab, Divider } from '@fluentui/react-components';
|
||||
import { useCanvas } from '@/store/canvas';
|
||||
|
||||
const PROPS = [
|
||||
{ key: 'title', val: '"Revenue Overview"', type: 's' },
|
||||
{ key: 'value', val: '"$12,450"', type: 's' },
|
||||
{ key: 'delta', val: '+2.4', type: 'n' },
|
||||
{ key: 'period', val: '"monthly"', type: 's' },
|
||||
{ key: 'loading', val: 'false', type: 'b' },
|
||||
];
|
||||
|
||||
const DIFF = [
|
||||
{ op: 'del', text: '− borderRadius: 8px' },
|
||||
{ op: 'add', text: '+ borderRadius: 12px' },
|
||||
{ op: 'del', text: '− accentColor: #2A6CD4' },
|
||||
{ op: 'add', text: '+ accentColor: #0F52BA' },
|
||||
];
|
||||
|
||||
const TYPE_COLORS: Record<string, string> = {
|
||||
s: '#16a34a',
|
||||
n: '#2563eb',
|
||||
b: '#d97706',
|
||||
};
|
||||
|
||||
export function Inspector() {
|
||||
const { selectedArtboardId } = useCanvas();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
gridColumn: 3,
|
||||
gridRow: 2,
|
||||
background: '#fafafa',
|
||||
borderLeft: '1px solid rgba(0,0,0,0.08)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden',
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
<TabList defaultSelectedValue="props" size="small" style={{ padding: '0 8px', borderBottom: '1px solid rgba(0,0,0,0.08)' }}>
|
||||
<Tab value="props">Props</Tab>
|
||||
<Tab value="diff">Diff</Tab>
|
||||
<Tab value="graph">Graph</Tab>
|
||||
</TabList>
|
||||
|
||||
{selectedArtboardId ? (
|
||||
<>
|
||||
<Section label="Component Props">
|
||||
{PROPS.map(({ key, val, type }) => (
|
||||
<PropRow key={key} label={key} value={val} color={TYPE_COLORS[type] ?? '#555'} />
|
||||
))}
|
||||
</Section>
|
||||
|
||||
<Divider style={{ margin: 0 }} />
|
||||
|
||||
<Section label="Intent Diff">
|
||||
{DIFF.map((d, i) => (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 11,
|
||||
padding: '3px 8px',
|
||||
borderRadius: 3,
|
||||
marginBottom: 3,
|
||||
background: d.op === 'del' ? 'rgba(239,68,68,0.08)' : 'rgba(34,197,94,0.08)',
|
||||
color: d.op === 'del' ? '#dc2626' : '#16a34a',
|
||||
}}
|
||||
>
|
||||
{d.text}
|
||||
</div>
|
||||
))}
|
||||
</Section>
|
||||
|
||||
<Divider style={{ margin: 0 }} />
|
||||
|
||||
<Section label="Render Target">
|
||||
<PropRow label="file" value="dashboard.tsx:42" color="#2563eb" />
|
||||
<PropRow label="status" value="connected" color="#16a34a" />
|
||||
<PropRow label="agent" value="claude-code" color="#16a34a" />
|
||||
</Section>
|
||||
</>
|
||||
) : (
|
||||
<div style={{ padding: 24, color: 'rgba(0,0,0,0.3)', fontSize: 12, fontFamily: 'monospace', textAlign: 'center' }}>
|
||||
Select an artboard
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Section({ label, children }: { label: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<div style={{ padding: '10px 12px' }}>
|
||||
<div style={{ fontFamily: 'monospace', fontSize: 9, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'rgba(0,0,0,0.3)', marginBottom: 8 }}>
|
||||
{label}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PropRow({ label, value, color }: { label: string; value: string; color: string }) {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
|
||||
<span style={{ fontFamily: 'monospace', fontSize: 11, color: 'rgba(0,0,0,0.4)' }}>{label}</span>
|
||||
<span style={{ fontFamily: 'monospace', fontSize: 11, color }}>{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Tree,
|
||||
TreeItem,
|
||||
TreeItemLayout,
|
||||
Text,
|
||||
} from '@fluentui/react-components';
|
||||
import {
|
||||
SquareRegular,
|
||||
DocumentRegular,
|
||||
FolderRegular,
|
||||
FolderOpenRegular,
|
||||
} from '@fluentui/react-icons';
|
||||
import { useCanvas } from '@/store/canvas';
|
||||
|
||||
const ARTBOARDS = [
|
||||
{ id: 'dashboard-card', label: 'DashboardCard' },
|
||||
{ id: 'user-profile', label: 'UserProfile' },
|
||||
{ id: 'nav-sidebar', label: 'NavSidebar' },
|
||||
{ id: 'data-table', label: 'DataTable' },
|
||||
];
|
||||
|
||||
export function ArtboardNavigator() {
|
||||
const { selectedArtboardId, selectArtboard } = useCanvas();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
gridColumn: 1,
|
||||
gridRow: 2,
|
||||
background: '#fafafa',
|
||||
borderRight: '1px solid rgba(0,0,0,0.08)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{/* Artboards section */}
|
||||
<SectionLabel>Artboards</SectionLabel>
|
||||
<Tree aria-label="Artboards" size="small" style={{ padding: '0 4px' }}>
|
||||
{ARTBOARDS.map((ab) => (
|
||||
<TreeItem
|
||||
key={ab.id}
|
||||
itemType="leaf"
|
||||
value={ab.id}
|
||||
style={{
|
||||
background: selectedArtboardId === ab.id ? 'rgba(15,82,186,0.08)' : undefined,
|
||||
borderRadius: 4,
|
||||
}}
|
||||
onClick={() => selectArtboard(ab.id)}
|
||||
>
|
||||
<TreeItemLayout iconBefore={<SquareRegular style={{ color: '#0F52BA', fontSize: 12 }} />}>
|
||||
<Text size={200}>{ab.label}</Text>
|
||||
</TreeItemLayout>
|
||||
</TreeItem>
|
||||
))}
|
||||
</Tree>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Codebase section */}
|
||||
<SectionLabel>Files</SectionLabel>
|
||||
<Tree aria-label="Codebase" size="small" style={{ padding: '0 4px' }}>
|
||||
<TreeItem itemType="branch" value="src">
|
||||
<TreeItemLayout iconBefore={<FolderOpenRegular style={{ fontSize: 12 }} />}>
|
||||
<Text size={200}>src</Text>
|
||||
</TreeItemLayout>
|
||||
<Tree>
|
||||
<TreeItem itemType="branch" value="components">
|
||||
<TreeItemLayout iconBefore={<FolderRegular style={{ fontSize: 12 }} />}>
|
||||
<Text size={200}>components</Text>
|
||||
</TreeItemLayout>
|
||||
<Tree>
|
||||
{ARTBOARDS.map((ab) => (
|
||||
<TreeItem key={ab.id} itemType="leaf" value={`file-${ab.id}`}>
|
||||
<TreeItemLayout iconBefore={<DocumentRegular style={{ fontSize: 12 }} />}>
|
||||
<Text size={200} style={{ color: 'rgba(0,0,0,0.55)' }}>
|
||||
{ab.label}.tsx
|
||||
</Text>
|
||||
</TreeItemLayout>
|
||||
</TreeItem>
|
||||
))}
|
||||
</Tree>
|
||||
</TreeItem>
|
||||
<TreeItem itemType="leaf" value="app-page">
|
||||
<TreeItemLayout iconBefore={<DocumentRegular style={{ fontSize: 12 }} />}>
|
||||
<Text size={200} style={{ color: 'rgba(0,0,0,0.55)' }}>page.tsx</Text>
|
||||
</TreeItemLayout>
|
||||
</TreeItem>
|
||||
</Tree>
|
||||
</TreeItem>
|
||||
</Tree>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SectionLabel({ children }: { children: string }) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
padding: '10px 12px 4px',
|
||||
fontSize: '0.625rem',
|
||||
fontFamily: 'monospace',
|
||||
letterSpacing: '0.1em',
|
||||
textTransform: 'uppercase',
|
||||
color: 'rgba(0,0,0,0.35)',
|
||||
userSelect: 'none',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Divider() {
|
||||
return <div style={{ height: 1, background: 'rgba(0,0,0,0.06)', margin: '6px 0' }} />;
|
||||
}
|
||||
Reference in New Issue
Block a user