@oaysus/cli 0.1.4 → 0.1.5

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.
Files changed (80) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +16 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/switch.d.ts +6 -0
  5. package/dist/commands/switch.d.ts.map +1 -0
  6. package/dist/commands/switch.js +120 -0
  7. package/dist/commands/switch.js.map +1 -0
  8. package/dist/components/App.d.ts +2 -0
  9. package/dist/components/App.d.ts.map +1 -1
  10. package/dist/components/App.js +3 -0
  11. package/dist/components/App.js.map +1 -1
  12. package/dist/lib/shared/auth-middleware.js +1 -1
  13. package/dist/lib/shared/auth-middleware.js.map +1 -1
  14. package/dist/lib/shared/auth.d.ts +8 -0
  15. package/dist/lib/shared/auth.d.ts.map +1 -1
  16. package/dist/lib/shared/auth.js +44 -0
  17. package/dist/lib/shared/auth.js.map +1 -1
  18. package/dist/lib/shared/commands.d.ts.map +1 -1
  19. package/dist/lib/shared/commands.js +4 -0
  20. package/dist/lib/shared/commands.js.map +1 -1
  21. package/dist/screens/SwitchScreen.d.ts +14 -0
  22. package/dist/screens/SwitchScreen.d.ts.map +1 -0
  23. package/dist/screens/SwitchScreen.js +196 -0
  24. package/dist/screens/SwitchScreen.js.map +1 -0
  25. package/dist/screens/WelcomeScreen.d.ts +2 -0
  26. package/dist/screens/WelcomeScreen.d.ts.map +1 -1
  27. package/dist/screens/WelcomeScreen.js +4 -1
  28. package/dist/screens/WelcomeScreen.js.map +1 -1
  29. package/dist/types/index.d.ts +1 -0
  30. package/dist/types/index.d.ts.map +1 -1
  31. package/package.json +3 -2
  32. package/src/templates/react-theme-pack/.storybook/main.ts.template +16 -0
  33. package/src/templates/react-theme-pack/.storybook/preview.ts.template +43 -0
  34. package/src/templates/react-theme-pack/.storybook/utils/schemaToArgTypes.ts.template +92 -0
  35. package/src/templates/react-theme-pack/README.md.template +71 -0
  36. package/src/templates/react-theme-pack/components/example-schema.json.template +24 -0
  37. package/src/templates/react-theme-pack/components/example.stories.tsx.template +29 -0
  38. package/src/templates/react-theme-pack/components/example.tsx.template +30 -0
  39. package/src/templates/react-theme-pack/package.json.template +51 -0
  40. package/src/templates/react-theme-pack/preview/generate.js.template +218 -0
  41. package/src/templates/react-theme-pack/preview/server.js.template +40 -0
  42. package/src/templates/react-theme-pack/shared/types.ts.template +19 -0
  43. package/src/templates/react-theme-pack/shared/utils.ts.template +30 -0
  44. package/src/templates/react-theme-pack/styles/tailwind.css.template +1 -0
  45. package/src/templates/react-theme-pack/tsconfig.json.template +24 -0
  46. package/src/templates/react-theme-pack/vite.config.ts.template +12 -0
  47. package/src/templates/shared/.gitignore.template +46 -0
  48. package/src/templates/shared/postcss.config.js.template +6 -0
  49. package/src/templates/shared/tailwind.config.js.template +11 -0
  50. package/src/templates/svelte-theme-pack/.storybook/main.ts.template +13 -0
  51. package/src/templates/svelte-theme-pack/.storybook/preview.ts.template +40 -0
  52. package/src/templates/svelte-theme-pack/.storybook/utils/schemaToArgTypes.ts.template +107 -0
  53. package/src/templates/svelte-theme-pack/README.md.template +67 -0
  54. package/src/templates/svelte-theme-pack/components/example-schema.json.template +24 -0
  55. package/src/templates/svelte-theme-pack/components/example.stories.ts.template +34 -0
  56. package/src/templates/svelte-theme-pack/components/example.svelte.template +29 -0
  57. package/src/templates/svelte-theme-pack/package.json.template +45 -0
  58. package/src/templates/svelte-theme-pack/preview/generate.js.template +221 -0
  59. package/src/templates/svelte-theme-pack/preview/server.js.template +40 -0
  60. package/src/templates/svelte-theme-pack/shared/types.ts.template +31 -0
  61. package/src/templates/svelte-theme-pack/shared/utils.ts.template +37 -0
  62. package/src/templates/svelte-theme-pack/styles/tailwind.css.template +1 -0
  63. package/src/templates/svelte-theme-pack/svelte.config.js.template +5 -0
  64. package/src/templates/svelte-theme-pack/tsconfig.json.template +27 -0
  65. package/src/templates/svelte-theme-pack/vite.config.ts.template +12 -0
  66. package/src/templates/vue-theme-pack/.storybook/main.ts.template +13 -0
  67. package/src/templates/vue-theme-pack/.storybook/preview.ts.template +40 -0
  68. package/src/templates/vue-theme-pack/.storybook/utils/schemaToArgTypes.ts.template +107 -0
  69. package/src/templates/vue-theme-pack/README.md.template +69 -0
  70. package/src/templates/vue-theme-pack/components/example-schema.json.template +24 -0
  71. package/src/templates/vue-theme-pack/components/example.stories.ts.template +34 -0
  72. package/src/templates/vue-theme-pack/components/example.vue.template +32 -0
  73. package/src/templates/vue-theme-pack/package.json.template +44 -0
  74. package/src/templates/vue-theme-pack/preview/generate.js.template +218 -0
  75. package/src/templates/vue-theme-pack/preview/server.js.template +40 -0
  76. package/src/templates/vue-theme-pack/shared/types.ts.template +31 -0
  77. package/src/templates/vue-theme-pack/shared/utils.ts.template +37 -0
  78. package/src/templates/vue-theme-pack/styles/tailwind.css.template +1 -0
  79. package/src/templates/vue-theme-pack/tsconfig.json.template +27 -0
  80. package/src/templates/vue-theme-pack/vite.config.ts.template +12 -0
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "{{DESCRIPTION}}",
6
+ "author": "{{AUTHOR}}",
7
+ "license": "MIT",
8
+ "scripts": {
9
+ "preview": "node preview/generate.js && node preview/server.js",
10
+ "preview:build": "node preview/generate.js",
11
+ "preview:start": "node preview/server.js",
12
+ "storybook": "storybook dev -p 6006",
13
+ "build-storybook": "storybook build -o storybook-static"
14
+ },
15
+ "peerDependencies": {
16
+ "react": "^19.2.0",
17
+ "react-dom": "^19.2.0"
18
+ },
19
+ "devDependencies": {
20
+ "@storybook/addon-a11y": "^10.1.2",
21
+ "@storybook/react": "^10.1.2",
22
+ "@storybook/react-vite": "^10.1.2",
23
+ "@tailwindcss/cli": "^4.1.17",
24
+ "@tailwindcss/postcss": "^4.1.17",
25
+ "@types/react": "^19.2.7",
26
+ "@types/react-dom": "^19.2.3",
27
+ "@vitejs/plugin-react": "^5.1.1",
28
+ "autoprefixer": "^10.4.22",
29
+ "express": "^5.1.0",
30
+ "postcss": "^8.5.6",
31
+ "react": "^19.2.0",
32
+ "react-dom": "^19.2.0",
33
+ "storybook": "^10.1.2",
34
+ "tailwindcss": "^4.1.17",
35
+ "typescript": "^5.9.3",
36
+ "vite": "^7.2.4"
37
+ },
38
+ "oaysus": {
39
+ "theme": {
40
+ "name": "{{PROJECT_NAME}}-pack",
41
+ "displayName": "{{DISPLAY_NAME}}",
42
+ "description": "{{DESCRIPTION}}",
43
+ "category": "marketing",
44
+ "isPremium": false,
45
+ "tags": ["marketing", "components", "theme", "react", "tailwind"]
46
+ }
47
+ },
48
+ "dependencies": {
49
+ "lucide-react": "^0.555.0"
50
+ }
51
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Preview HTML Generator - React
3
+ * Generates a local preview page that mimics the dashboard's preview-shell.html
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ const BUILD_DIR = path.join(__dirname, '../.oaysus-build');
14
+ const PREVIEW_DIST = path.join(__dirname, 'dist');
15
+ const OUTPUT_HTML = path.join(PREVIEW_DIST, 'index.html');
16
+
17
+ // Ensure preview/dist directory exists
18
+ if (!fs.existsSync(PREVIEW_DIST)) {
19
+ fs.mkdirSync(PREVIEW_DIST, { recursive: true });
20
+ }
21
+
22
+ // Check if build exists
23
+ if (!fs.existsSync(BUILD_DIR)) {
24
+ console.error('❌ Error: .oaysus-build directory not found!');
25
+ console.error(' Run "oaysus build" first to build your components.');
26
+ process.exit(1);
27
+ }
28
+
29
+ // Read all components
30
+ const components = [];
31
+ const componentDirs = fs.readdirSync(BUILD_DIR).filter(dir => {
32
+ const fullPath = path.join(BUILD_DIR, dir);
33
+ return fs.statSync(fullPath).isDirectory() && dir !== 'deps';
34
+ });
35
+
36
+ for (const dir of componentDirs) {
37
+ const schemaPath = path.join(BUILD_DIR, dir, 'schema.json');
38
+ const jsPath = path.join(BUILD_DIR, dir, 'index.js');
39
+
40
+ if (fs.existsSync(schemaPath) && fs.existsSync(jsPath)) {
41
+ const schema = JSON.parse(fs.readFileSync(schemaPath, 'utf-8'));
42
+ components.push({
43
+ name: dir,
44
+ displayName: schema.displayName || dir,
45
+ schema,
46
+ jsPath: `/build/${dir}/index.js`
47
+ });
48
+ }
49
+ }
50
+
51
+ // Read import map
52
+ let importMap = { imports: {} };
53
+ const importMapPath = path.join(BUILD_DIR, 'import-map.json');
54
+ if (fs.existsSync(importMapPath)) {
55
+ importMap = JSON.parse(fs.readFileSync(importMapPath, 'utf-8'));
56
+ }
57
+
58
+ // Convert R2 URLs to local URLs
59
+ const localImportMap = { imports: {} };
60
+ for (const [key, value] of Object.entries(importMap.imports)) {
61
+ // Convert R2 URL to local path
62
+ // Example: https://r2.dev/.../deps/react@18.3.1/index.js → /build/deps/react@18.3.1/index.js
63
+ const match = value.match(/deps\/(.*)/);
64
+ if (match) {
65
+ localImportMap.imports[key] = `/build/deps/${match[1]}`;
66
+ } else {
67
+ localImportMap.imports[key] = value;
68
+ }
69
+ }
70
+
71
+ // Generate HTML
72
+ const html = `<!DOCTYPE html>
73
+ <html lang="en">
74
+ <head>
75
+ <meta charset="UTF-8">
76
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
77
+ <title>Component Preview - {{PROJECT_NAME}}</title>
78
+ <link rel="stylesheet" href="/build/theme.css">
79
+ <style>
80
+ body {
81
+ margin: 0;
82
+ padding: 0;
83
+ }
84
+ </style>
85
+ </head>
86
+ <body>
87
+ ${components.map(comp => `<div id="preview-${comp.name}"></div>`).join('\n ')}
88
+
89
+ <!-- Import Map -->
90
+ <script type="importmap">
91
+ ${JSON.stringify(localImportMap, null, 2)}
92
+ </script>
93
+
94
+ <!-- Component Loading Script -->
95
+ <script type="module">
96
+ // Component configurations
97
+ const components = ${JSON.stringify(components, null, 2)};
98
+
99
+ // Load React and ReactDOM
100
+ let React, ReactDOM;
101
+
102
+ async function loadReact() {
103
+ try {
104
+ const reactModule = await import('react');
105
+ const reactDomModule = await import('react-dom/client');
106
+
107
+ React = reactModule.default || reactModule;
108
+ ReactDOM = reactDomModule.default || reactDomModule;
109
+
110
+ console.log('✅ React loaded:', React);
111
+ console.log('✅ ReactDOM loaded:', ReactDOM);
112
+ } catch (error) {
113
+ console.error('❌ Failed to load React:', error);
114
+ throw error;
115
+ }
116
+ }
117
+
118
+ // Load and render a component
119
+ async function loadComponent(comp) {
120
+ const container = document.getElementById(\`preview-\${comp.name}\`);
121
+
122
+ try {
123
+ console.log(\`Loading component: \${comp.displayName}\`);
124
+
125
+ // Import the component module
126
+ const module = await import(comp.jsPath);
127
+ console.log(\`✅ Loaded module for \${comp.displayName}:\`, module);
128
+
129
+ // Get the component (try default export first, then named)
130
+ const Component = module.default || module[Object.keys(module)[0]];
131
+
132
+ if (!Component) {
133
+ throw new Error('No component export found in module');
134
+ }
135
+
136
+ console.log(\`✅ Component function for \${comp.displayName}:\`, Component);
137
+
138
+ // Get default props from schema
139
+ const defaultProps = {};
140
+ if (comp.schema.props) {
141
+ for (const [key, prop] of Object.entries(comp.schema.props)) {
142
+ if (prop.default !== undefined) {
143
+ defaultProps[key] = prop.default;
144
+ } else if (prop.type === 'object' && prop.properties) {
145
+ // Build nested object from properties
146
+ const nestedObj = {};
147
+ for (const [nestedKey, nestedProp] of Object.entries(prop.properties)) {
148
+ if (nestedProp.default !== undefined) {
149
+ nestedObj[nestedKey] = nestedProp.default;
150
+ }
151
+ }
152
+ if (Object.keys(nestedObj).length > 0) {
153
+ defaultProps[key] = nestedObj;
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ console.log(\`📝 Rendering \${comp.displayName} with props:\`, defaultProps);
160
+
161
+ // Create root and render
162
+ const root = ReactDOM.createRoot(container);
163
+ root.render(React.createElement(Component, defaultProps));
164
+
165
+ console.log(\`✅ Successfully rendered \${comp.displayName}\`);
166
+ } catch (error) {
167
+ console.error(\`❌ Failed to load \${comp.displayName}:\`, error);
168
+ container.innerHTML = \`
169
+ <div class="error">
170
+ <strong>Error loading \${comp.displayName}:</strong><br>
171
+ \${error.message}
172
+ </div>
173
+ \`;
174
+ }
175
+ }
176
+
177
+ // Main execution
178
+ async function main() {
179
+ try {
180
+ console.log('🚀 Starting component preview...');
181
+
182
+ // Load React first
183
+ await loadReact();
184
+
185
+ // Load all components
186
+ for (const comp of components) {
187
+ await loadComponent(comp);
188
+ }
189
+
190
+ console.log('✅ All components loaded successfully!');
191
+ } catch (error) {
192
+ console.error('❌ Preview failed:', error);
193
+ }
194
+ }
195
+
196
+ main();
197
+ </script>
198
+ </body>
199
+ </html>
200
+ `;
201
+
202
+ // Write HTML file
203
+ fs.writeFileSync(OUTPUT_HTML, html);
204
+
205
+ console.log(`
206
+ ✅ Preview HTML generated successfully!
207
+
208
+ 📁 Location: ${OUTPUT_HTML}
209
+
210
+ 🎯 Components found: ${components.length}
211
+ ${components.map(c => ` • ${c.displayName} (${c.name})`).join('\n')}
212
+
213
+ 🚀 Start the preview server with:
214
+ pnpm run preview:start
215
+
216
+ Or run the full preview (generate + serve):
217
+ pnpm run preview
218
+ `);
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Local Preview Server
3
+ * Serves the built components for local testing without uploading to R2
4
+ */
5
+
6
+ import express from 'express';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ const app = express();
14
+ const PORT = 4000;
15
+
16
+ // Serve .oaysus-build directory (component bundles and dependencies)
17
+ app.use('/build', express.static(path.join(__dirname, '../.oaysus-build')));
18
+
19
+ // Serve preview directory (HTML and assets)
20
+ app.use(express.static(path.join(__dirname, 'dist')));
21
+
22
+ // Handle 404s
23
+ app.use((req, res) => {
24
+ res.status(404).send('File not found');
25
+ });
26
+
27
+ // Start server
28
+ app.listen(PORT, () => {
29
+ console.log(`
30
+ ╔════════════════════════════════════════════════════════════╗
31
+ ║ ║
32
+ ║ 🎨 Component Preview Server ║
33
+ ║ ║
34
+ ║ Running at: http://localhost:${PORT} ║
35
+ ║ ║
36
+ ║ Press Ctrl+C to stop the server ║
37
+ ║ ║
38
+ ╚════════════════════════════════════════════════════════════╝
39
+ `);
40
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Shared TypeScript types for {{DISPLAY_NAME}}
3
+ */
4
+
5
+ export interface BaseComponentProps {
6
+ className?: string;
7
+ style?: React.CSSProperties;
8
+ }
9
+
10
+ export interface ButtonProps extends BaseComponentProps {
11
+ text: string;
12
+ link: string;
13
+ variant?: 'primary' | 'secondary';
14
+ }
15
+
16
+ export interface HeadingProps extends BaseComponentProps {
17
+ heading: string;
18
+ subheading?: string;
19
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared utility functions for {{DISPLAY_NAME}}
3
+ */
4
+
5
+ /**
6
+ * Combine class names
7
+ */
8
+ export function cn(...classes: (string | undefined | null | false)[]): string {
9
+ return classes.filter(Boolean).join(' ');
10
+ }
11
+
12
+ /**
13
+ * Format a date string
14
+ */
15
+ export function formatDate(date: Date | string): string {
16
+ const d = typeof date === 'string' ? new Date(date) : date;
17
+ return d.toLocaleDateString('en-US', {
18
+ year: 'numeric',
19
+ month: 'long',
20
+ day: 'numeric'
21
+ });
22
+ }
23
+
24
+ /**
25
+ * Truncate text to a maximum length
26
+ */
27
+ export function truncate(text: string, maxLength: number): string {
28
+ if (text.length <= maxLength) return text;
29
+ return text.slice(0, maxLength - 3) + '...';
30
+ }
@@ -0,0 +1 @@
1
+ @import "tailwindcss";
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
5
+ "jsx": "react-jsx",
6
+ "module": "ESNext",
7
+ "moduleResolution": "bundler",
8
+ "resolveJsonModule": true,
9
+ "allowImportingTsExtensions": false,
10
+ "strict": true,
11
+ "noUnusedLocals": true,
12
+ "noUnusedParameters": true,
13
+ "noFallthroughCasesInSwitch": true,
14
+ "esModuleInterop": true,
15
+ "skipLibCheck": true,
16
+ "forceConsistentCasingInFileNames": true,
17
+ "baseUrl": ".",
18
+ "paths": {
19
+ "@/*": ["./*"]
20
+ }
21
+ },
22
+ "include": ["**/*.ts", "**/*.tsx"],
23
+ "exclude": ["node_modules", "dist"]
24
+ }
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import { resolve } from 'path';
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ resolve: {
8
+ alias: {
9
+ '@': resolve(__dirname, './')
10
+ }
11
+ }
12
+ });
@@ -0,0 +1,46 @@
1
+ # Dependencies
2
+ node_modules/
3
+ pnpm-lock.yaml
4
+ yarn.lock
5
+ package-lock.json
6
+
7
+ # Build outputs
8
+ dist/
9
+ build/
10
+ .next/
11
+ .nuxt/
12
+ .output/
13
+ .oaysus-build/
14
+ storybook-static/
15
+
16
+ # IDE
17
+ .vscode/
18
+ .idea/
19
+ *.swp
20
+ *.swo
21
+ *~
22
+
23
+ # OS
24
+ .DS_Store
25
+ Thumbs.db
26
+
27
+ # Environment
28
+ .env
29
+ .env.local
30
+ .env.*.local
31
+
32
+ # Testing
33
+ coverage/
34
+ .nyc_output/
35
+
36
+ # Logs
37
+ *.log
38
+ npm-debug.log*
39
+ yarn-debug.log*
40
+ yarn-error.log*
41
+ pnpm-debug.log*
42
+
43
+ # Misc
44
+ .cache/
45
+ *.tgz
46
+ *.zip
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ autoprefixer: {},
5
+ },
6
+ }
@@ -0,0 +1,11 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: [
4
+ "./components/**/*.{js,ts,jsx,tsx,vue,svelte}",
5
+ "./shared/**/*.{js,ts,jsx,tsx,vue,svelte}"
6
+ ],
7
+ theme: {
8
+ extend: {},
9
+ },
10
+ plugins: [],
11
+ }
@@ -0,0 +1,13 @@
1
+ import type { StorybookConfig } from '@storybook/svelte-vite';
2
+
3
+ const config: StorybookConfig = {
4
+ stories: ['../components/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
5
+ addons: ['@storybook/addon-a11y'],
6
+ framework: {
7
+ name: '@storybook/svelte-vite',
8
+ options: {}
9
+ },
10
+ docs: {}
11
+ };
12
+
13
+ export default config;
@@ -0,0 +1,40 @@
1
+ import type { Preview } from '@storybook/svelte';
2
+ import '../styles/tailwind.css';
3
+
4
+ const preview: Preview = {
5
+ parameters: {
6
+ controls: {
7
+ matchers: {
8
+ color: /(background|color)$/i,
9
+ date: /Date$/i
10
+ }
11
+ },
12
+ viewport: {
13
+ viewports: {
14
+ mobile: {
15
+ name: 'Mobile',
16
+ styles: { width: '375px', height: '667px' }
17
+ },
18
+ tablet: {
19
+ name: 'Tablet',
20
+ styles: { width: '768px', height: '1024px' }
21
+ },
22
+ desktop: {
23
+ name: 'Desktop',
24
+ styles: { width: '1280px', height: '800px' }
25
+ }
26
+ }
27
+ },
28
+ backgrounds: {
29
+ default: 'light',
30
+ values: [
31
+ { name: 'light', value: '#ffffff' },
32
+ { name: 'dark', value: '#1f2937' },
33
+ { name: 'gray', value: '#f3f4f6' }
34
+ ]
35
+ },
36
+ layout: 'fullscreen'
37
+ }
38
+ };
39
+
40
+ export default preview;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Converts a component schema.json to Storybook ArgTypes
3
+ * This enables automatic control generation from Oaysus component schemas
4
+ */
5
+
6
+ interface SchemaProp {
7
+ type: string;
8
+ displayName?: string;
9
+ description?: string;
10
+ default?: unknown;
11
+ min?: number;
12
+ max?: number;
13
+ step?: number;
14
+ properties?: Record<string, SchemaProp>;
15
+ fields?: Array<{ name: string; type: string; default?: unknown }>;
16
+ }
17
+
18
+ interface ComponentSchema {
19
+ type: string;
20
+ displayName: string;
21
+ description?: string;
22
+ category?: string;
23
+ props: Record<string, SchemaProp>;
24
+ }
25
+
26
+ interface ArgType {
27
+ name?: string;
28
+ description?: string;
29
+ control: { type: string; [key: string]: unknown };
30
+ table?: {
31
+ category?: string;
32
+ defaultValue?: { summary: string };
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Map schema prop type to Storybook control type
38
+ */
39
+ function propTypeToControl(prop: SchemaProp): ArgType['control'] {
40
+ switch (prop.type) {
41
+ case 'color':
42
+ return {
43
+ type: 'color',
44
+ presetColors: ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899']
45
+ };
46
+ case 'range':
47
+ return {
48
+ type: 'range',
49
+ min: prop.min ?? 0,
50
+ max: prop.max ?? 100,
51
+ step: prop.step ?? 1
52
+ };
53
+ case 'number':
54
+ return { type: 'number' };
55
+ case 'boolean':
56
+ return { type: 'boolean' };
57
+ case 'textarea':
58
+ case 'string':
59
+ case 'text':
60
+ case 'link':
61
+ return { type: 'text' };
62
+ case 'image':
63
+ case 'array':
64
+ case 'object':
65
+ return { type: 'object' };
66
+ default:
67
+ return { type: 'text' };
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Convert full schema to Storybook ArgTypes object
73
+ */
74
+ export function schemaToArgTypes(schema: ComponentSchema): Record<string, ArgType> {
75
+ const argTypes: Record<string, ArgType> = {};
76
+
77
+ for (const [propName, propDef] of Object.entries(schema.props)) {
78
+ argTypes[propName] = {
79
+ name: propDef.displayName || propName,
80
+ description: propDef.description || '',
81
+ control: propTypeToControl(propDef),
82
+ table: {
83
+ category: 'Props',
84
+ defaultValue: propDef.default !== undefined
85
+ ? { summary: JSON.stringify(propDef.default) }
86
+ : undefined
87
+ }
88
+ };
89
+ }
90
+
91
+ return argTypes;
92
+ }
93
+
94
+ /**
95
+ * Extract default args from schema for story initialization
96
+ */
97
+ export function schemaToDefaultArgs(schema: ComponentSchema): Record<string, unknown> {
98
+ const args: Record<string, unknown> = {};
99
+
100
+ for (const [propName, propDef] of Object.entries(schema.props)) {
101
+ if (propDef.default !== undefined) {
102
+ args[propName] = propDef.default;
103
+ }
104
+ }
105
+
106
+ return args;
107
+ }
@@ -0,0 +1,67 @@
1
+ # {{DISPLAY_NAME}}
2
+
3
+ {{DESCRIPTION}}
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm install
9
+ ```
10
+
11
+ ## Components
12
+
13
+ This theme pack includes the following Svelte components:
14
+
15
+ ### Hero
16
+ A hero section component with heading, subheading, and CTA button.
17
+
18
+ ### CTA
19
+ A call-to-action component for conversions.
20
+
21
+ ### Testimonials
22
+ A testimonials section to showcase customer reviews.
23
+
24
+ ## Usage
25
+
26
+ ```svelte
27
+ <script>
28
+ import Hero from './components/Hero';
29
+ import CTA from './components/CTA';
30
+ import Testimonials from './components/Testimonials';
31
+ </script>
32
+
33
+ <Hero
34
+ heading="Welcome"
35
+ subheading="Build amazing things"
36
+ buttonText="Get Started"
37
+ buttonLink="/start"
38
+ />
39
+ <Testimonials />
40
+ <CTA />
41
+ ```
42
+
43
+ ## Adding New Components
44
+
45
+ To add a new component to this theme pack:
46
+
47
+ ```bash
48
+ oaysus create component MyComponent
49
+ ```
50
+
51
+ ## Development
52
+
53
+ This theme pack was created using the Oaysus CLI.
54
+
55
+ To validate and package for upload:
56
+
57
+ ```bash
58
+ oaysus validate
59
+ ```
60
+
61
+ ## Author
62
+
63
+ {{AUTHOR}}
64
+
65
+ ## License
66
+
67
+ MIT