Skip to content

Commit 869b946

Browse files
gmoonclaude
andcommitted
Extract @forkzero/ui shared design system package
Move tokens, styles, Header, Footer, and CopyButton into packages/ui/ using npm workspaces. Header and Footer now accept props (navLinks, githubUrl, repoUrl, etc.) instead of importing constants directly, making them reusable across repos. Consumers install from GitHub Packages; forkzero.ai uses the workspace symlink during dev. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 34e6661 commit 869b946

25 files changed

Lines changed: 314 additions & 109 deletions

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ jobs:
3333
- name: Lint
3434
run: npm run lint
3535

36+
- name: Build design system
37+
run: npm run build -w packages/ui
38+
3639
- name: Typecheck
3740
run: npx tsc --noEmit
3841

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Publish Design System
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths: ['packages/ui/**']
7+
8+
jobs:
9+
publish:
10+
name: Publish @forkzero/ui
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
14+
packages: write
15+
steps:
16+
- uses: actions/checkout@v4
17+
- uses: actions/setup-node@v4
18+
with:
19+
node-version: 22
20+
registry-url: https://npm.pkg.github.com
21+
cache: npm
22+
- run: npm ci
23+
- run: npm run build -w packages/ui
24+
- run: npm publish -w packages/ui
25+
env:
26+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
node_modules
22
dist
3+
packages/*/dist
34
coverage
45
*.tsbuildinfo
56
*.local

Makefile

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: ci install format lint typecheck build test clean pre-commit pre-push
1+
.PHONY: ci install format lint typecheck build build-ui test clean pre-commit pre-push
22

33
# Pre-commit gate: fast checks (format + lint)
44
pre-commit: format lint
@@ -21,23 +21,27 @@ format:
2121
lint:
2222
npm run lint
2323

24-
typecheck:
24+
build-ui:
25+
npm run build -w packages/ui
26+
27+
typecheck: build-ui
2528
npx tsc --noEmit
2629

27-
build:
30+
build: build-ui
2831
npm run build
2932

3033
test:
3134
npm test
3235

3336
clean:
34-
rm -rf dist node_modules
37+
rm -rf dist packages/*/dist node_modules
3538

3639
help:
3740
@echo "Available targets:"
3841
@echo " make pre-commit - Check formatting + lint (run before commit)"
3942
@echo " make pre-push - Full check: format + lint + typecheck + test + build (run before push)"
4043
@echo " make ci - Full CI with clean install"
44+
@echo " make build-ui - Build @forkzero/ui package"
4145
@echo " make build - Build for production"
4246
@echo " make test - Run tests with coverage"
4347
@echo " make clean - Remove dist and node_modules"

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import tseslint from 'typescript-eslint'
33
import reactHooks from 'eslint-plugin-react-hooks'
44

55
export default tseslint.config(
6-
{ ignores: ['dist', 'node_modules'] },
6+
{ ignores: ['dist', 'node_modules', 'packages/*/dist'] },
77
js.configs.recommended,
88
...tseslint.configs.recommended,
99
{

package-lock.json

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@
33
"private": true,
44
"version": "0.1.0",
55
"type": "module",
6+
"workspaces": ["packages/*"],
67
"scripts": {
78
"dev": "vite",
89
"build": "tsc -b && vite build && tsx scripts/prerender.ts",
910
"preview": "vite preview",
1011
"test": "vitest run --coverage",
1112
"test:fast": "vitest run",
1213
"test:watch": "vitest",
13-
"lint": "eslint src scripts",
14-
"lint:fix": "eslint src scripts --fix",
15-
"format": "prettier --write 'src/**/*.{ts,tsx}' 'scripts/**/*.ts'",
16-
"format:check": "prettier --check 'src/**/*.{ts,tsx}' 'scripts/**/*.ts'"
14+
"lint": "eslint src scripts packages/ui/src",
15+
"lint:fix": "eslint src scripts packages/ui/src --fix",
16+
"format": "prettier --write 'src/**/*.{ts,tsx}' 'scripts/**/*.ts' 'packages/ui/src/**/*.{ts,tsx}'",
17+
"format:check": "prettier --check 'src/**/*.{ts,tsx}' 'scripts/**/*.ts' 'packages/ui/src/**/*.{ts,tsx}'"
1718
},
1819
"dependencies": {
1920
"@giscus/react": "^3.1.0",

packages/ui/package.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "@forkzero/ui",
3+
"version": "0.1.0",
4+
"type": "module",
5+
"main": "dist/index.js",
6+
"types": "dist/index.d.ts",
7+
"exports": {
8+
".": {
9+
"types": "./dist/index.d.ts",
10+
"import": "./dist/index.js"
11+
},
12+
"./tokens": {
13+
"types": "./dist/tokens.d.ts",
14+
"import": "./dist/tokens.js"
15+
},
16+
"./styles": {
17+
"types": "./dist/styles.d.ts",
18+
"import": "./dist/styles.js"
19+
}
20+
},
21+
"files": ["dist"],
22+
"scripts": {
23+
"build": "tsc"
24+
},
25+
"peerDependencies": {
26+
"react": "^18.0.0 || ^19.0.0"
27+
},
28+
"devDependencies": {
29+
"react": "^19.0.0",
30+
"@types/react": "^19.0.0",
31+
"typescript": "^5.7.0"
32+
},
33+
"repository": {
34+
"type": "git",
35+
"url": "https://github.com/forkzero/forkzero.ai.git",
36+
"directory": "packages/ui"
37+
},
38+
"publishConfig": {
39+
"registry": "https://npm.pkg.github.com"
40+
}
41+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { colors, fonts } from '../tokens'
2+
3+
export interface FooterProps {
4+
repoUrl?: string
5+
repoLabel?: string
6+
orgName?: string
7+
}
8+
9+
const styles = {
10+
footer: {
11+
textAlign: 'center' as const,
12+
padding: '2rem',
13+
color: colors.textMuted,
14+
fontSize: '0.85rem',
15+
fontFamily: fonts.system,
16+
borderTop: `1px solid ${colors.borderColor}`,
17+
marginTop: '3rem',
18+
},
19+
link: {
20+
color: colors.accentBlue,
21+
textDecoration: 'none',
22+
},
23+
}
24+
25+
export function Footer({ repoUrl, repoLabel, orgName }: FooterProps) {
26+
return (
27+
<footer style={styles.footer}>
28+
<p>
29+
&copy; {new Date().getFullYear()} {orgName ?? 'Forkzero'}.{' '}
30+
{repoUrl ? (
31+
<>
32+
Built with{' '}
33+
<a href={repoUrl} style={styles.link}>
34+
{repoLabel ?? 'Lattice'}
35+
</a>
36+
.
37+
</>
38+
) : (
39+
<>Built with {repoLabel ?? 'Lattice'}.</>
40+
)}
41+
</p>
42+
</footer>
43+
)
44+
}

0 commit comments

Comments
 (0)