@oaysus/cli 0.1.3 → 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.
- package/README.md +87 -95
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/switch.d.ts +6 -0
- package/dist/commands/switch.d.ts.map +1 -0
- package/dist/commands/switch.js +120 -0
- package/dist/commands/switch.js.map +1 -0
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +11 -2
- package/dist/commands/whoami.js.map +1 -1
- package/dist/components/App.d.ts +3 -1
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +4 -1
- package/dist/components/App.js.map +1 -1
- package/dist/components/SlashCommands.js +1 -1
- package/dist/lib/push.d.ts.map +1 -1
- package/dist/lib/push.js +11 -12
- package/dist/lib/push.js.map +1 -1
- package/dist/lib/react/builder.js +5 -5
- package/dist/lib/react/builder.js.map +1 -1
- package/dist/lib/react/bundler.js +2 -2
- package/dist/lib/react/bundler.js.map +1 -1
- package/dist/lib/shared/auth-middleware.js +1 -1
- package/dist/lib/shared/auth-middleware.js.map +1 -1
- package/dist/lib/shared/auth.d.ts +8 -0
- package/dist/lib/shared/auth.d.ts.map +1 -1
- package/dist/lib/shared/auth.js +102 -10
- package/dist/lib/shared/auth.js.map +1 -1
- package/dist/lib/shared/cdn-downloader.js +2 -2
- package/dist/lib/shared/cdn-downloader.js.map +1 -1
- package/dist/lib/shared/commands.d.ts.map +1 -1
- package/dist/lib/shared/commands.js +5 -1
- package/dist/lib/shared/commands.js.map +1 -1
- package/dist/lib/shared/config.d.ts +6 -8
- package/dist/lib/shared/config.d.ts.map +1 -1
- package/dist/lib/shared/config.js +75 -10
- package/dist/lib/shared/config.js.map +1 -1
- package/dist/lib/shared/import-analyzer.js +4 -4
- package/dist/lib/shared/import-analyzer.js.map +1 -1
- package/dist/lib/shared/uploader.d.ts +14 -0
- package/dist/lib/shared/uploader.d.ts.map +1 -1
- package/dist/lib/shared/uploader.js +207 -0
- package/dist/lib/shared/uploader.js.map +1 -1
- package/dist/screens/PushScreen.d.ts.map +1 -1
- package/dist/screens/PushScreen.js +43 -27
- package/dist/screens/PushScreen.js.map +1 -1
- package/dist/screens/SwitchScreen.d.ts +14 -0
- package/dist/screens/SwitchScreen.d.ts.map +1 -0
- package/dist/screens/SwitchScreen.js +196 -0
- package/dist/screens/SwitchScreen.js.map +1 -0
- package/dist/screens/WelcomeScreen.d.ts +3 -1
- package/dist/screens/WelcomeScreen.d.ts.map +1 -1
- package/dist/screens/WelcomeScreen.js +8 -5
- package/dist/screens/WelcomeScreen.js.map +1 -1
- package/dist/screens/WhoamiScreen.d.ts.map +1 -1
- package/dist/screens/WhoamiScreen.js +13 -6
- package/dist/screens/WhoamiScreen.js.map +1 -1
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/templates/react-theme-pack/.storybook/main.ts.template +16 -0
- package/src/templates/react-theme-pack/.storybook/preview.ts.template +43 -0
- package/src/templates/react-theme-pack/.storybook/utils/schemaToArgTypes.ts.template +92 -0
- package/src/templates/react-theme-pack/README.md.template +71 -0
- package/src/templates/react-theme-pack/components/example-schema.json.template +24 -0
- package/src/templates/react-theme-pack/components/example.stories.tsx.template +29 -0
- package/src/templates/react-theme-pack/components/example.tsx.template +30 -0
- package/src/templates/react-theme-pack/package.json.template +51 -0
- package/src/templates/react-theme-pack/preview/generate.js.template +218 -0
- package/src/templates/react-theme-pack/preview/server.js.template +40 -0
- package/src/templates/react-theme-pack/shared/types.ts.template +19 -0
- package/src/templates/react-theme-pack/shared/utils.ts.template +30 -0
- package/src/templates/react-theme-pack/styles/tailwind.css.template +1 -0
- package/src/templates/react-theme-pack/tsconfig.json.template +24 -0
- package/src/templates/react-theme-pack/vite.config.ts.template +12 -0
- package/src/templates/shared/.gitignore.template +46 -0
- package/src/templates/shared/postcss.config.js.template +6 -0
- package/src/templates/shared/tailwind.config.js.template +11 -0
- package/src/templates/svelte-theme-pack/.storybook/main.ts.template +13 -0
- package/src/templates/svelte-theme-pack/.storybook/preview.ts.template +40 -0
- package/src/templates/svelte-theme-pack/.storybook/utils/schemaToArgTypes.ts.template +107 -0
- package/src/templates/svelte-theme-pack/README.md.template +67 -0
- package/src/templates/svelte-theme-pack/components/example-schema.json.template +24 -0
- package/src/templates/svelte-theme-pack/components/example.stories.ts.template +34 -0
- package/src/templates/svelte-theme-pack/components/example.svelte.template +29 -0
- package/src/templates/svelte-theme-pack/package.json.template +45 -0
- package/src/templates/svelte-theme-pack/preview/generate.js.template +221 -0
- package/src/templates/svelte-theme-pack/preview/server.js.template +40 -0
- package/src/templates/svelte-theme-pack/shared/types.ts.template +31 -0
- package/src/templates/svelte-theme-pack/shared/utils.ts.template +37 -0
- package/src/templates/svelte-theme-pack/styles/tailwind.css.template +1 -0
- package/src/templates/svelte-theme-pack/svelte.config.js.template +5 -0
- package/src/templates/svelte-theme-pack/tsconfig.json.template +27 -0
- package/src/templates/svelte-theme-pack/vite.config.ts.template +12 -0
- package/src/templates/vue-theme-pack/.storybook/main.ts.template +13 -0
- package/src/templates/vue-theme-pack/.storybook/preview.ts.template +40 -0
- package/src/templates/vue-theme-pack/.storybook/utils/schemaToArgTypes.ts.template +107 -0
- package/src/templates/vue-theme-pack/README.md.template +69 -0
- package/src/templates/vue-theme-pack/components/example-schema.json.template +24 -0
- package/src/templates/vue-theme-pack/components/example.stories.ts.template +34 -0
- package/src/templates/vue-theme-pack/components/example.vue.template +32 -0
- package/src/templates/vue-theme-pack/package.json.template +44 -0
- package/src/templates/vue-theme-pack/preview/generate.js.template +218 -0
- package/src/templates/vue-theme-pack/preview/server.js.template +40 -0
- package/src/templates/vue-theme-pack/shared/types.ts.template +31 -0
- package/src/templates/vue-theme-pack/shared/utils.ts.template +37 -0
- package/src/templates/vue-theme-pack/styles/tailwind.css.template +1 -0
- package/src/templates/vue-theme-pack/tsconfig.json.template +27 -0
- package/src/templates/vue-theme-pack/vite.config.ts.template +12 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/svelte';
|
|
2
|
+
import {{COMPONENT_NAME}} from './{{COMPONENT_NAME}}.svelte';
|
|
3
|
+
import { schemaToArgTypes, schemaToDefaultArgs } from '../.storybook/utils/schemaToArgTypes';
|
|
4
|
+
import schema from './schema.json';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof {{COMPONENT_NAME}}> = {
|
|
7
|
+
title: 'Components/{{COMPONENT_NAME}}',
|
|
8
|
+
component: {{COMPONENT_NAME}},
|
|
9
|
+
argTypes: schemaToArgTypes(schema),
|
|
10
|
+
args: schemaToDefaultArgs(schema),
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'fullscreen'
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story = StoryObj<typeof {{COMPONENT_NAME}}>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Default story using schema defaults
|
|
21
|
+
*/
|
|
22
|
+
export const Default: Story = {};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Custom example with modified props
|
|
26
|
+
*/
|
|
27
|
+
export const CustomExample: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
heading: 'Custom Heading',
|
|
30
|
+
subheading: 'This is a custom subheading',
|
|
31
|
+
buttonText: 'Click Me',
|
|
32
|
+
buttonLink: '/custom-link'
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// Svelte 5 runes mode - use $props() instead of export let
|
|
3
|
+
interface Props {
|
|
4
|
+
heading?: string;
|
|
5
|
+
subheading?: string;
|
|
6
|
+
buttonText?: string;
|
|
7
|
+
buttonLink?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
heading = 'Welcome',
|
|
12
|
+
subheading = 'Your amazing tagline',
|
|
13
|
+
buttonText = 'Get Started',
|
|
14
|
+
buttonLink = '#'
|
|
15
|
+
}: Props = $props();
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<div class="bg-gradient-to-r from-orange-500 via-pink-500 to-purple-600 text-white py-24 px-4 min-h-[500px] flex items-center justify-center border-8 border-yellow-400 shadow-2xl">
|
|
19
|
+
<div class="max-w-4xl mx-auto text-center">
|
|
20
|
+
<h1 class="text-6xl font-black mb-6 text-white drop-shadow-lg">{heading}</h1>
|
|
21
|
+
<p class="text-2xl mb-10 text-yellow-200 font-semibold">{subheading}</p>
|
|
22
|
+
<a
|
|
23
|
+
href={buttonLink}
|
|
24
|
+
class="inline-block bg-gradient-to-r from-green-400 to-cyan-500 text-white px-8 py-4 rounded-full text-xl font-bold shadow-xl hover:scale-110 hover:rotate-2 transition-all duration-300 cursor-pointer no-underline"
|
|
25
|
+
>
|
|
26
|
+
{buttonText}
|
|
27
|
+
</a>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
"svelte": "^5.43.14"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@storybook/addon-a11y": "^10.1.2",
|
|
20
|
+
"@storybook/svelte": "^10.1.2",
|
|
21
|
+
"@storybook/svelte-vite": "^10.1.2",
|
|
22
|
+
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
|
23
|
+
"@tailwindcss/cli": "^4.1.17",
|
|
24
|
+
"@tailwindcss/postcss": "^4.1.17",
|
|
25
|
+
"autoprefixer": "^10.4.22",
|
|
26
|
+
"express": "^5.1.0",
|
|
27
|
+
"postcss": "^8.5.6",
|
|
28
|
+
"storybook": "^10.1.2",
|
|
29
|
+
"svelte": "^5.43.14",
|
|
30
|
+
"svelte-check": "^3.6.0",
|
|
31
|
+
"tailwindcss": "^4.1.17",
|
|
32
|
+
"typescript": "^5.9.3",
|
|
33
|
+
"vite": "^6.0.0"
|
|
34
|
+
},
|
|
35
|
+
"oaysus": {
|
|
36
|
+
"theme": {
|
|
37
|
+
"name": "{{PROJECT_NAME}}-pack",
|
|
38
|
+
"displayName": "{{DISPLAY_NAME}}",
|
|
39
|
+
"description": "{{DESCRIPTION}}",
|
|
40
|
+
"category": "marketing",
|
|
41
|
+
"isPremium": false,
|
|
42
|
+
"tags": ["marketing", "components", "theme", "svelte", "performance"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preview HTML Generator - Svelte
|
|
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/svelte@4.2.0/index.js → /build/deps/svelte@4.2.0/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 Svelte mount function
|
|
100
|
+
let mount;
|
|
101
|
+
|
|
102
|
+
async function loadSvelte() {
|
|
103
|
+
try {
|
|
104
|
+
const svelteModule = await import('svelte');
|
|
105
|
+
mount = svelteModule.mount;
|
|
106
|
+
|
|
107
|
+
if (!mount) {
|
|
108
|
+
throw new Error('mount not found in svelte module');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log('✅ Svelte mount function loaded');
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error('❌ Failed to load Svelte:', error);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Load and render a Svelte 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 - Svelte 5 uses default export
|
|
130
|
+
const Component = module.default;
|
|
131
|
+
|
|
132
|
+
if (!Component || typeof Component !== 'function') {
|
|
133
|
+
throw new Error('Component must be exported as default and must be a function');
|
|
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
|
+
// Mount Svelte 5 component using mount() function
|
|
162
|
+
const app = mount(Component, {
|
|
163
|
+
target: container,
|
|
164
|
+
props: defaultProps
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
console.log(\`✅ Successfully mounted \${comp.displayName}\`, app);
|
|
168
|
+
return app;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error(\`❌ Failed to load \${comp.displayName}:\`, error);
|
|
171
|
+
container.innerHTML = \`
|
|
172
|
+
<div class="error">
|
|
173
|
+
<strong>Error loading \${comp.displayName}:</strong><br>
|
|
174
|
+
\${error.message}
|
|
175
|
+
</div>
|
|
176
|
+
\`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Main execution
|
|
181
|
+
async function main() {
|
|
182
|
+
try {
|
|
183
|
+
console.log('🚀 Starting component preview...');
|
|
184
|
+
|
|
185
|
+
// Load Svelte legacy adapter first
|
|
186
|
+
await loadSvelte();
|
|
187
|
+
|
|
188
|
+
// Load all components
|
|
189
|
+
for (const comp of components) {
|
|
190
|
+
await loadComponent(comp);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
console.log('✅ All components loaded successfully!');
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error('❌ Preview failed:', error);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
main();
|
|
200
|
+
</script>
|
|
201
|
+
</body>
|
|
202
|
+
</html>
|
|
203
|
+
`;
|
|
204
|
+
|
|
205
|
+
// Write HTML file
|
|
206
|
+
fs.writeFileSync(OUTPUT_HTML, html);
|
|
207
|
+
|
|
208
|
+
console.log(`
|
|
209
|
+
✅ Preview HTML generated successfully!
|
|
210
|
+
|
|
211
|
+
📁 Location: ${OUTPUT_HTML}
|
|
212
|
+
|
|
213
|
+
🎯 Components found: ${components.length}
|
|
214
|
+
${components.map(c => ` • ${c.displayName} (${c.name})`).join('\n')}
|
|
215
|
+
|
|
216
|
+
🚀 Start the preview server with:
|
|
217
|
+
pnpm run preview:start
|
|
218
|
+
|
|
219
|
+
Or run the full preview (generate + serve):
|
|
220
|
+
pnpm run preview
|
|
221
|
+
`);
|
|
@@ -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,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TypeScript types for Svelte components
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface BaseComponentProps {
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ButtonProps extends BaseComponentProps {
|
|
10
|
+
text: string;
|
|
11
|
+
link: string;
|
|
12
|
+
variant?: 'primary' | 'secondary';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface HeadingProps extends BaseComponentProps {
|
|
16
|
+
heading: string;
|
|
17
|
+
subheading?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ImageProps {
|
|
21
|
+
src: string;
|
|
22
|
+
alt: string;
|
|
23
|
+
width?: number;
|
|
24
|
+
height?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface LinkProps {
|
|
28
|
+
text: string;
|
|
29
|
+
href: string;
|
|
30
|
+
target?: '_blank' | '_self';
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utility functions for Svelte components
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Combine class names, filtering out falsy values
|
|
7
|
+
*/
|
|
8
|
+
export function cn(...classes: (string | undefined | null | false)[]): string {
|
|
9
|
+
return classes.filter(Boolean).join(' ');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Format a date to a readable 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).trim() + '...';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate a unique ID
|
|
34
|
+
*/
|
|
35
|
+
export function generateId(prefix: string = 'id'): string {
|
|
36
|
+
return `${prefix}-${Math.random().toString(36).substr(2, 9)}`;
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./.svelte-kit/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ES2020",
|
|
5
|
+
"useDefineForClassFields": true,
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"esModuleInterop": true,
|
|
19
|
+
"forceConsistentCasingInFileNames": true,
|
|
20
|
+
"baseUrl": ".",
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": ["**/*.ts", "**/*.svelte"],
|
|
26
|
+
"exclude": ["node_modules", "dist", ".oaysus-build"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [svelte()],
|
|
7
|
+
resolve: {
|
|
8
|
+
alias: {
|
|
9
|
+
'@': resolve(__dirname, './')
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StorybookConfig } from '@storybook/vue3-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/vue3-vite',
|
|
8
|
+
options: {}
|
|
9
|
+
},
|
|
10
|
+
docs: {}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default config;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Preview } from '@storybook/vue3';
|
|
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
|
+
}
|