Skip to content

Commit

Permalink
switch theme to zinc, add support for run button
Browse files Browse the repository at this point in the history
  • Loading branch information
seveibar committed Jan 18, 2025
1 parent 72028fd commit 0836ea4
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 26 deletions.
2 changes: 1 addition & 1 deletion components.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"tailwind": {
"config": "tailwind.config.js",
"css": "index.css",
"baseColor": "neutral",
"baseColor": "zinc",
"cssVariables": false,
"prefix": "rf-"
},
Expand Down
File renamed without changes.
19 changes: 19 additions & 0 deletions examples/example8-run-button.fixture.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { RunFrame } from "lib/components/RunFrame"
import React from "react"

export default () => (
<RunFrame
fsMap={{
"main.tsx": `
circuit.add(
<board width="10mm" height="10mm">
<resistor name="R1" resistance="1k" footprint="0402" />
<capacitor name="C1" capacitance="1uF" footprint="0603" pcbX={4} />
<trace from=".R1 .pin1" to=".C1 .pin1" />
</board>
)`,
}}
entrypoint="main.tsx"
showRunButton={true}
/>
)
55 changes: 50 additions & 5 deletions lib/components/RunFrame.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createCircuitWebWorker } from "@tscircuit/eval-webworker"
import { CircuitJsonPreview, type TabId } from "./CircuitJsonPreview"
import { useEffect, useRef, useState } from "react"
import { useEffect, useReducer, useRef, useState } from "react"
import Debug from "debug"
import { Loader2, Play } from "lucide-react"

// TODO waiting for core PR: https://github.com/tscircuit/core/pull/489
// import { orderedRenderPhases } from "@tscircuit/core"
Expand Down Expand Up @@ -33,6 +34,11 @@ interface Props {
*/
entrypoint: string

/**
* Whether to show a run button that controls when code executes
*/
showRunButton?: boolean

/**
* An optional left-side header, you can put a save button, a run button, or
* a title here.
Expand Down Expand Up @@ -100,6 +106,12 @@ export const RunFrame = (props: Props) => {
error?: string
stack?: string
} | null>(null)
const [runCountTrigger, incRunCountTrigger] = useReducer(
(acc: number, s: number) => acc + 1,
0,
)
const lastRunCountTriggerRef = useRef(0)
const [isRunning, setIsRunning] = useState(false)
const [renderLog, setRenderLog] = useState<RenderLog | null>(null)
const [activeTab, setActiveTab] = useState<TabId>(
props.defaultActiveTab ?? "pcb",
Expand All @@ -120,21 +132,31 @@ export const RunFrame = (props: Props) => {

useEffect(() => {
if (!fsMap) return
const wasTriggeredByRunButton =
props.showRunButton && runCountTrigger !== lastRunCountTriggerRef.current
if (lastFsMapRef.current && circuitJson) {
const changes = getChangesBetweenFsMaps(lastFsMapRef.current, fsMap)

if (Object.keys(changes).length > 0) {
debug("render triggered by changes:", changes)
debug("code changes detected")
} else if (lastEntrypointRef.current !== props.entrypoint) {
debug("render triggered by entrypoint change")
} else {
} else if (!wasTriggeredByRunButton) {
debug("render triggered without changes to fsMap, skipping")
return
}
}

if (
props.showRunButton &&
runCountTrigger === lastRunCountTriggerRef.current
) {
return
}

lastFsMapRef.current = fsMap
lastEntrypointRef.current = props.entrypoint
setIsRunning(true)

async function runWorker() {
debug("running render worker")
Expand Down Expand Up @@ -222,6 +244,7 @@ export const RunFrame = (props: Props) => {
debug("error getting initial circuit json", e)
props.onError?.(e)
setError({ error: e.message, stack: e.stack })
setIsRunning(false)
return null
})
if (!circuitJson) return
Expand All @@ -246,14 +269,36 @@ export const RunFrame = (props: Props) => {
renderLog.progress = 1

setRenderLog({ ...renderLog })
setIsRunning(false)
}
runWorker()
}, [props.fsMap, props.entrypoint])
}, [props.fsMap, props.entrypoint, runCountTrigger])

return (
<CircuitJsonPreview
defaultActiveTab={props.defaultActiveTab}
leftHeaderContent={props.leftHeaderContent}
leftHeaderContent={
<>
{props.showRunButton && (
<button
type="button"
onClick={() => {
incRunCountTrigger(1)
}}
className="rf-flex rf-items-center rf-gap-2 rf-px-4 rf-py-2 rf-bg-blue-600 rf-text-white rf-rounded-md rf-mr-2 disabled:rf-opacity-50"
disabled={isRunning}
>
Run{" "}
{isRunning ? (
<Loader2 className="rf-w-3 rf-h-3 rf-animate-spin" />
) : (
<Play className="rf-w-3 rf-h-3" />
)}
</button>
)}
{props.leftHeaderContent}
</>
}
onActiveTabChange={setActiveTab}
circuitJson={circuitJson}
renderLog={renderLog}
Expand Down
14 changes: 7 additions & 7 deletions lib/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "lib/utils"

const buttonVariants = cva(
"rf-inline-flex rf-items-center rf-justify-center rf-gap-2 rf-whitespace-nowrap rf-rounded-md rf-text-sm rf-font-medium rf-transition-colors focus-visible:rf-outline-none focus-visible:rf-ring-1 focus-visible:rf-ring-neutral-950 disabled:rf-pointer-events-none disabled:rf-opacity-50 [&_svg]:rf-pointer-events-none [&_svg]:rf-size-4 [&_svg]:rf-shrink-0 dark:focus-visible:rf-ring-neutral-300",
"rf-inline-flex rf-items-center rf-justify-center rf-gap-2 rf-whitespace-nowrap rf-rounded-md rf-text-sm rf-font-medium rf-transition-colors focus-visible:rf-outline-none focus-visible:rf-ring-1 focus-visible:rf-ring-zinc-950 disabled:rf-pointer-events-none disabled:rf-opacity-50 [&_svg]:rf-pointer-events-none [&_svg]:rf-size-4 [&_svg]:rf-shrink-0 dark:focus-visible:rf-ring-zinc-300",
{
variants: {
variant: {
default:
"rf-bg-neutral-900 rf-text-neutral-50 rf-shadow hover:rf-bg-neutral-900/90 dark:rf-bg-neutral-50 dark:rf-text-neutral-900 dark:hover:rf-bg-neutral-50/90",
"rf-bg-zinc-900 rf-text-zinc-50 rf-shadow hover:rf-bg-zinc-900/90 dark:rf-bg-zinc-50 dark:rf-text-zinc-900 dark:hover:rf-bg-zinc-50/90",
destructive:
"rf-bg-red-500 rf-text-neutral-50 rf-shadow-sm hover:rf-bg-red-500/90 dark:rf-bg-red-900 dark:rf-text-neutral-50 dark:hover:rf-bg-red-900/90",
"rf-bg-red-500 rf-text-zinc-50 rf-shadow-sm hover:rf-bg-red-500/90 dark:rf-bg-red-900 dark:rf-text-zinc-50 dark:hover:rf-bg-red-900/90",
outline:
"rf-border rf-border-neutral-200 rf-bg-white rf-shadow-sm hover:rf-bg-neutral-100 hover:rf-text-neutral-900 dark:rf-border-neutral-800 dark:rf-bg-neutral-950 dark:hover:rf-bg-neutral-800 dark:hover:rf-text-neutral-50",
"rf-border rf-border-zinc-200 rf-bg-white rf-shadow-sm hover:rf-bg-zinc-100 hover:rf-text-zinc-900 dark:rf-border-zinc-800 dark:rf-bg-zinc-950 dark:hover:rf-bg-zinc-800 dark:hover:rf-text-zinc-50",
secondary:
"rf-bg-neutral-100 rf-text-neutral-900 rf-shadow-sm hover:rf-bg-neutral-100/80 dark:rf-bg-neutral-800 dark:rf-text-neutral-50 dark:hover:rf-bg-neutral-800/80",
"rf-bg-zinc-100 rf-text-zinc-900 rf-shadow-sm hover:rf-bg-zinc-100/80 dark:rf-bg-zinc-800 dark:rf-text-zinc-50 dark:hover:rf-bg-zinc-800/80",
ghost:
"hover:rf-bg-neutral-100 hover:rf-text-neutral-900 dark:hover:rf-bg-neutral-800 dark:hover:rf-text-neutral-50",
link: "rf-text-neutral-900 rf-underline-offset-4 hover:rf-underline dark:rf-text-neutral-50",
"hover:rf-bg-zinc-100 hover:rf-text-zinc-900 dark:hover:rf-bg-zinc-800 dark:hover:rf-text-zinc-50",
link: "rf-text-zinc-900 rf-underline-offset-4 hover:rf-underline dark:rf-text-zinc-50",
},
size: {
default: "rf-h-9 rf-px-4 rf-py-2",
Expand Down
14 changes: 7 additions & 7 deletions lib/components/ui/dropdown-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"rf-flex rf-cursor-default rf-gap-2 rf-select-none rf-items-center rf-rounded-sm rf-px-2 rf-py-1.5 rf-text-sm rf-outline-none focus:rf-bg-neutral-100 data-[state=open]:rf-bg-neutral-100 [&_svg]:rf-pointer-events-none [&_svg]:rf-size-4 [&_svg]:rf-shrink-0 dark:focus:rf-bg-neutral-800 dark:data-[state=open]:rf-bg-neutral-800",
"rf-flex rf-cursor-default rf-gap-2 rf-select-none rf-items-center rf-rounded-sm rf-px-2 rf-py-1.5 rf-text-sm rf-outline-none focus:rf-bg-zinc-100 data-[state=open]:rf-bg-zinc-100 [&_svg]:rf-pointer-events-none [&_svg]:rf-size-4 [&_svg]:rf-shrink-0 dark:focus:rf-bg-zinc-800 dark:data-[state=open]:rf-bg-zinc-800",
inset && "rf-pl-8",
className,
)}
Expand All @@ -45,7 +45,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"rf-z-50 rf-min-w-[8rem] rf-overflow-hidden rf-rounded-md rf-border rf-border-neutral-200 rf-bg-white rf-p-1 rf-text-neutral-950 rf-shadow-lg data-[state=open]:rf-animate-in data-[state=closed]:rf-animate-out data-[state=closed]:rf-fade-out-0 data-[state=open]:rf-fade-in-0 data-[state=closed]:rf-zoom-out-95 data-[state=open]:rf-zoom-in-95 data-[side=bottom]:rf-slide-in-from-top-2 data-[side=left]:rf-slide-in-from-right-2 data-[side=right]:rf-slide-in-from-left-2 data-[side=top]:rf-slide-in-from-bottom-2 dark:rf-border-neutral-800 dark:rf-bg-neutral-950 dark:rf-text-neutral-50",
"rf-z-50 rf-min-w-[8rem] rf-overflow-hidden rf-rounded-md rf-border rf-border-zinc-200 rf-bg-white rf-p-1 rf-text-zinc-950 rf-shadow-lg data-[state=open]:rf-animate-in data-[state=closed]:rf-animate-out data-[state=closed]:rf-fade-out-0 data-[state=open]:rf-fade-in-0 data-[state=closed]:rf-zoom-out-95 data-[state=open]:rf-zoom-in-95 data-[side=bottom]:rf-slide-in-from-top-2 data-[side=left]:rf-slide-in-from-right-2 data-[side=right]:rf-slide-in-from-left-2 data-[side=top]:rf-slide-in-from-bottom-2 dark:rf-border-zinc-800 dark:rf-bg-zinc-950 dark:rf-text-zinc-50",
className,
)}
{...props}
Expand All @@ -63,7 +63,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"rf-z-50 rf-min-w-[8rem] rf-overflow-hidden rf-rounded-md rf-border rf-border-neutral-200 rf-bg-white rf-p-1 rf-text-neutral-950 rf-shadow-md dark:rf-border-neutral-800 dark:rf-bg-neutral-950 dark:rf-text-neutral-50",
"rf-z-50 rf-min-w-[8rem] rf-overflow-hidden rf-rounded-md rf-border rf-border-zinc-200 rf-bg-white rf-p-1 rf-text-zinc-950 rf-shadow-md dark:rf-border-zinc-800 dark:rf-bg-zinc-950 dark:rf-text-zinc-50",
"data-[state=open]:rf-animate-in data-[state=closed]:rf-animate-out data-[state=closed]:rf-fade-out-0 data-[state=open]:rf-fade-in-0 data-[state=closed]:rf-zoom-out-95 data-[state=open]:rf-zoom-in-95 data-[side=bottom]:rf-slide-in-from-top-2 data-[side=left]:rf-slide-in-from-right-2 data-[side=right]:rf-slide-in-from-left-2 data-[side=top]:rf-slide-in-from-bottom-2",
className,
)}
Expand All @@ -82,7 +82,7 @@ const DropdownMenuItem = React.forwardRef<
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"rf-relative rf-flex rf-cursor-default rf-select-none rf-items-center rf-gap-2 rf-rounded-sm rf-px-2 rf-py-1.5 rf-text-sm rf-outline-none rf-transition-colors focus:rf-bg-neutral-100 focus:rf-text-neutral-900 data-[disabled]:rf-pointer-events-none data-[disabled]:rf-opacity-50 [&>svg]:rf-size-4 [&>svg]:rf-shrink-0 dark:focus:rf-bg-neutral-800 dark:focus:rf-text-neutral-50",
"rf-relative rf-flex rf-cursor-default rf-select-none rf-items-center rf-gap-2 rf-rounded-sm rf-px-2 rf-py-1.5 rf-text-sm rf-outline-none rf-transition-colors focus:rf-bg-zinc-100 focus:rf-text-zinc-900 data-[disabled]:rf-pointer-events-none data-[disabled]:rf-opacity-50 [&>svg]:rf-size-4 [&>svg]:rf-shrink-0 dark:focus:rf-bg-zinc-800 dark:focus:rf-text-zinc-50",
inset && "rf-pl-8",
className,
)}
Expand All @@ -98,7 +98,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"rf-relative rf-flex rf-cursor-default rf-select-none rf-items-center rf-rounded-sm rf-py-1.5 rf-pl-8 rf-pr-2 rf-text-sm rf-outline-none rf-transition-colors focus:rf-bg-neutral-100 focus:rf-text-neutral-900 data-[disabled]:rf-pointer-events-none data-[disabled]:rf-opacity-50 dark:focus:rf-bg-neutral-800 dark:focus:rf-text-neutral-50",
"rf-relative rf-flex rf-cursor-default rf-select-none rf-items-center rf-rounded-sm rf-py-1.5 rf-pl-8 rf-pr-2 rf-text-sm rf-outline-none rf-transition-colors focus:rf-bg-zinc-100 focus:rf-text-zinc-900 data-[disabled]:rf-pointer-events-none data-[disabled]:rf-opacity-50 dark:focus:rf-bg-zinc-800 dark:focus:rf-text-zinc-50",
className,
)}
checked={checked}
Expand All @@ -122,7 +122,7 @@ const DropdownMenuRadioItem = React.forwardRef<
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"rf-relative rf-flex rf-cursor-default rf-select-none rf-items-center rf-rounded-sm rf-py-1.5 rf-pl-8 rf-pr-2 rf-text-sm rf-outline-none rf-transition-colors focus:rf-bg-neutral-100 focus:rf-text-neutral-900 data-[disabled]:rf-pointer-events-none data-[disabled]:rf-opacity-50 dark:focus:rf-bg-neutral-800 dark:focus:rf-text-neutral-50",
"rf-relative rf-flex rf-cursor-default rf-select-none rf-items-center rf-rounded-sm rf-py-1.5 rf-pl-8 rf-pr-2 rf-text-sm rf-outline-none rf-transition-colors focus:rf-bg-zinc-100 focus:rf-text-zinc-900 data-[disabled]:rf-pointer-events-none data-[disabled]:rf-opacity-50 dark:focus:rf-bg-zinc-800 dark:focus:rf-text-zinc-50",
className,
)}
{...props}
Expand Down Expand Up @@ -162,7 +162,7 @@ const DropdownMenuSeparator = React.forwardRef<
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn(
"rf--mx-1 rf-my-1 rf-h-px rf-bg-neutral-100 dark:rf-bg-neutral-800",
"rf--mx-1 rf-my-1 rf-h-px rf-bg-zinc-100 dark:rf-bg-zinc-800",
className,
)}
{...props}
Expand Down
6 changes: 3 additions & 3 deletions lib/components/ui/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List
ref={ref}
className={cn(
"rf-inline-flex rf-h-9 rf-items-center rf-justify-center rf-rounded-lg rf-bg-neutral-100 rf-p-1 rf-text-neutral-500 dark:rf-bg-neutral-800 dark:rf-text-neutral-400",
"rf-inline-flex rf-h-9 rf-items-center rf-justify-center rf-rounded-lg rf-bg-zinc-100 rf-p-1 rf-text-zinc-500 dark:rf-bg-zinc-800 dark:rf-text-zinc-400",
className,
)}
{...props}
Expand All @@ -29,7 +29,7 @@ const TabsTrigger = React.forwardRef<
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"rf-inline-flex rf-items-center rf-justify-center rf-whitespace-nowrap rf-rounded-md rf-px-3 rf-py-1 rf-text-sm rf-font-medium rf-ring-offset-white rf-transition-all focus-visible:rf-outline-none focus-visible:rf-ring-2 focus-visible:rf-ring-neutral-950 focus-visible:rf-ring-offset-2 disabled:rf-pointer-events-none disabled:rf-opacity-50 data-[state=active]:rf-bg-white data-[state=active]:rf-text-neutral-950 data-[state=active]:rf-shadow dark:rf-ring-offset-neutral-950 dark:focus-visible:rf-ring-neutral-300 dark:data-[state=active]:rf-bg-neutral-950 dark:data-[state=active]:rf-text-neutral-50",
"rf-inline-flex rf-items-center rf-justify-center rf-whitespace-nowrap rf-rounded-md rf-px-3 rf-py-1 rf-text-sm rf-font-medium rf-ring-offset-white rf-transition-all focus-visible:rf-outline-none focus-visible:rf-ring-2 focus-visible:rf-ring-zinc-950 focus-visible:rf-ring-offset-2 disabled:rf-pointer-events-none disabled:rf-opacity-50 data-[state=active]:rf-bg-white data-[state=active]:rf-text-zinc-950 data-[state=active]:rf-shadow dark:rf-ring-offset-zinc-950 dark:focus-visible:rf-ring-zinc-300 dark:data-[state=active]:rf-bg-zinc-950 dark:data-[state=active]:rf-text-zinc-50",
className,
)}
{...props}
Expand All @@ -44,7 +44,7 @@ const TabsContent = React.forwardRef<
<TabsPrimitive.Content
ref={ref}
className={cn(
"rf-mt-2 rf-ring-offset-white focus-visible:rf-outline-none focus-visible:rf-ring-2 focus-visible:rf-ring-neutral-950 focus-visible:rf-ring-offset-2 dark:rf-ring-offset-neutral-950 dark:focus-visible:rf-ring-neutral-300",
"rf-mt-2 rf-ring-offset-white focus-visible:rf-outline-none focus-visible:rf-ring-2 focus-visible:rf-ring-zinc-950 focus-visible:rf-ring-offset-2 dark:rf-ring-offset-zinc-950 dark:focus-visible:rf-ring-zinc-300",
className,
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion lib/hooks/styles.generated.ts

Large diffs are not rendered by default.

18 changes: 16 additions & 2 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RunFrameForCli } from "lib/runner"
import { RunFrame } from "lib/runner"
import React from "react"
import { createRoot } from "react-dom/client"

Expand All @@ -7,7 +7,21 @@ const root = createRoot(document.getElementById("root")!)
root.render(
<React.StrictMode>
<div style={{ width: "100vw", height: "100vh" }}>
<RunFrameForCli debug={window.location.search.includes("debug")} />
<RunFrame
fsMap={{
"main.tsx": `
circuit.add(
<board width="10mm" height="10mm">
<resistor name="R1" resistance="1k" footprint="0402" />
<capacitor name="C1" capacitance="1uF" footprint="0603" pcbX={4} />
<trace from=".R1 .pin1" to=".C1 .pin1" />
</board>
)`,
}}
entrypoint="main.tsx"
showRunButton={true}
debug={window.location.search.includes("debug")}
/>
</div>
</React.StrictMode>,
)

0 comments on commit 0836ea4

Please sign in to comment.