improved a lot of things

This commit is contained in:
SinachPat
2026-04-26 12:31:31 +01:00
parent f9528702c8
commit 7a4c1d3147
30 changed files with 1316 additions and 59 deletions
@@ -1,6 +1,10 @@
'use client';
import { useState, useCallback } from 'react';
import { useCanvas } from '@/store/canvas';
import { LiveArtboard } from './LiveArtboard';
import { SelectionOverlay } from './SelectionOverlay';
import type { FiberNode } from '@originmain/renderer';
interface ArtboardProps {
id: string;
@@ -9,11 +13,19 @@ interface ArtboardProps {
y: number;
width: number;
height: number;
renderUrl?: string;
}
export function Artboard({ id, label, x, y, width, height }: ArtboardProps) {
export function Artboard({ id, label, x, y, width, height, renderUrl }: ArtboardProps) {
const { selectedArtboardId, selectArtboard } = useCanvas();
const selected = selectedArtboardId === id;
const [fiberRoot, setFiberRoot] = useState<FiberNode | undefined>(undefined);
const handleFiberUpdate = useCallback((root: FiberNode) => setFiberRoot(root), []);
const handleComponentSelected = useCallback(
(nodeId: string) => { void nodeId; /* future: highlight in inspector */ },
[]
);
return (
<div
@@ -66,7 +78,26 @@ export function Artboard({ id, label, x, y, width, height }: ArtboardProps) {
)}
{/* Per-artboard content */}
<ArtboardContent id={id} />
{renderUrl ? (
<>
<LiveArtboard
id={id}
src={renderUrl}
width={width}
height={height}
onFiberTreeUpdate={handleFiberUpdate}
onComponentSelected={handleComponentSelected}
/>
<SelectionOverlay
artboardId={id}
{...(fiberRoot !== undefined ? { fiberRoot } : {})}
width={width}
height={height}
/>
</>
) : (
<ArtboardContent id={id} />
)}
</div>
</div>
);
@@ -3,15 +3,10 @@
import { useRef, useEffect, useCallback } from 'react';
import { useViewport } from '@/store/viewport';
import { useCanvas } from '@/store/canvas';
import { useWorkspace } from '@/hooks/useWorkspace';
import { useArtboards } from '@/hooks/useArtboards';
import { Artboard } from './Artboard';
const ARTBOARDS = [
{ id: 'dashboard-card', label: 'DashboardCard', x: 120, y: 100, width: 280, height: 200 },
{ id: 'user-profile', label: 'UserProfile', x: 460, y: 100, width: 200, height: 260 },
{ id: 'nav-sidebar', label: 'NavSidebar', x: 120, y: 360, width: 200, height: 340 },
{ id: 'data-table', label: 'DataTable', x: 380, y: 380, width: 420, height: 280 },
];
export function Canvas() {
const containerRef = useRef<HTMLDivElement>(null);
const panX = useViewport((s) => s.panX);
@@ -19,6 +14,9 @@ export function Canvas() {
const zoom = useViewport((s) => s.zoom);
const { activeTool, selectArtboard } = useCanvas();
const { data: workspace } = useWorkspace();
const { artboards } = useArtboards(workspace?.id);
const isPanning = useRef(false);
const lastPos = useRef({ x: 0, y: 0 });
const spaceDown = useRef(false);
@@ -124,7 +122,7 @@ export function Canvas() {
zIndex: 2,
}}
>
{ARTBOARDS.map((ab) => (
{artboards.map((ab) => (
<Artboard key={ab.id} {...ab} />
))}
</div>
@@ -1,11 +1,33 @@
'use client';
import { useEffect } from 'react';
import { Toolbar } from './Toolbar';
import { ArtboardNavigator } from '../navigator/ArtboardNavigator';
import { Canvas } from '../canvas/Canvas';
import { Inspector } from '../inspector/Inspector';
import { useHistory } from '@/store/history';
import { useCanvas } from '@/store/canvas';
export function AppChrome() {
const selectedArtboardId = useCanvas((s) => s.selectedArtboardId);
useEffect(() => {
function onKeyDown(e: KeyboardEvent) {
if (!(e.metaKey || e.ctrlKey)) return;
if (!selectedArtboardId) return;
if (e.key === 'z' && !e.shiftKey) {
e.preventDefault();
useHistory.getState().undo(selectedArtboardId);
} else if ((e.key === 'z' && e.shiftKey) || e.key === 'y') {
e.preventDefault();
useHistory.getState().redo(selectedArtboardId);
}
}
window.addEventListener('keydown', onKeyDown);
return () => window.removeEventListener('keydown', onKeyDown);
}, [selectedArtboardId]);
return (
<div
style={{
@@ -1,17 +1,12 @@
'use client';
import { useState } from 'react';
import { useFileTree, FileTree, useFileTreeSelection } from '@pierre/trees/react';
import { useFileTree, FileTree } from '@pierre/trees/react';
import { themeToTreeStyles } from '@pierre/trees';
import { SquareRegular } 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' },
];
import { useWorkspace } from '@/hooks/useWorkspace';
import { useArtboards } from '@/hooks/useArtboards';
const FILE_PATHS = [
'src/components/DashboardCard.tsx',
@@ -54,6 +49,8 @@ const treeThemeStyles = themeToTreeStyles({
export function ArtboardNavigator() {
const { selectedArtboardId, selectArtboard } = useCanvas();
const { data: workspace } = useWorkspace();
const { artboards } = useArtboards(workspace?.id);
const { model } = useFileTree({
paths: FILE_PATHS,
@@ -78,7 +75,7 @@ export function ArtboardNavigator() {
{/* ── Artboards ── */}
<SectionLabel>Artboards</SectionLabel>
<div style={{ padding: '2px 6px 0' }}>
{ARTBOARDS.map((ab) => {
{artboards.map((ab) => {
const sel = selectedArtboardId === ab.id;
return (
<NavRow