@launch77-shared/plugin-design-system 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,244 @@
1
+ # Design System Plugin
2
+
3
+ Launch77 plugin for setting up a token-driven design system with Tailwind CSS integration.
4
+
5
+ ## Features
6
+
7
+ - 🎨 **Semantic Design Tokens** - HSL-format CSS custom properties for consistent theming
8
+ - 🌗 **Dark Mode** - Complete dark mode support via `.dark` class
9
+ - ⚡ **Tailwind Integration** - Automatic preset configuration with all theme colors
10
+ - 🎬 **Animations** - 8 built-in keyframe animations
11
+ - 🎯 **Brand Customization** - Simple CSS override system
12
+ - 🔧 **shadcn Compatible** - Follows shadcn/ui token architecture
13
+ - 📄 **Test Page** - Comprehensive visual testing route
14
+
15
+ ## Installation
16
+
17
+ From your Launch77 app directory:
18
+
19
+ ```bash
20
+ launch77 plugin:install design-system
21
+ ```
22
+
23
+ The plugin will automatically:
24
+
25
+ 1. Add `@launch77-shared/lib-design-system` dependency to package.json
26
+ 2. Insert CSS token imports into `app/globals.css`
27
+ 3. Add Tailwind preset to `tailwind.config.ts`
28
+ 4. Copy template files:
29
+ - `/app/design-system-test/page.tsx` - Visual test page
30
+ - `/src/modules/design-system/config/brand.css` - Brand customization
31
+ - `/src/modules/design-system/README.md` - Module documentation
32
+
33
+ ## What Gets Modified
34
+
35
+ ### `package.json`
36
+
37
+ ```json
38
+ {
39
+ "dependencies": {
40
+ "@launch77-shared/lib-design-system": "^0.1.0"
41
+ }
42
+ }
43
+ ```
44
+
45
+ ### `app/globals.css`
46
+
47
+ ```css
48
+ /* Launch77 Design System */
49
+ @import '@launch77-shared/lib-design-system/tokens.css';
50
+ @import '../src/modules/design-system/config/brand.css';
51
+ ```
52
+
53
+ ### `tailwind.config.ts`
54
+
55
+ ```typescript
56
+ const config: Config = {
57
+ presets: [require('@launch77-shared/lib-design-system')],
58
+ // ... rest of config
59
+ }
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ After installation:
65
+
66
+ 1. **Test the design system**
67
+
68
+ ```bash
69
+ npm run dev
70
+ # Visit http://localhost:3000/design-system-test
71
+ ```
72
+
73
+ 2. **Customize your brand colors**
74
+
75
+ Edit `src/modules/design-system/config/brand.css`:
76
+
77
+ ```css
78
+ :root {
79
+ /* Your brand's primary color */
80
+ --color-primary: 158 64% 52%;
81
+ --color-primary-foreground: 0 0% 100%;
82
+ }
83
+
84
+ .dark {
85
+ /* Dark mode overrides */
86
+ --color-primary: 158 64% 52%;
87
+ }
88
+ ```
89
+
90
+ 3. **Start building with semantic tokens**
91
+ ```tsx
92
+ <button className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg px-4 py-2">Primary Action</button>
93
+ ```
94
+
95
+ ## Available Tokens
96
+
97
+ The design system provides semantic color tokens:
98
+
99
+ - `background` / `foreground` - Main app background and text
100
+ - `primary` / `primary-foreground` - Brand color
101
+ - `secondary` / `secondary-foreground` - Secondary actions
102
+ - `accent` / `accent-foreground` - Accent/highlight color
103
+ - `muted` / `muted-foreground` - Subtle backgrounds
104
+ - `destructive` / `destructive-foreground` - Errors/warnings
105
+ - `card` / `card-foreground` - Card backgrounds
106
+ - `border` - Border color
107
+ - `input` - Input border color
108
+ - `ring` - Focus ring color
109
+
110
+ Use with Tailwind utilities:
111
+
112
+ ```tsx
113
+ <div className="bg-card text-card-foreground border border-border rounded-lg p-6">
114
+ <p className="text-muted-foreground">Subtle text</p>
115
+ </div>
116
+ ```
117
+
118
+ ## Alpha Channel Support
119
+
120
+ All colors support Tailwind's alpha channel syntax:
121
+
122
+ ```tsx
123
+ <div className="bg-primary/10">10% opacity</div>
124
+ <div className="bg-primary/20">20% opacity</div>
125
+ <button className="bg-primary/90 hover:bg-primary">Hover effect</button>
126
+ ```
127
+
128
+ ## Dark Mode
129
+
130
+ Toggle dark mode by adding/removing `.dark` class on `<html>`:
131
+
132
+ ```tsx
133
+ 'use client'
134
+
135
+ export function DarkModeToggle() {
136
+ const toggleDark = () => {
137
+ document.documentElement.classList.toggle('dark')
138
+ }
139
+
140
+ return <button onClick={toggleDark}>Toggle Dark Mode</button>
141
+ }
142
+ ```
143
+
144
+ ## Animations
145
+
146
+ Built-in animations available as Tailwind utilities:
147
+
148
+ - `animate-fade-in` / `animate-fade-out`
149
+ - `animate-slide-in-from-top` / `-bottom` / `-left` / `-right`
150
+ - `animate-accordion-down` / `animate-accordion-up`
151
+
152
+ All animations respect `prefers-reduced-motion` preferences.
153
+
154
+ ## shadcn/ui Integration
155
+
156
+ This design system follows shadcn/ui's token architecture. To add shadcn components:
157
+
158
+ ```bash
159
+ npx shadcn@latest init
160
+ npx shadcn@latest add button
161
+ npx shadcn@latest add card
162
+ ```
163
+
164
+ Components will automatically use your theme tokens.
165
+
166
+ ## Documentation
167
+
168
+ For detailed documentation, see:
169
+
170
+ - Module README: `src/modules/design-system/README.md` (installed with plugin)
171
+ - Library README: `@launch77-shared/lib-design-system` package
172
+
173
+ ## Development
174
+
175
+ ### Building the Plugin
176
+
177
+ ```bash
178
+ npm run build
179
+ ```
180
+
181
+ Compiles TypeScript to `dist/generator.js`.
182
+
183
+ ### Testing Changes
184
+
185
+ 1. Build the plugin: `npm run build`
186
+ 2. Install in a test app: `launch77 plugin:install design-system`
187
+ 3. Verify all features work
188
+
189
+ ### Type Checking
190
+
191
+ ```bash
192
+ npm run typecheck
193
+ ```
194
+
195
+ ## Architecture
196
+
197
+ This plugin uses the `StandardGenerator` pattern:
198
+
199
+ 1. **updateDependencies()** - Reads `plugin.json`, merges into app's `package.json`
200
+ 2. **installDependencies()** - Runs `npm install` at workspace root
201
+ 3. **copyTemplates()** - Copies `templates/` to app
202
+ 4. **injectCode()** - Surgical code edits (CSS imports, Tailwind preset)
203
+
204
+ All operations are idempotent - safe to run multiple times.
205
+
206
+ ## Template Files
207
+
208
+ The `templates/` directory contains:
209
+
210
+ ```
211
+ templates/
212
+ ├── app/
213
+ │ └── design-system-test/
214
+ │ └── page.tsx # Comprehensive test page
215
+ └── src/
216
+ └── modules/
217
+ └── design-system/
218
+ ├── config/
219
+ │ └── brand.css # Brand customization
220
+ └── README.md # Module documentation
221
+ ```
222
+
223
+ ## Troubleshooting
224
+
225
+ ### Colors Not Applying
226
+
227
+ 1. Verify CSS imports in `app/globals.css`
228
+ 2. Check Tailwind preset in `tailwind.config.ts`
229
+ 3. Restart dev server
230
+
231
+ ### Dark Mode Not Working
232
+
233
+ 1. Ensure `.dark` class is on `<html>` element (not `<body>`)
234
+ 2. Check browser DevTools to verify class is applied
235
+
236
+ ### Build Errors
237
+
238
+ 1. Run `npm install` at workspace root
239
+ 2. Verify `@launch77-shared/lib-design-system` in package.json
240
+ 3. Restart dev server
241
+
242
+ ## License
243
+
244
+ UNLICENSED
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/generator.ts
4
+ import * as path from "path";
5
+ import chalk from "chalk";
6
+ import { StandardGenerator } from "@launch77/plugin-runtime";
7
+
8
+ // src/utils/config-modifier.ts
9
+ import fs from "fs/promises";
10
+ async function addTailwindPreset(filePath, presetRequire) {
11
+ try {
12
+ const fileExists = await fs.access(filePath).then(() => true).catch(() => false);
13
+ if (!fileExists) {
14
+ return {
15
+ success: false,
16
+ error: `File not found: ${filePath}`
17
+ };
18
+ }
19
+ const content = await fs.readFile(filePath, "utf-8");
20
+ if (content.includes(presetRequire)) {
21
+ return {
22
+ success: true,
23
+ alreadyExists: true
24
+ };
25
+ }
26
+ const lines = content.split("\n");
27
+ let configStartIndex = -1;
28
+ let presetsIndex = -1;
29
+ let indentation = " ";
30
+ for (let i = 0; i < lines.length; i++) {
31
+ const line = lines[i];
32
+ if (line.includes("satisfies Config") || line.includes(": Config =")) {
33
+ configStartIndex = i;
34
+ for (let j = i + 1; j < lines.length; j++) {
35
+ const propLine = lines[j];
36
+ const match = propLine.match(/^(\s+)\w+:/);
37
+ if (match) {
38
+ indentation = match[1];
39
+ break;
40
+ }
41
+ }
42
+ }
43
+ if (line.includes("presets:")) {
44
+ presetsIndex = i;
45
+ }
46
+ }
47
+ if (configStartIndex === -1) {
48
+ return {
49
+ success: false,
50
+ error: "Could not find Tailwind config object"
51
+ };
52
+ }
53
+ let newContent;
54
+ if (presetsIndex !== -1) {
55
+ const presetsLine = lines[presetsIndex];
56
+ if (presetsLine.includes("[]")) {
57
+ lines[presetsIndex] = presetsLine.replace("[]", `[${presetRequire}]`);
58
+ } else {
59
+ const openBracketIndex = presetsLine.indexOf("[");
60
+ if (openBracketIndex !== -1) {
61
+ lines[presetsIndex] = presetsLine.slice(0, openBracketIndex + 1) + presetRequire + ", " + presetsLine.slice(openBracketIndex + 1);
62
+ } else {
63
+ return {
64
+ success: false,
65
+ error: "Could not parse existing presets array"
66
+ };
67
+ }
68
+ }
69
+ newContent = lines.join("\n");
70
+ } else {
71
+ let insertIndex = configStartIndex + 1;
72
+ if (lines[configStartIndex].includes("{")) {
73
+ } else {
74
+ while (insertIndex < lines.length && !lines[insertIndex].includes("{")) {
75
+ insertIndex++;
76
+ }
77
+ insertIndex++;
78
+ }
79
+ const presetsLine = `${indentation}presets: [${presetRequire}],`;
80
+ lines.splice(insertIndex, 0, presetsLine);
81
+ newContent = lines.join("\n");
82
+ }
83
+ await fs.writeFile(filePath, newContent, "utf-8");
84
+ return {
85
+ success: true
86
+ };
87
+ } catch (error) {
88
+ return {
89
+ success: false,
90
+ error: error instanceof Error ? error.message : String(error)
91
+ };
92
+ }
93
+ }
94
+
95
+ // src/utils/css-modifier.ts
96
+ import fs2 from "fs/promises";
97
+ async function insertCssImports(filePath, imports) {
98
+ try {
99
+ const fileExists = await fs2.access(filePath).then(() => true).catch(() => false);
100
+ if (!fileExists) {
101
+ return {
102
+ success: false,
103
+ error: `File not found: ${filePath}`
104
+ };
105
+ }
106
+ const content = await fs2.readFile(filePath, "utf-8");
107
+ const allImportsExist = imports.every((importLine) => content.includes(importLine));
108
+ if (allImportsExist) {
109
+ return {
110
+ success: true,
111
+ alreadyExists: true
112
+ };
113
+ }
114
+ const lines = content.split("\n");
115
+ let lastTailwindIndex = -1;
116
+ for (let i = 0; i < lines.length; i++) {
117
+ if (lines[i].trim().startsWith("@tailwind")) {
118
+ lastTailwindIndex = i;
119
+ }
120
+ }
121
+ if (lastTailwindIndex === -1) {
122
+ return {
123
+ success: false,
124
+ error: "Could not find @tailwind directives"
125
+ };
126
+ }
127
+ const importsToAdd = imports.filter((importLine) => !content.includes(importLine));
128
+ if (importsToAdd.length === 0) {
129
+ return {
130
+ success: true,
131
+ alreadyExists: true
132
+ };
133
+ }
134
+ const before = lines.slice(0, lastTailwindIndex + 1);
135
+ const after = lines.slice(lastTailwindIndex + 1);
136
+ const newContent = [...before, "", "/* Launch77 Design System */", ...importsToAdd, ...after].join("\n");
137
+ await fs2.writeFile(filePath, newContent, "utf-8");
138
+ return {
139
+ success: true
140
+ };
141
+ } catch (error) {
142
+ return {
143
+ success: false,
144
+ error: error instanceof Error ? error.message : String(error)
145
+ };
146
+ }
147
+ }
148
+
149
+ // src/generator.ts
150
+ var DesignSystemGenerator = class extends StandardGenerator {
151
+ constructor(context) {
152
+ super(context);
153
+ }
154
+ async injectCode() {
155
+ console.log(chalk.cyan("\u{1F527} Configuring design system...\n"));
156
+ await this.updateGlobalsCss();
157
+ await this.updateTailwindConfig();
158
+ }
159
+ async updateGlobalsCss() {
160
+ const globalsCssPath = path.join(this.context.appPath, "app/globals.css");
161
+ const result = await insertCssImports(globalsCssPath, ["@import '@launch77-shared/lib-design-system/tokens.css';", "@import '../src/modules/design-system/config/brand.css';"]);
162
+ if (result.success) {
163
+ if (result.alreadyExists) {
164
+ console.log(chalk.gray(" \u2713 CSS imports already exist in app/globals.css"));
165
+ } else {
166
+ console.log(chalk.green(" \u2713 Added CSS imports to app/globals.css"));
167
+ }
168
+ } else {
169
+ console.log(chalk.yellow(` \u26A0\uFE0F Could not auto-configure app/globals.css: ${result.error}`));
170
+ console.log(chalk.gray(" You will need to add imports manually"));
171
+ }
172
+ }
173
+ async updateTailwindConfig() {
174
+ const tailwindConfigPath = path.join(this.context.appPath, "tailwind.config.ts");
175
+ const result = await addTailwindPreset(tailwindConfigPath, "require('@launch77-shared/lib-design-system')");
176
+ if (result.success) {
177
+ if (result.alreadyExists) {
178
+ console.log(chalk.gray(" \u2713 Design system preset already exists in tailwind.config.ts"));
179
+ } else {
180
+ console.log(chalk.green(" \u2713 Added design system preset to tailwind.config.ts"));
181
+ }
182
+ } else {
183
+ console.log(chalk.yellow(` \u26A0\uFE0F Could not auto-configure tailwind.config.ts: ${result.error}`));
184
+ console.log(chalk.gray(" You will need to add preset manually"));
185
+ }
186
+ }
187
+ showNextSteps() {
188
+ console.log(chalk.bold.green("\n\u2705 Plugin installed successfully!\n"));
189
+ console.log(chalk.bold("Next Steps:\n"));
190
+ console.log("1. Test your design system:");
191
+ console.log(chalk.cyan(" Visit http://localhost:3000/design-system-test\n"));
192
+ console.log("2. Customize your brand:");
193
+ console.log(chalk.cyan(" Edit src/modules/design-system/config/brand.css\n"));
194
+ }
195
+ };
196
+ async function main() {
197
+ const args = process.argv.slice(2);
198
+ const appPath = args.find((arg) => arg.startsWith("--appPath="))?.split("=")[1];
199
+ const appName = args.find((arg) => arg.startsWith("--appName="))?.split("=")[1];
200
+ const workspaceName = args.find((arg) => arg.startsWith("--workspaceName="))?.split("=")[1];
201
+ const pluginPath = args.find((arg) => arg.startsWith("--pluginPath="))?.split("=")[1];
202
+ if (!appPath || !appName || !workspaceName || !pluginPath) {
203
+ console.error(chalk.red("Error: Missing required arguments"));
204
+ console.error("Usage: generate --appPath=<path> --appName=<name> --workspaceName=<workspace> --pluginPath=<path>");
205
+ process.exit(1);
206
+ }
207
+ const generator = new DesignSystemGenerator({ appPath, appName, workspaceName, pluginPath });
208
+ await generator.run();
209
+ }
210
+ if (import.meta.url === `file://${process.argv[1]}`) {
211
+ main().catch((error) => {
212
+ console.error(chalk.red("\n\u274C Error during design system setup:"));
213
+ console.error(error);
214
+ process.exit(1);
215
+ });
216
+ }
217
+ export {
218
+ DesignSystemGenerator
219
+ };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@launch77-shared/plugin-design-system",
3
+ "version": "1.0.0",
4
+ "description": "Launch77 design system plugin - Setup design tokens and Tailwind preset for elegant web applications",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "main": "dist/generator.js",
8
+ "bin": {
9
+ "generate": "./dist/generator.js"
10
+ },
11
+ "files": [
12
+ "dist/",
13
+ "templates/",
14
+ "plugin.json"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsup --watch",
19
+ "typecheck": "tsc --noEmit",
20
+ "lint": "eslint src/**/*.ts",
21
+ "release:connect": "launch77-release-connect",
22
+ "release:verify": "launch77-release-verify"
23
+ },
24
+ "dependencies": {
25
+ "@launch77-shared/lib-design-system": "^0.1.0",
26
+ "@launch77/plugin-runtime": "^0.2.0",
27
+ "chalk": "^5.3.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^20.10.0",
31
+ "tsup": "^8.0.0",
32
+ "typescript": "^5.3.0"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "launch77": {
38
+ "installedPlugins": {
39
+ "release": {
40
+ "package": "release",
41
+ "version": "1.0.0",
42
+ "installedAt": "2026-01-22T23:35:14.175Z",
43
+ "source": "local"
44
+ }
45
+ }
46
+ }
47
+ }
package/plugin.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "design-system",
3
+ "version": "1.0.0",
4
+ "description": "Launch77 design system - Token-driven theming foundation with Tailwind preset",
5
+ "targets": ["app", "library"],
6
+ "pluginDependencies": {},
7
+ "libraryDependencies": {
8
+ "@launch77-shared/lib-design-system": "^0.1.0"
9
+ }
10
+ }
@@ -0,0 +1,203 @@
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+
5
+ export default function DesignSystemTest() {
6
+ const [isDark, setIsDark] = useState(false)
7
+
8
+ const toggleDark = () => {
9
+ if (isDark) {
10
+ document.documentElement.classList.remove('dark')
11
+ } else {
12
+ document.documentElement.classList.add('dark')
13
+ }
14
+ setIsDark(!isDark)
15
+ }
16
+
17
+ return (
18
+ <div className="min-h-screen bg-background text-foreground p-8">
19
+ {/* Header */}
20
+ <header className="max-w-6xl mx-auto mb-12">
21
+ <div className="flex items-center justify-between mb-6">
22
+ <h1 className="text-4xl font-bold">Design System Test</h1>
23
+ <button onClick={toggleDark} className="px-4 py-2 rounded-lg bg-secondary text-secondary-foreground hover:bg-secondary/80 transition-colors">
24
+ {isDark ? '☀️ Light Mode' : '🌙 Dark Mode'}
25
+ </button>
26
+ </div>
27
+ <p className="text-muted-foreground">Testing all features of @launch77-shared/lib-design-system</p>
28
+ </header>
29
+
30
+ <div className="max-w-6xl mx-auto space-y-12">
31
+ {/* Color Tokens */}
32
+ <section>
33
+ <h2 className="text-2xl font-bold mb-6">Semantic Color Tokens</h2>
34
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
35
+ <ColorCard name="Background" className="bg-background text-foreground border border-border" />
36
+ <ColorCard name="Primary" className="bg-primary text-primary-foreground" />
37
+ <ColorCard name="Secondary" className="bg-secondary text-secondary-foreground" />
38
+ <ColorCard name="Accent" className="bg-accent text-accent-foreground" />
39
+ <ColorCard name="Muted" className="bg-muted text-muted-foreground" />
40
+ <ColorCard name="Destructive" className="bg-destructive text-destructive-foreground" />
41
+ <ColorCard name="Card" className="bg-card text-card-foreground border border-border" />
42
+ </div>
43
+ </section>
44
+
45
+ {/* Alpha Channel Support */}
46
+ <section>
47
+ <h2 className="text-2xl font-bold mb-6">Alpha Channel Support</h2>
48
+ <div className="grid grid-cols-2 md:grid-cols-5 gap-4">
49
+ <div className="bg-primary/10 text-primary p-4 rounded-lg text-center">10%</div>
50
+ <div className="bg-primary/20 text-primary p-4 rounded-lg text-center">20%</div>
51
+ <div className="bg-primary/40 text-primary p-4 rounded-lg text-center">40%</div>
52
+ <div className="bg-primary/60 text-primary p-4 rounded-lg text-center">60%</div>
53
+ <div className="bg-primary/80 text-primary p-4 rounded-lg text-center">80%</div>
54
+ </div>
55
+ </section>
56
+
57
+ {/* Buttons */}
58
+ <section>
59
+ <h2 className="text-2xl font-bold mb-6">Button Variants</h2>
60
+ <div className="flex flex-wrap gap-4">
61
+ <button className="px-6 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors">Primary</button>
62
+ <button className="px-6 py-2 rounded-lg bg-secondary text-secondary-foreground hover:bg-secondary/80 transition-colors">Secondary</button>
63
+ <button className="px-6 py-2 rounded-lg bg-destructive text-destructive-foreground hover:bg-destructive/90 transition-colors">Destructive</button>
64
+ <button className="px-6 py-2 rounded-lg border border-input bg-background hover:bg-accent transition-colors">Outline</button>
65
+ <button className="px-6 py-2 hover:bg-accent hover:text-accent-foreground transition-colors rounded-lg">Ghost</button>
66
+ </div>
67
+ </section>
68
+
69
+ {/* Border Radius */}
70
+ <section>
71
+ <h2 className="text-2xl font-bold mb-6">Border Radius Scale</h2>
72
+ <div className="flex flex-wrap gap-4">
73
+ <div className="bg-primary text-primary-foreground p-6 rounded-sm">rounded-sm</div>
74
+ <div className="bg-primary text-primary-foreground p-6 rounded-md">rounded-md</div>
75
+ <div className="bg-primary text-primary-foreground p-6 rounded-lg">rounded-lg</div>
76
+ </div>
77
+ </section>
78
+
79
+ {/* Animations */}
80
+ <section>
81
+ <h2 className="text-2xl font-bold mb-6">Animations</h2>
82
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
83
+ <AnimationDemo name="Fade In" className="animate-fade-in" />
84
+ <AnimationDemo name="Slide from Top" className="animate-slide-in-from-top" />
85
+ <AnimationDemo name="Slide from Bottom" className="animate-slide-in-from-bottom" />
86
+ <AnimationDemo name="Slide from Left" className="animate-slide-in-from-left" />
87
+ <AnimationDemo name="Slide from Right" className="animate-slide-in-from-right" />
88
+ </div>
89
+ </section>
90
+
91
+ {/* Form Elements */}
92
+ <section>
93
+ <h2 className="text-2xl font-bold mb-6">Form Elements</h2>
94
+ <div className="space-y-4 max-w-md">
95
+ <div>
96
+ <label className="block text-sm font-medium mb-2">Input Field</label>
97
+ <input type="text" placeholder="Enter text..." className="w-full px-3 py-2 rounded-md border border-input bg-background ring-offset-background focus-visible:ring-2 focus-visible:ring-ring" />
98
+ </div>
99
+ <div>
100
+ <label className="block text-sm font-medium mb-2">Textarea</label>
101
+ <textarea placeholder="Enter multiline text..." rows={4} className="w-full px-3 py-2 rounded-md border border-input bg-background ring-offset-background focus-visible:ring-2 focus-visible:ring-ring" />
102
+ </div>
103
+ <div>
104
+ <label className="block text-sm font-medium mb-2">Select</label>
105
+ <select className="w-full px-3 py-2 rounded-md border border-input bg-background ring-offset-background focus-visible:ring-2 focus-visible:ring-ring">
106
+ <option>Option 1</option>
107
+ <option>Option 2</option>
108
+ <option>Option 3</option>
109
+ </select>
110
+ </div>
111
+ </div>
112
+ </section>
113
+
114
+ {/* Cards */}
115
+ <section>
116
+ <h2 className="text-2xl font-bold mb-6">Cards</h2>
117
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
118
+ <div className="bg-card text-card-foreground p-6 rounded-lg border border-border">
119
+ <h3 className="text-lg font-semibold mb-2">Card Title</h3>
120
+ <p className="text-muted-foreground">This is a card component using semantic tokens.</p>
121
+ </div>
122
+ <div className="bg-card text-card-foreground p-6 rounded-lg border border-border">
123
+ <h3 className="text-lg font-semibold mb-2">Another Card</h3>
124
+ <p className="text-muted-foreground">Cards adapt to dark mode automatically.</p>
125
+ </div>
126
+ <div className="bg-card text-card-foreground p-6 rounded-lg border border-border">
127
+ <h3 className="text-lg font-semibold mb-2">Third Card</h3>
128
+ <p className="text-muted-foreground">All using the same semantic tokens.</p>
129
+ </div>
130
+ </div>
131
+ </section>
132
+
133
+ {/* Typography */}
134
+ <section>
135
+ <h2 className="text-2xl font-bold mb-6">Typography</h2>
136
+ <div className="space-y-4">
137
+ <h1 className="text-4xl font-bold">Heading 1</h1>
138
+ <h2 className="text-3xl font-bold">Heading 2</h2>
139
+ <h3 className="text-2xl font-bold">Heading 3</h3>
140
+ <p className="text-base">This is regular body text using the foreground color.</p>
141
+ <p className="text-muted-foreground">This is muted text for secondary information.</p>
142
+ <p className="text-sm text-muted-foreground">Small text for captions and helper text.</p>
143
+ </div>
144
+ </section>
145
+
146
+ {/* Accessibility Features */}
147
+ <section>
148
+ <h2 className="text-2xl font-bold mb-6">Accessibility Features</h2>
149
+ <div className="space-y-4">
150
+ <div className="bg-muted p-4 rounded-lg">
151
+ <h3 className="font-semibold mb-2">✅ Focus Rings</h3>
152
+ <p className="text-sm text-muted-foreground mb-2">Tab through these buttons to see accessible focus rings:</p>
153
+ <div className="flex gap-2">
154
+ <button className="px-4 py-2 bg-primary text-primary-foreground rounded-lg">Button 1</button>
155
+ <button className="px-4 py-2 bg-secondary text-secondary-foreground rounded-lg">Button 2</button>
156
+ <button className="px-4 py-2 bg-accent text-accent-foreground rounded-lg">Button 3</button>
157
+ </div>
158
+ </div>
159
+
160
+ <div className="bg-muted p-4 rounded-lg">
161
+ <h3 className="font-semibold mb-2">✅ Minimum Tap Targets</h3>
162
+ <p className="text-sm text-muted-foreground">All interactive elements have minimum 44x44px tap targets (WCAG AAA).</p>
163
+ </div>
164
+
165
+ <div className="bg-muted p-4 rounded-lg">
166
+ <h3 className="font-semibold mb-2">✅ Reduced Motion Support</h3>
167
+ <p className="text-sm text-muted-foreground">Animations respect prefers-reduced-motion preferences.</p>
168
+ </div>
169
+
170
+ <div className="bg-muted p-4 rounded-lg">
171
+ <h3 className="font-semibold mb-2">✅ Smooth Scrolling</h3>
172
+ <p className="text-sm text-muted-foreground">Smooth scrolling enabled (respects reduced motion).</p>
173
+ </div>
174
+ </div>
175
+ </section>
176
+ </div>
177
+ </div>
178
+ )
179
+ }
180
+
181
+ function ColorCard({ name, className }: { name: string; className: string }) {
182
+ return (
183
+ <div className={`p-6 rounded-lg ${className}`}>
184
+ <div className="font-semibold">{name}</div>
185
+ <div className="text-sm opacity-75 mt-1">Semantic token</div>
186
+ </div>
187
+ )
188
+ }
189
+
190
+ function AnimationDemo({ name, className }: { name: string; className: string }) {
191
+ const [key, setKey] = useState(0)
192
+
193
+ return (
194
+ <div className="bg-muted p-4 rounded-lg">
195
+ <div key={key} className={`bg-primary text-primary-foreground p-4 rounded-md mb-2 ${className}`}>
196
+ {name}
197
+ </div>
198
+ <button onClick={() => setKey((k) => k + 1)} className="text-sm px-3 py-1 bg-secondary text-secondary-foreground rounded hover:bg-secondary/80 transition-colors">
199
+ Replay
200
+ </button>
201
+ </div>
202
+ )
203
+ }
File without changes
@@ -0,0 +1,318 @@
1
+ # Launch77 Design System
2
+
3
+ Token-driven design system providing a consistent theming foundation for your application.
4
+
5
+ ## Features
6
+
7
+ - 🎨 **Semantic Design Tokens** - HSL-format CSS custom properties
8
+ - 🌗 **Dark Mode** - Complete dark mode support via `.dark` class
9
+ - ⚡ **Tailwind Integration** - Preset with all theme colors and utilities
10
+ - ♿ **Accessibility** - Focus rings, reduced motion, minimum tap targets
11
+ - 🎬 **Animations** - 8 built-in keyframe animations
12
+ - 🎯 **Brand Customization** - Simple CSS override system
13
+ - 🔧 **shadcn Compatible** - Follows shadcn/ui token architecture
14
+
15
+ ## Quick Start
16
+
17
+ The plugin has already configured your app with:
18
+
19
+ 1. ✅ Tailwind preset in `tailwind.config.ts`
20
+ 2. ✅ Token imports in `app/globals.css`
21
+ 3. ✅ Brand customization file at `src/modules/design-system/config/brand.css`
22
+
23
+ You're ready to start using the design system immediately!
24
+
25
+ ## Testing
26
+
27
+ Visit the test page to see all design tokens in action:
28
+
29
+ ```bash
30
+ npm run dev
31
+ # Navigate to http://localhost:3000/design-system-test
32
+ ```
33
+
34
+ The test page demonstrates:
35
+
36
+ - All semantic color tokens
37
+ - Alpha channel support
38
+ - Button variants
39
+ - Form elements
40
+ - Cards
41
+ - Typography
42
+ - Animations
43
+ - Accessibility features
44
+ - Dark mode toggle
45
+
46
+ ## Customizing Your Brand
47
+
48
+ Edit `src/modules/design-system/config/brand.css` to override colors:
49
+
50
+ ```css
51
+ :root {
52
+ /* Your brand's primary color */
53
+ --color-primary: 158 64% 52%;
54
+ --color-primary-foreground: 0 0% 100%;
55
+
56
+ /* Your brand's accent color */
57
+ --color-accent: 156 72% 72%;
58
+ }
59
+
60
+ .dark {
61
+ /* Dark mode overrides */
62
+ --color-primary: 158 64% 52%;
63
+ }
64
+ ```
65
+
66
+ ### HSL Color Format
67
+
68
+ Colors use HSL format: `Hue Saturation% Lightness%`
69
+
70
+ - **Hue**: 0-360 (color wheel position)
71
+ - **Saturation**: 0-100% (color intensity)
72
+ - **Lightness**: 0-100% (brightness)
73
+
74
+ Benefits:
75
+
76
+ - Alpha channel support: `bg-primary/20` for 20% opacity
77
+ - Easy to adjust (change lightness for variations)
78
+ - Compatible with color pickers
79
+
80
+ ### Finding HSL Values
81
+
82
+ Use any color picker tool:
83
+
84
+ - https://hslpicker.com
85
+ - Browser DevTools color picker
86
+ - Design tools (Figma, Sketch, etc.)
87
+
88
+ ## Available Tokens
89
+
90
+ ### Color Tokens
91
+
92
+ ```css
93
+ --color-background /* Main app background */
94
+ --color-foreground /* Main text color */
95
+
96
+ --color-primary /* Brand color */
97
+ --color-primary-foreground
98
+
99
+ --color-secondary /* Secondary actions */
100
+ --color-secondary-foreground
101
+
102
+ --color-accent /* Accent/highlight color */
103
+ --color-accent-foreground
104
+
105
+ --color-muted /* Subtle backgrounds */
106
+ --color-muted-foreground
107
+
108
+ --color-destructive /* Errors/destructive actions */
109
+ --color-destructive-foreground
110
+
111
+ --color-card /* Card backgrounds */
112
+ --color-card-foreground
113
+
114
+ --color-border /* Border color */
115
+ --color-input /* Input border color */
116
+ --color-ring /* Focus ring color */
117
+ ```
118
+
119
+ ### Border Radius
120
+
121
+ ```css
122
+ --radius: 1rem /* Base radius (16px) */;
123
+ ```
124
+
125
+ Tailwind utilities:
126
+
127
+ - `rounded-lg` → `var(--radius)`
128
+ - `rounded-md` → `calc(var(--radius) - 2px)`
129
+ - `rounded-sm` → `calc(var(--radius) - 4px)`
130
+
131
+ ## Usage Examples
132
+
133
+ ### Buttons
134
+
135
+ ```tsx
136
+ <button className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg px-4 py-2">
137
+ Primary Action
138
+ </button>
139
+
140
+ <button className="bg-secondary text-secondary-foreground hover:bg-secondary/80 rounded-lg px-4 py-2">
141
+ Secondary Action
142
+ </button>
143
+ ```
144
+
145
+ ### Cards
146
+
147
+ ```tsx
148
+ <div className="bg-card text-card-foreground border border-border rounded-lg p-6">
149
+ <h2 className="text-xl font-bold mb-2">Card Title</h2>
150
+ <p className="text-muted-foreground">Card description text</p>
151
+ </div>
152
+ ```
153
+
154
+ ### Form Inputs
155
+
156
+ ```tsx
157
+ <input type="text" className="w-full px-3 py-2 rounded-md border border-input bg-background focus-visible:ring-2 focus-visible:ring-ring" placeholder="Enter text..." />
158
+ ```
159
+
160
+ ### Alpha Channel
161
+
162
+ ```tsx
163
+ {/* Light backgrounds */}
164
+ <div className="bg-primary/10 text-primary">10% opacity</div>
165
+ <div className="bg-primary/20 text-primary">20% opacity</div>
166
+
167
+ {/* Hover effects */}
168
+ <button className="bg-primary/90 hover:bg-primary">
169
+ Hover me
170
+ </button>
171
+ ```
172
+
173
+ ## Dark Mode
174
+
175
+ Toggle dark mode by adding/removing `.dark` class on `<html>`:
176
+
177
+ ```tsx
178
+ 'use client'
179
+
180
+ export function DarkModeToggle() {
181
+ const toggleDark = () => {
182
+ document.documentElement.classList.toggle('dark')
183
+ }
184
+
185
+ return <button onClick={toggleDark}>Toggle Dark Mode</button>
186
+ }
187
+ ```
188
+
189
+ ### Persisting User Preference
190
+
191
+ ```tsx
192
+ // Save to localStorage
193
+ const toggleDark = () => {
194
+ const isDark = document.documentElement.classList.toggle('dark')
195
+ localStorage.setItem('theme', isDark ? 'dark' : 'light')
196
+ }
197
+
198
+ // Restore on mount
199
+ useEffect(() => {
200
+ const theme = localStorage.getItem('theme')
201
+ if (theme === 'dark') {
202
+ document.documentElement.classList.add('dark')
203
+ }
204
+ }, [])
205
+ ```
206
+
207
+ ## Animations
208
+
209
+ Use built-in animation utilities:
210
+
211
+ ```tsx
212
+ {/* Fade animations */}
213
+ <div className="animate-fade-in">Fades in</div>
214
+ <div className="animate-fade-out">Fades out</div>
215
+
216
+ {/* Slide animations */}
217
+ <div className="animate-slide-in-from-top">Slides from top</div>
218
+ <div className="animate-slide-in-from-bottom">Slides from bottom</div>
219
+ <div className="animate-slide-in-from-left">Slides from left</div>
220
+ <div className="animate-slide-in-from-right">Slides from right</div>
221
+
222
+ {/* Accordion animations (for Radix UI) */}
223
+ <div className="animate-accordion-down">Expands</div>
224
+ <div className="animate-accordion-up">Collapses</div>
225
+ ```
226
+
227
+ Animations automatically respect `prefers-reduced-motion` preferences.
228
+
229
+ ## shadcn/ui Integration
230
+
231
+ This design system follows shadcn/ui's token architecture. To add shadcn components:
232
+
233
+ ```bash
234
+ npx shadcn@latest init
235
+ npx shadcn@latest add button
236
+ npx shadcn@latest add card
237
+ ```
238
+
239
+ Components will automatically use your theme tokens!
240
+
241
+ ## Troubleshooting
242
+
243
+ ### Colors Not Applying
244
+
245
+ **Issue:** Semantic utilities like `bg-primary` don't work.
246
+
247
+ **Solution:**
248
+
249
+ 1. Verify tokens are imported in `app/globals.css`
250
+ 2. Check Tailwind preset is in `tailwind.config.ts`
251
+ 3. Restart dev server after changes
252
+
253
+ ### Dark Mode Not Working
254
+
255
+ **Issue:** Colors don't change in dark mode.
256
+
257
+ **Solution:**
258
+
259
+ 1. Ensure `.dark` class is on `<html>` element (not `<body>`)
260
+ 2. Check browser DevTools to verify class is applied
261
+ 3. Verify dark mode tokens exist in `tokens.css`
262
+
263
+ ### Brand Colors Not Showing
264
+
265
+ **Issue:** Custom colors in `brand.css` aren't visible.
266
+
267
+ **Solution:**
268
+
269
+ 1. Check import order in `app/globals.css`:
270
+ - Tokens must be imported first
271
+ - Brand CSS must come after
272
+ 2. Verify HSL format: `158 64% 52%` (no `hsl()` wrapper)
273
+ 3. Clear browser cache and rebuild
274
+
275
+ ### Build Errors
276
+
277
+ **Issue:** Build fails with module not found.
278
+
279
+ **Solution:**
280
+
281
+ 1. Run `npm install` at workspace root
282
+ 2. Verify `@launch77-shared/lib-design-system` in package.json
283
+ 3. Restart dev server
284
+
285
+ ## Best Practices
286
+
287
+ ### Do's ✅
288
+
289
+ - Use semantic utilities (`bg-primary`, `text-foreground`)
290
+ - Use alpha channel for transparency (`bg-primary/20`)
291
+ - Keep components neutral (no hardcoded colors)
292
+ - Override tokens in `brand.css` only
293
+
294
+ ### Don'ts ❌
295
+
296
+ - Don't hardcode colors in components
297
+ - Don't use `!important` for overrides
298
+ - Don't modify node_modules
299
+ - Don't skip the design system tokens
300
+
301
+ ## Next Steps
302
+
303
+ 1. **Customize Your Brand** - Edit `brand.css` with your colors
304
+ 2. **Test Thoroughly** - Visit `/design-system-test` and test all features
305
+ 3. **Build Components** - Create reusable components with semantic tokens
306
+ 4. **Add shadcn Components** - Integrate shadcn/ui for pre-built components
307
+ 5. **Set Up Dark Mode** - Implement dark mode toggle with persistence
308
+
309
+ ## Resources
310
+
311
+ - **Library Documentation**: Check node_modules/@launch77-shared/lib-design-system
312
+ - **shadcn/ui**: https://ui.shadcn.com
313
+ - **HSL Color Picker**: https://hslpicker.com
314
+ - **Tailwind CSS**: https://tailwindcss.com
315
+
316
+ ---
317
+
318
+ Need help? Check the design system library README or ask in the Launch77 community.
@@ -0,0 +1,23 @@
1
+ /* Brand Colors */
2
+ /* Customize your theme by overriding CSS variables */
3
+
4
+ :root {
5
+ /* Example: Customize primary color */
6
+ /* --color-primary: 158 64% 52%; */
7
+ /* --color-primary-foreground: 0 0% 100%; */
8
+
9
+ /* Example: Customize accent color */
10
+ /* --color-accent: 25 95% 53%; */
11
+ /* --color-accent-foreground: 0 0% 100%; */
12
+
13
+ /* Example: Customize secondary color */
14
+ /* --color-secondary: 270 50% 40%; */
15
+ /* --color-secondary-foreground: 0 0% 100%; */
16
+ }
17
+
18
+ /* Dark mode overrides */
19
+ .dark {
20
+ /* Example: Customize colors for dark mode */
21
+ /* --color-primary: 158 64% 52%; */
22
+ /* --color-primary-foreground: 240 5.9% 10%; */
23
+ }