@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.
- 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/components/App.d.ts +2 -0
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +3 -0
- package/dist/components/App.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 +44 -0
- package/dist/lib/shared/auth.js.map +1 -1
- package/dist/lib/shared/commands.d.ts.map +1 -1
- package/dist/lib/shared/commands.js +4 -0
- package/dist/lib/shared/commands.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 +2 -0
- package/dist/screens/WelcomeScreen.d.ts.map +1 -1
- package/dist/screens/WelcomeScreen.js +4 -1
- package/dist/screens/WelcomeScreen.js.map +1 -1
- package/dist/types/index.d.ts +1 -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,69 @@
|
|
|
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 Vue 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
|
+
```vue
|
|
27
|
+
<template>
|
|
28
|
+
<Hero
|
|
29
|
+
heading="Welcome"
|
|
30
|
+
subheading="Build amazing things"
|
|
31
|
+
buttonText="Get Started"
|
|
32
|
+
buttonLink="/start"
|
|
33
|
+
/>
|
|
34
|
+
<Testimonials />
|
|
35
|
+
<CTA />
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup>
|
|
39
|
+
import Hero from './components/Hero';
|
|
40
|
+
import CTA from './components/CTA';
|
|
41
|
+
import Testimonials from './components/Testimonials';
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Adding New Components
|
|
46
|
+
|
|
47
|
+
To add a new component to this theme pack:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
oaysus create component MyComponent
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Development
|
|
54
|
+
|
|
55
|
+
This theme pack was created using the Oaysus CLI.
|
|
56
|
+
|
|
57
|
+
To validate and package for upload:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
oaysus validate
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Author
|
|
64
|
+
|
|
65
|
+
{{AUTHOR}}
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "{{COMPONENT_TYPE}}",
|
|
3
|
+
"displayName": "{{COMPONENT_NAME}}",
|
|
4
|
+
"description": "{{DESCRIPTION}}",
|
|
5
|
+
"category": "{{CATEGORY}}",
|
|
6
|
+
"props": {
|
|
7
|
+
"heading": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"default": "Welcome"
|
|
10
|
+
},
|
|
11
|
+
"subheading": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"default": "Your amazing tagline"
|
|
14
|
+
},
|
|
15
|
+
"buttonText": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"default": "Get Started"
|
|
18
|
+
},
|
|
19
|
+
"buttonLink": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"default": "#"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import {{COMPONENT_NAME}} from './{{COMPONENT_NAME}}.vue';
|
|
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,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<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">
|
|
3
|
+
<div class="max-w-4xl mx-auto text-center">
|
|
4
|
+
<h1 class="text-6xl font-black mb-6 text-white drop-shadow-lg">{{ heading }}</h1>
|
|
5
|
+
<p class="text-2xl mb-10 text-yellow-200 font-semibold">{{ subheading }}</p>
|
|
6
|
+
<a
|
|
7
|
+
:href="buttonLink"
|
|
8
|
+
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"
|
|
9
|
+
>
|
|
10
|
+
{{ buttonText }}
|
|
11
|
+
</a>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup lang="ts">
|
|
17
|
+
import { defineProps, withDefaults } from 'vue';
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
heading?: string;
|
|
21
|
+
subheading?: string;
|
|
22
|
+
buttonText?: string;
|
|
23
|
+
buttonLink?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
27
|
+
heading: 'Welcome',
|
|
28
|
+
subheading: 'Your amazing tagline',
|
|
29
|
+
buttonText: 'Get Started',
|
|
30
|
+
buttonLink: '#'
|
|
31
|
+
});
|
|
32
|
+
</script>
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
"vue": "^3.5.24"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@storybook/addon-a11y": "^10.1.2",
|
|
20
|
+
"@storybook/vue3": "^10.1.2",
|
|
21
|
+
"@storybook/vue3-vite": "^10.1.2",
|
|
22
|
+
"@tailwindcss/cli": "^4.1.17",
|
|
23
|
+
"@tailwindcss/postcss": "^4.1.17",
|
|
24
|
+
"@vitejs/plugin-vue": "^6.0.2",
|
|
25
|
+
"autoprefixer": "^10.4.22",
|
|
26
|
+
"express": "^5.1.0",
|
|
27
|
+
"postcss": "^8.5.6",
|
|
28
|
+
"storybook": "^10.1.2",
|
|
29
|
+
"tailwindcss": "^4.1.17",
|
|
30
|
+
"typescript": "^5.9.3",
|
|
31
|
+
"vite": "^6.0.0",
|
|
32
|
+
"vue": "^3.5.24"
|
|
33
|
+
},
|
|
34
|
+
"oaysus": {
|
|
35
|
+
"theme": {
|
|
36
|
+
"name": "{{PROJECT_NAME}}-pack",
|
|
37
|
+
"displayName": "{{DISPLAY_NAME}}",
|
|
38
|
+
"description": "{{DESCRIPTION}}",
|
|
39
|
+
"category": "marketing",
|
|
40
|
+
"isPremium": false,
|
|
41
|
+
"tags": ["marketing", "components", "theme", "vue", "composition-api"]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preview HTML Generator - Vue
|
|
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/vue@3.3.4/index.js → /build/deps/vue@3.3.4/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 Vue
|
|
100
|
+
let createApp;
|
|
101
|
+
|
|
102
|
+
async function loadVue() {
|
|
103
|
+
try {
|
|
104
|
+
const vueModule = await import('vue');
|
|
105
|
+
createApp = vueModule.createApp || vueModule.default?.createApp;
|
|
106
|
+
|
|
107
|
+
if (!createApp) {
|
|
108
|
+
throw new Error('createApp not found in Vue module');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log('✅ Vue loaded:', vueModule);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error('❌ Failed to load Vue:', error);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Load and render a Vue 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 definition 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 Vue app and mount
|
|
162
|
+
const app = createApp(Component, defaultProps);
|
|
163
|
+
app.mount(container);
|
|
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 Vue first
|
|
183
|
+
await loadVue();
|
|
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,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TypeScript types for Vue 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 Vue 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
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "preserve",
|
|
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", "**/*.vue"],
|
|
26
|
+
"exclude": ["node_modules", "dist", ".oaysus-build"]
|
|
27
|
+
}
|