diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts index c4b7818..9edff1c 100644 --- a/apps/web/next-env.d.ts +++ b/apps/web/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/dev/types/routes.d.ts"; +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/web/src/components/app-shell/code-panel.tsx b/apps/web/src/components/app-shell/code-panel.tsx index c996804..dbf280a 100644 --- a/apps/web/src/components/app-shell/code-panel.tsx +++ b/apps/web/src/components/app-shell/code-panel.tsx @@ -17,14 +17,28 @@ export function CodePanel() { React / Tailwind / JSON -
-        {`export const rainbowCode = {
-  product: "global-design-to-code-editor",
-  studios: ["brand", "theme", "component", "canvas", "code"],
-  canvas: "v1-ready",
-  next: "brand-studio"
-};`}
-      
+
+
+
+ {""} +
+ +

+ Code output is generated inside Canvas Studio +

+ +

+ Use the Canvas Studio generated-code panel for live TSX export, JSON + export, import, copy, and future RBC CLI install flows. +

+ +
+            {`rbc export canvas
+rbc add component
+rbc install theme`}
+          
+
+
); } \ No newline at end of file diff --git a/apps/web/src/features/canvas-studio/components/canvas-layers-panel.tsx b/apps/web/src/features/canvas-studio/components/canvas-layers-panel.tsx index 7011900..cfd96e2 100644 --- a/apps/web/src/features/canvas-studio/components/canvas-layers-panel.tsx +++ b/apps/web/src/features/canvas-studio/components/canvas-layers-panel.tsx @@ -1,100 +1,108 @@ "use client"; +import { RbcBadge } from "@/components/ui/rbc-badge"; +import { RbcButton } from "@/components/ui/rbc-button"; import { useCanvasStore } from "@/features/canvas-studio/store/canvas-store"; import { getCanvasNodeLabel } from "@/features/canvas-studio/utils/canvas-node-label"; +function LayersEmptyState() { + const addRectangle = useCanvasStore((state) => state.addRectangle); + const addText = useCanvasStore((state) => state.addText); + const applyTemplate = useCanvasStore((state) => state.applyTemplate); + + return ( +
+
+ ◇ +
+ +

+ No layers yet +

+ +

+ Add a node or apply a template to start building your visual hierarchy. +

+ +
+ applyTemplate("hero")}> + Template + + + Rectangle + + + Text + +
+
+ ); +} + export function CanvasLayersPanel() { const nodes = useCanvasStore((state) => state.nodes); const selectedNodeIds = useCanvasStore((state) => state.selectedNodeIds); const selectNode = useCanvasStore((state) => state.selectNode); - const deleteSelectedNode = useCanvasStore((state) => state.deleteSelectedNode); - const bringSelectedToFront = useCanvasStore( - (state) => state.bringSelectedToFront, - ); - const sendSelectedToBack = useCanvasStore((state) => state.sendSelectedToBack); - - const hasSelection = selectedNodeIds.length > 0; return ( - + + {isSelected ? "Selected" : `#${index + 1}`} + + + ); + })} + + )} + + ); } \ No newline at end of file diff --git a/apps/web/src/features/canvas-studio/components/canvas-properties-panel.tsx b/apps/web/src/features/canvas-studio/components/canvas-properties-panel.tsx index 8e64e20..d0c2648 100644 --- a/apps/web/src/features/canvas-studio/components/canvas-properties-panel.tsx +++ b/apps/web/src/features/canvas-studio/components/canvas-properties-panel.tsx @@ -1,5 +1,7 @@ "use client"; +import { RbcBadge } from "@/components/ui/rbc-badge"; +import { RbcButton } from "@/components/ui/rbc-button"; import { useCanvasStore } from "@/features/canvas-studio/store/canvas-store"; import type { CanvasNode } from "@/features/canvas-studio/types/canvas-node"; @@ -22,7 +24,7 @@ function NumberField({ id, label, value, min, onChange }: NumberFieldProps) {
@@ -32,7 +34,7 @@ function NumberField({ id, label, value, min, onChange }: NumberFieldProps) { min={min} value={Math.round(value)} onChange={(event) => onChange(toNumber(event.currentTarget.value))} - className="mt-1 h-10 w-full rounded-xl border border-slate-200 bg-slate-50 px-3 text-sm text-slate-950 outline-none focus:bg-white focus:ring-2 focus:ring-slate-300 dark:border-slate-800 dark:bg-slate-900 dark:text-white dark:focus:ring-slate-700" + className="mt-1 h-10 w-full rounded-xl border border-slate-200 bg-slate-50 px-3 text-sm font-semibold text-slate-950 outline-none transition focus:border-indigo-300 focus:bg-white focus:ring-4 focus:ring-indigo-500/10 dark:border-slate-800 dark:bg-slate-900 dark:text-white" />
); @@ -80,9 +82,9 @@ function CanvasPropertiesFields({ node }: CanvasPropertiesFieldsProps) { /> -
- Group contains {node.childNodeIds.length} child nodes. Group movement - and ungroup will be added in upcoming issues. +
+ Group contains {node.childNodeIds.length} child + nodes. Moving or resizing this group updates child nodes together.
); @@ -125,7 +127,7 @@ function CanvasPropertiesFields({ node }: CanvasPropertiesFieldsProps) {
@@ -136,7 +138,7 @@ function CanvasPropertiesFields({ node }: CanvasPropertiesFieldsProps) { onChange={(event) => updateNode(node.id, { fill: event.currentTarget.value }) } - className="mt-1 h-10 w-full rounded-xl border border-slate-200 bg-slate-50 px-3 text-sm text-slate-950 outline-none focus:bg-white focus:ring-2 focus:ring-slate-300 dark:border-slate-800 dark:bg-slate-900 dark:text-white dark:focus:ring-slate-700" + className="mt-1 h-10 w-full rounded-xl border border-slate-200 bg-slate-50 px-3 text-sm font-semibold text-slate-950 outline-none transition focus:border-indigo-300 focus:bg-white focus:ring-4 focus:ring-indigo-500/10 dark:border-slate-800 dark:bg-slate-900 dark:text-white" />
@@ -155,7 +157,7 @@ function CanvasPropertiesFields({ node }: CanvasPropertiesFieldsProps) {
@@ -166,7 +168,7 @@ function CanvasPropertiesFields({ node }: CanvasPropertiesFieldsProps) { onChange={(event) => updateNode(node.id, { text: event.currentTarget.value }) } - className="mt-1 h-10 w-full rounded-xl border border-slate-200 bg-slate-50 px-3 text-sm text-slate-950 outline-none focus:bg-white focus:ring-2 focus:ring-slate-300 dark:border-slate-800 dark:bg-slate-900 dark:text-white dark:focus:ring-slate-700" + className="mt-1 h-10 w-full rounded-xl border border-slate-200 bg-slate-50 px-3 text-sm font-semibold text-slate-950 outline-none transition focus:border-indigo-300 focus:bg-white focus:ring-4 focus:ring-indigo-500/10 dark:border-slate-800 dark:bg-slate-900 dark:text-white" />
@@ -183,6 +185,37 @@ function CanvasPropertiesFields({ node }: CanvasPropertiesFieldsProps) { ); } +function PropertiesEmptyState() { + const addRectangle = useCanvasStore((state) => state.addRectangle); + const applyTemplate = useCanvasStore((state) => state.applyTemplate); + + return ( +
+
+ ⚙ +
+ +

+ Nothing selected +

+ +

+ Select a layer or canvas object to edit size, position, color, text, or + group behavior. +

+ +
+ + Add Node + + applyTemplate("hero")}> + Use Template + +
+
+ ); +} + export function CanvasPropertiesPanel() { const nodes = useCanvasStore((state) => state.nodes); const selectedNodeIds = useCanvasStore((state) => state.selectedNodeIds); @@ -191,19 +224,22 @@ export function CanvasPropertiesPanel() { return ( ); @@ -217,30 +253,39 @@ export function CanvasPropertiesPanel() { return ( ); } \ No newline at end of file diff --git a/apps/web/src/features/canvas-studio/components/canvas-stage.tsx b/apps/web/src/features/canvas-studio/components/canvas-stage.tsx index fab20c3..c84e916 100644 --- a/apps/web/src/features/canvas-studio/components/canvas-stage.tsx +++ b/apps/web/src/features/canvas-studio/components/canvas-stage.tsx @@ -3,6 +3,8 @@ import { useEffect, useRef } from "react"; import type Konva from "konva"; import { Group, Layer, Rect, Stage, Text, Transformer } from "react-konva"; +import { RbcBadge } from "@/components/ui/rbc-badge"; +import { RbcButton } from "@/components/ui/rbc-button"; import { useCanvasStore } from "@/features/canvas-studio/store/canvas-store"; import { CANVAS_GRID_SIZE } from "@/features/canvas-studio/utils/canvas-grid"; @@ -19,6 +21,57 @@ function isAdditiveSelection( : false; } +function CanvasEmptyState() { + const addRectangle = useCanvasStore((state) => state.addRectangle); + const addText = useCanvasStore((state) => state.addText); + const applyTemplate = useCanvasStore((state) => state.applyTemplate); + + return ( +
+
+
+ RBC +
+ +
+ Start here + Canvas ready +
+ +

+ Create your first visual layout +

+ +

+ Start from a template or add your own rectangle/text nodes. Every + design action updates live code and JSON export. +

+ +
+ applyTemplate("hero")}> + Use Hero Template + + + applyTemplate("pricing-card")} + > + Pricing Card + + + + Add Rectangle + + + + Add Text + +
+
+
+ ); +} + export function CanvasStage() { const nodes = useCanvasStore((state) => state.nodes); const selectedNodeIds = useCanvasStore((state) => state.selectedNodeIds); @@ -73,7 +126,9 @@ export function CanvasStage() {
-
+
+ {nodes.length === 0 ? : null} +