From 615a3a2dbf1f734726e2b63478c7e673f74ae1f5 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 28 Feb 2026 16:49:43 -0500 Subject: [PATCH] Replace direct Shiki usage with @pierre/diffs File component Use the File component from @pierre/diffs/react instead of manually creating a Shiki highlighter instance. Register the custom DOT grammar via attachResolvedLanguages and drop the direct shiki dependency. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/arc-web/app/app.css | 15 --- apps/arc-web/app/data/dot-grammar.ts | 2 +- .../arc-web/app/data/register-dot-language.ts | 17 +++ .../app/routes/workflow-definition.tsx | 116 +++++------------- apps/arc-web/package.json | 3 +- 5 files changed, 48 insertions(+), 105 deletions(-) create mode 100644 apps/arc-web/app/data/register-dot-language.ts diff --git a/apps/arc-web/app/app.css b/apps/arc-web/app/app.css index 901b51bb4..63818aa80 100644 --- a/apps/arc-web/app/app.css +++ b/apps/arc-web/app/app.css @@ -35,21 +35,6 @@ radial-gradient(ellipse 80% 50% at 85% 90%, rgba(90, 200, 168, 0.07) 0%, transparent 45%); background-attachment: fixed; } -/* ── Shiki syntax highlighting ── */ - -.shiki-container pre.shiki { - background: transparent !important; - margin: 0; - padding: 1rem 1.25rem; - font-family: var(--font-mono); - font-size: 0.8125rem; - line-height: 1.7; -} - -.shiki-container pre.shiki code { - font-family: inherit; -} - /* ── @pierre/diffs brand overrides ── */ :root { diff --git a/apps/arc-web/app/data/dot-grammar.ts b/apps/arc-web/app/data/dot-grammar.ts index b3be1d95c..96f2a799a 100644 --- a/apps/arc-web/app/data/dot-grammar.ts +++ b/apps/arc-web/app/data/dot-grammar.ts @@ -1,4 +1,4 @@ -import type { LanguageRegistration } from "shiki"; +import type { LanguageRegistration } from "@pierre/diffs"; export const dotLanguage: LanguageRegistration = { name: "dot", diff --git a/apps/arc-web/app/data/register-dot-language.ts b/apps/arc-web/app/data/register-dot-language.ts new file mode 100644 index 000000000..6b2876ec9 --- /dev/null +++ b/apps/arc-web/app/data/register-dot-language.ts @@ -0,0 +1,17 @@ +import type { BundledLanguage } from "@pierre/diffs"; +import { + attachResolvedLanguages, + getSharedHighlighter, +} from "@pierre/diffs"; +import { dotLanguage } from "./dot-grammar"; + +export async function registerDotLanguage(): Promise { + const highlighter = await getSharedHighlighter({ + themes: ["pierre-dark"], + langs: [], + }); + attachResolvedLanguages( + { name: "dot" as BundledLanguage, data: [dotLanguage] }, + highlighter, + ); +} diff --git a/apps/arc-web/app/routes/workflow-definition.tsx b/apps/arc-web/app/routes/workflow-definition.tsx index eff7a9892..2ca0c98ce 100644 --- a/apps/arc-web/app/routes/workflow-definition.tsx +++ b/apps/arc-web/app/routes/workflow-definition.tsx @@ -1,94 +1,24 @@ -import { ChevronRightIcon } from "@heroicons/react/20/solid"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useState } from "react"; import { useParams } from "react-router"; +import type { BundledLanguage } from "@pierre/diffs"; +import { File } from "@pierre/diffs/react"; +import { registerDotLanguage } from "../data/register-dot-language"; import { workflowData } from "./workflow-detail"; -import { dotLanguage } from "../data/dot-grammar"; - -function CodeBlock({ - code, - lang, - filename, - defaultOpen = true, -}: { - code: string; - lang: string; - filename: string; - defaultOpen?: boolean; -}) { - const containerRef = useRef(null); - const [ready, setReady] = useState(false); - const [open, setOpen] = useState(defaultOpen); - - useEffect(() => { - let cancelled = false; - - async function highlight() { - const { createHighlighter } = await import("shiki"); - if (cancelled) return; - - const highlighter = await createHighlighter({ - themes: ["nord"], - langs: lang === "dot" ? [dotLanguage] : [lang], - }); - - if (cancelled) return; - - const html = highlighter.codeToHtml(code, { - lang, - theme: "nord", - }); - - if (cancelled || containerRef.current == null) return; - containerRef.current.innerHTML = html; - setReady(true); - } - - highlight(); - return () => { - cancelled = true; - }; - }, [code, lang]); - - const lines = code.split("\n"); - const lineCount = lines.length; - const loc = lines.filter((l) => l.trim().length > 0).length; - - return ( -
- - -
-
-
- - {!ready && ( -
-            {code}
-          
- )} -
-
- ); -} export default function WorkflowDefinition() { const { name } = useParams(); const workflow = workflowData[name ?? ""]; + const [dotReady, setDotReady] = useState(false); + + useEffect(() => { + let cancelled = false; + registerDotLanguage().then(() => { + if (!cancelled) setDotReady(true); + }); + return () => { + cancelled = true; + }; + }, []); if (workflow == null) { return

No configuration found.

; @@ -96,8 +26,20 @@ export default function WorkflowDefinition() { return (
- - + + {dotReady && ( + + )}
); } diff --git a/apps/arc-web/package.json b/apps/arc-web/package.json index 7a270fabf..4182023c8 100644 --- a/apps/arc-web/package.json +++ b/apps/arc-web/package.json @@ -18,8 +18,7 @@ "isbot": "^5.1.31", "react": "^19.2.4", "react-dom": "^19.2.4", - "react-router": "7.12.0", - "shiki": "^4.0.0" + "react-router": "7.12.0" }, "devDependencies": { "@react-router/dev": "7.12.0",