Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .fallowrc.jsonc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/config-schema.json",
"entry": [
// promptwise: run by hand to sync BoardUI from a bebraai checkout.
"packages/studio/scripts/sync-boardui.mjs",
// IconButton, Tabs and cn are exported before their first consumer exists.
"packages/studio/src/components/ui/index.ts",
"packages/producer/src/**/*.test.ts",
Expand Down Expand Up @@ -83,6 +85,8 @@
],
"ignorePatterns": [
"docs/**",
// promptwise: BoardUI, copied in whole by packages/studio/scripts/sync-boardui.mjs.
"packages/studio/src/boardui/**",
// Chrome browser binaries downloaded by puppeteer — not project source.
"chrome/**",
// Standalone spike scripts and benchmark runners used during R&D.
Expand Down Expand Up @@ -429,6 +433,9 @@
},
],
"ignoreDependencies": [
// promptwise: used by src/boardui, which is ignored above as synced code.
"react-aria-components",
"tailwind-merge",
// Runtime/dynamic deps not visible to static analysis: tsup `external`,
// dynamic require() resolution, peer/static-file consumption in tests,
// and bun-hoisted workspace devDeps (e.g. happy-dom in root package.json
Expand Down
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,6 @@ registry/**/*.html linguist-vendored
examples/docs-reference-project/**/*.wav filter=lfs diff=lfs merge=lfs -text

packages/cli/src/cloud/_gen/** linguist-generated=true

# promptwise: BoardUI, copied in whole by packages/studio/scripts/sync-boardui.mjs.
packages/studio/src/boardui/** linguist-generated=true
1 change: 1 addition & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"registry/blocks/{glass-shard-title,code-slice-hero,cuboid-carousel,frost-sequence-camera-orbit,orbit-card}/**/*.{js,mjs}",
"registry/blocks/frost-sequence-camera-orbit/source/**",
"chrome/",
"packages/studio/src/boardui/",
"packages/cli/src/media-use/lib/svg-sanitize.mjs"
],
"overrides": [
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ skills/media-use/SKILL.md
skills/figma/SKILL.md
skills/slideshow/SKILL.md
skills/remotion-to-hyperframes/SKILL.md

# promptwise: BoardUI, copied in whole by packages/studio/scripts/sync-boardui.mjs.
packages/studio/src/boardui/
24 changes: 24 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion packages/studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@
"cn": "0.2.4",
"dockview-react": "8.3.1",
"gsap": "^3.13.0",
"mediabunny": "^1.45.3"
"mediabunny": "^1.45.3",
"react-aria-components": "^1.22.1",
"tailwind-merge": "^3.7.0"
},
"devDependencies": {
"@hyperframes/producer": "workspace:*",
Expand Down
104 changes: 104 additions & 0 deletions packages/studio/scripts/sync-boardui.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env node
// Copies promptwise's BoardUI components into src/boardui, the only place Studio's UI comes from.
// Usage: node packages/studio/scripts/sync-boardui.mjs <path to a bebraai checkout>
import {
cpSync,
existsSync,
readFileSync,
readdirSync,
rmSync,
statSync,
writeFileSync,
} from "node:fs";
import { dirname, join, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";

const web = resolve(process.argv[2] ?? "", "apps/web");
if (!existsSync(join(web, "components/base"))) {
console.error("usage: sync-boardui.mjs <bebraai checkout>");
process.exit(1);
}
const out = resolve(dirname(fileURLToPath(import.meta.url)), "../src/boardui");

const COMPONENTS = [
"badges",
"buttons",
"checkbox",
"divider",
"dropdown",
"empty-state",
"input",
"kbd",
"menu",
"modal",
"popover",
"radio",
"segmented-control",
"select",
"slider",
"switch",
"tabs",
"textarea",
"toast",
"tooltip",
];
const FILES = [
...COMPONENTS.map((name) => `components/base/${name}`),
"components/foundations/direction",
"components/foundations/icons",
"components/icons.tsx",
"utils/cx.ts",
"utils/directional-icon.ts",
"utils/use-dismiss-on-outside-press.ts",
"styles/theme.css",
"styles/typography.css",
];

rmSync(out, { recursive: true, force: true });
for (const path of FILES) cpSync(join(web, path), join(out, path), { recursive: true });

const files = (dir) =>
readdirSync(dir).flatMap((name) => {
const path = join(dir, name);
return statSync(path).isDirectory() ? files(path) : [path];
});

for (const file of files(out).filter((f) => /\.tsx?$/.test(f))) {
const source = readFileSync(file, "utf8")
.replace(/from "next\/link"/g, 'from "@/next-link"')
.replace(/from "@\/([^"]+)"/g, (_, target) => {
const rel = relative(dirname(file), join(out, target));
return `from "${rel.startsWith(".") ? rel : `./${rel}`}"`;
});
writeFileSync(file, source);
}
// Studio clears Tailwind's palette and reuses some ramp names for its own tokens, so BoardUI's ramps move to
// --bui-* (filled from Tailwind's defaults, as BoardUI expects), and its dark mode follows Studio's data-theme.
const RAMP =
/--color-((?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-\d+)/g;
const tailwind = new Map(
[
...readFileSync(resolve(web, "../../node_modules/tailwindcss/theme.css"), "utf8").matchAll(
/--color-([a-z]+-\d+):\s*([^;]+);/g,
),
].map((m) => [m[1], m[2]]),
);
const themePath = join(out, "styles/theme.css");
const theme = readFileSync(themePath, "utf8")
.replace(RAMP, "--bui-$1")
.replace(/^\.dark\b/gm, ':root:not([data-theme="paper"])');
const defined = new Set([...theme.matchAll(/(--bui-[a-z]+-\d+):/g)].map((m) => m[1]));
const missing = [...new Set([...theme.matchAll(/var\((--bui-([a-z]+-\d+))\)/g)].map((m) => m[2]))]
.filter((name) => !defined.has(`--bui-${name}`))
.sort();
writeFileSync(
themePath,
`${theme}\n:root {\n${missing.map((name) => ` --bui-${name}: ${tailwind.get(name)};`).join("\n")}\n}\n`,
);

// Studio has no Next router, so BoardUI's links are plain anchors.
writeFileSync(
join(out, "next-link.tsx"),
'import type { ComponentProps } from "react";\n\nexport default function Link(props: ComponentProps<"a">) {\n return <a {...props} />;\n}\n',
);
console.log(`boardui: synced ${FILES.length} paths from ${web}`);
75 changes: 75 additions & 0 deletions packages/studio/src/boardui/components/base/badges/chip.tsx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading