Files
cosscom__coss/apps/ui/scripts/sync-ui.mts
Pasquale Vitiello e7a3a00c5f refactor: UI/UX general improvements (#617)
* feat: 1:1 font replacement

* feat: add examples app

* style: update font sizes and improve component styles for consistency

* update font

* style: restore default font weights

* refactor: move local fonts to packages

* feat: update font weights and refactor font imports in examples app

* fix CommandDialog not closing on ESC

* refactor: command component improvements

* chore: remove console log from command demo

* refactor: update Command and Menu components to use <kbd> for shortcuts and improve styling

* style: fix formatting in globals.css by removing unnecessary whitespace

* fix: refactor group and toggle-group to prevent flickering menu trigger at the end of a group

* refactor: toggle group and group improvements

* refactor: update toggle component styles for consistency and clarity

* refactor: major styling improvements

* fix: dialogs

* refactor: prefer not-dark:

* fix: scrollarea overscroll

* refactor: integrate ScrollArea component throughout

* style: various improvements

* style: mc

* style: update button sizes and improve mobile footer layout

* style: adjust code component font size and refactor particle card container className

* style: improve mobile footer

* refactor: improve carious components

* style: mc

* chore: implement Cal.ai badge

* feat: implement new event type dialog

* refactor: clean up event types and improve page layout

* feat: implement ai-mode in the cmdk component

* chore: format

* fix: remove outline from CommandDialogPopup

* fix: update separator className to use bg-input instead of bg-border

* fix: cubic issues

* style: update font size in code components for consistency

* style: improve shadows

* fix: update badge and toggle components to use bg-background

* chore: update color references

* chore: fix registry

* chore: sync package component + build registry

* fix(accordion): issue 596

* fix: issue 609

* docs: updates

* chore: improve sync script

* feat: add AI-powered command particle

* feat: improve switch and add menu checkbox switch variant

* style: toggle improvements

* fix: docs container

* style: remove css vars from examples

* chore: format

* feat: add more example pages
2026-01-08 09:35:53 +00:00

135 lines
4.0 KiB
TypeScript

import { promises as fs } from "node:fs";
import path from "node:path";
async function resolvePaths() {
const cwd = process.cwd();
const sourceRoot = path.join(cwd, "registry/default");
const sourceDirs = {
hooks: path.join(sourceRoot, "hooks"),
lib: path.join(sourceRoot, "lib"),
ui: path.join(sourceRoot, "ui"),
};
// From apps/ui → ../../packages/ui/src/*
const targetRoot = path.resolve(cwd, "../../packages/ui/src");
const targetDirs = {
hooks: path.join(targetRoot, "hooks"),
lib: path.join(targetRoot, "lib"),
ui: path.join(targetRoot, "components"),
};
return { sourceDirs, sourceRoot, targetDirs, targetRoot };
}
async function ensureDirExists(dir: string) {
await fs.mkdir(dir, { recursive: true });
}
async function copyAndRewriteFile(from: string, to: string) {
const content = await fs.readFile(from, "utf8");
// Only rewrite TypeScript/JavaScript files
if (/(\.tsx|\.ts|\.mts|\.cts|\.jsx|\.js)$/.test(from)) {
const rewritten = rewriteImports(content);
await fs.writeFile(to, rewritten, "utf8");
} else {
// Copy non-code files as-is
await fs.copyFile(from, to);
}
}
async function copyDirectoryRecursive(from: string, to: string) {
await ensureDirExists(to);
const entries = await fs.readdir(from, { withFileTypes: true });
for (const entry of entries) {
const fromPath = path.join(from, entry.name);
const toPath = path.join(to, entry.name);
if (entry.isDirectory()) {
await copyDirectoryRecursive(fromPath, toPath);
} else {
await copyAndRewriteFile(fromPath, toPath);
}
}
}
async function copyRegistryTrees() {
const { sourceRoot, sourceDirs, targetDirs } = await resolvePaths();
// Validate root exists
try {
await fs.access(sourceRoot);
} catch {
throw new Error(`Source root not found: ${sourceRoot}`);
}
// For each subtree (ui, hooks, lib), copy if present
for (const key of Object.keys(sourceDirs) as (keyof typeof sourceDirs)[]) {
const from = sourceDirs[key];
const to = targetDirs[key];
try {
await fs.access(from);
} catch {
// Skip silently if the subtree doesn't exist
continue;
}
await copyDirectoryRecursive(from, to);
}
}
function rewriteImports(code: string): string {
let result = code;
// Rewrite paths according to rules
// "@/lib/*" → "@coss/ui/lib/*"
// "@/hooks/*" → "@coss/ui/hooks/*"
// "@/registry/default/ui/*" → "@coss/ui/components/*"
// "@/registry/default/hooks/*" → "@coss/ui/hooks/*"
// "@/registry/default/lib/*" → "@coss/ui/lib/*"
result = result.replace(/(["'])@\/lib\//g, "$1@coss/ui/lib/");
result = result.replace(/(["'])@\/hooks\//g, "$1@coss/ui/hooks/");
result = result.replace(
/(["'])@\/registry\/default\/ui\//g,
"$1@coss/ui/components/",
);
result = result.replace(
/(["'])@\/registry\/default\/hooks\//g,
"$1@coss/ui/hooks/",
);
result = result.replace(
/(["'])@\/registry\/default\/lib\//g,
"$1@coss/ui/lib/",
);
return result;
}
async function invalidatePackageCache() {
const { targetRoot } = await resolvePaths();
const packageJsonPath = path.join(targetRoot, "../package.json");
try {
// Touch package.json to invalidate Next.js module cache
const now = new Date();
await fs.utimes(packageJsonPath, now, now);
} catch {
// Ignore if package.json doesn't exist or can't be touched
}
}
try {
console.log("📦 Propagating registry primitives → packages/ui/src …");
const { sourceDirs, targetRoot } = await resolvePaths();
console.log("├─ Sources:");
console.log(`│ ├─ UI: ${sourceDirs.ui}`);
console.log(`│ ├─ Hooks: ${sourceDirs.hooks}`);
console.log(`│ └─ Lib: ${sourceDirs.lib}`);
console.log(`└─ Target root: ${targetRoot}`);
await copyRegistryTrees();
await invalidatePackageCache();
console.log(
"✅ UI primitives synced successfully! (imports rewritten during copy)",
);
} catch (error) {
console.error(error);
process.exit(1);
}