@object-ui/runner 0.3.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/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/dist/assets/AdvancedChartImpl-DZ0-Siqu.js +11 -0
- package/dist/assets/BarChart-C_mJtBYc.js +69 -0
- package/dist/assets/ChartImpl-BcbiBEtK.js +1 -0
- package/dist/assets/KanbanImpl-APLTSaom.js +5 -0
- package/dist/assets/index-BAf0tooB.css +1 -0
- package/dist/assets/index-CW0j9o4j.js +16235 -0
- package/dist/index.html +14 -0
- package/index.html +13 -0
- package/package.json +37 -0
- package/postcss.config.js +6 -0
- package/src/App.tsx +149 -0
- package/src/LayoutRenderer.tsx +312 -0
- package/src/index.css +76 -0
- package/src/lib/MetadataLoader.ts +95 -0
- package/src/lib/mockDataSource.ts +34 -0
- package/src/main.tsx +10 -0
- package/tailwind.config.js +63 -0
- package/vite.config.ts +29 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { AppSchema, PageSchema } from '@object-ui/types';
|
|
2
|
+
|
|
3
|
+
export interface MetadataLoader {
|
|
4
|
+
loadAppConfig(): Promise<AppSchema | null>;
|
|
5
|
+
loadPage(path: string): Promise<PageSchema | null>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Strategy A: Local Bundle Loader (Vite Glob)
|
|
10
|
+
* Used during local development via 'pnpm dev:crm'
|
|
11
|
+
*/
|
|
12
|
+
export class LocalBundleLoader implements MetadataLoader {
|
|
13
|
+
private appGlob = import.meta.glob('../app-data/app.json');
|
|
14
|
+
private pagesGlob = import.meta.glob('../app-data/pages/**/*.json');
|
|
15
|
+
private rootGlob = import.meta.glob('../app-data/*.json');
|
|
16
|
+
|
|
17
|
+
async loadAppConfig(): Promise<AppSchema | null> {
|
|
18
|
+
const key = '../app-data/app.json';
|
|
19
|
+
if (this.appGlob[key]) {
|
|
20
|
+
const mod: any = await this.appGlob[key]();
|
|
21
|
+
return mod.default || mod;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async loadPage(path: string): Promise<PageSchema | null> {
|
|
27
|
+
// 1. Normalize Path
|
|
28
|
+
const normalizedPath = path.replace(/^\//, '') || 'index';
|
|
29
|
+
|
|
30
|
+
// 2. Try Exact Match in Pages
|
|
31
|
+
if (await this.tryLoad(`../app-data/pages/${normalizedPath}.json`)) {
|
|
32
|
+
return await this.loadKey(`../app-data/pages/${normalizedPath}.json`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 3. Try Index Match
|
|
36
|
+
if (await this.tryLoad(`../app-data/pages/${normalizedPath}/index.json`)) {
|
|
37
|
+
return await this.loadKey(`../app-data/pages/${normalizedPath}/index.json`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 4. Try Root fallback
|
|
41
|
+
if (normalizedPath === 'index' && await this.tryLoad(`../app-data/index.json`)) {
|
|
42
|
+
return await this.loadKey(`../app-data/index.json`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 5. Dynamic Routing (Basic Mock)
|
|
46
|
+
// TODO: Implement proper glob matching for dynamic routes if needed here,
|
|
47
|
+
// but usually exact paths are enough for this loader demo.
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private async tryLoad(key: string) {
|
|
52
|
+
return !!(this.pagesGlob[key] || this.rootGlob[key]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private async loadKey(key: string) {
|
|
56
|
+
const loader = this.pagesGlob[key] || this.rootGlob[key];
|
|
57
|
+
if (!loader) return null;
|
|
58
|
+
const mod: any = await loader();
|
|
59
|
+
return mod.default || mod;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Strategy B: Network Loader (Fetch API)
|
|
65
|
+
* Used in production to fetch JSONs from an API endpoint
|
|
66
|
+
*/
|
|
67
|
+
export class NetworkLoader implements MetadataLoader {
|
|
68
|
+
private baseUrl: string;
|
|
69
|
+
|
|
70
|
+
constructor(baseUrl: string = '/api') {
|
|
71
|
+
this.baseUrl = baseUrl;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async loadAppConfig(): Promise<AppSchema | null> {
|
|
75
|
+
try {
|
|
76
|
+
const res = await fetch(`${this.baseUrl}/app.json`);
|
|
77
|
+
if (!res.ok) return null;
|
|
78
|
+
return await res.json();
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async loadPage(path: string): Promise<PageSchema | null> {
|
|
85
|
+
try {
|
|
86
|
+
// Maps /customers -> /api/pages/customers.json
|
|
87
|
+
const jsonPath = path === '/' ? '/index' : path;
|
|
88
|
+
const res = await fetch(`${this.baseUrl}/pages${jsonPath}.json`);
|
|
89
|
+
if (!res.ok) return null;
|
|
90
|
+
return await res.json();
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { DataSource } from '@object-ui/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 模拟数据源 (Mock Adapter)
|
|
5
|
+
* 在真实项目中,你会在这里使用 fetch/axios 调用你的 API。
|
|
6
|
+
*/
|
|
7
|
+
export class MockDataSource implements DataSource {
|
|
8
|
+
async find(resource: string, params?: any): Promise<any[]> {
|
|
9
|
+
console.log(`[DataSource] Querying ${resource}`, params);
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async findOne(resource: string, id: string): Promise<any> {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async create(resource: string, data: any): Promise<any> {
|
|
18
|
+
// 模拟网络请求
|
|
19
|
+
await new Promise(resolve => setTimeout(resolve, 800));
|
|
20
|
+
|
|
21
|
+
console.log(`[DataSource] Created ${resource}:`, data);
|
|
22
|
+
alert(`Success! Created record in "${resource}":\n${JSON.stringify(data, null, 2)}`);
|
|
23
|
+
|
|
24
|
+
return { id: Math.random().toString(), ...data };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async update(resource: string, id: string, data: any): Promise<any> {
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async delete(resource: string, id: string): Promise<any> {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/main.tsx
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
export default {
|
|
3
|
+
darkMode: ["class"],
|
|
4
|
+
content: [
|
|
5
|
+
"./index.html",
|
|
6
|
+
"./src/**/*.{ts,tsx}",
|
|
7
|
+
|
|
8
|
+
// ⚠️ 核心配置:
|
|
9
|
+
// 指向 Monorepo 中的包源码,确保 Tailwind 能提取出 Object UI 组件内的 className
|
|
10
|
+
"../../packages/components/src/**/*.{ts,tsx}",
|
|
11
|
+
"../../packages/react/src/**/*.{ts,tsx}",
|
|
12
|
+
"../../packages/plugin-kanban/src/**/*.{ts,tsx}",
|
|
13
|
+
"../../packages/plugin-charts/src/**/*.{ts,tsx}",
|
|
14
|
+
],
|
|
15
|
+
theme: {
|
|
16
|
+
extend: {
|
|
17
|
+
// 映射 Shadcn UI 变量
|
|
18
|
+
colors: {
|
|
19
|
+
border: "hsl(var(--border))",
|
|
20
|
+
input: "hsl(var(--input))",
|
|
21
|
+
ring: "hsl(var(--ring))",
|
|
22
|
+
background: "hsl(var(--background))",
|
|
23
|
+
foreground: "hsl(var(--foreground))",
|
|
24
|
+
primary: {
|
|
25
|
+
DEFAULT: "hsl(var(--primary))",
|
|
26
|
+
foreground: "hsl(var(--primary-foreground))",
|
|
27
|
+
},
|
|
28
|
+
secondary: {
|
|
29
|
+
DEFAULT: "hsl(var(--secondary))",
|
|
30
|
+
foreground: "hsl(var(--secondary-foreground))",
|
|
31
|
+
},
|
|
32
|
+
destructive: {
|
|
33
|
+
DEFAULT: "hsl(var(--destructive))",
|
|
34
|
+
foreground: "hsl(var(--destructive-foreground))",
|
|
35
|
+
},
|
|
36
|
+
muted: {
|
|
37
|
+
DEFAULT: "hsl(var(--muted))",
|
|
38
|
+
foreground: "hsl(var(--muted-foreground))",
|
|
39
|
+
},
|
|
40
|
+
accent: {
|
|
41
|
+
DEFAULT: "hsl(var(--accent))",
|
|
42
|
+
foreground: "hsl(var(--accent-foreground))",
|
|
43
|
+
},
|
|
44
|
+
popover: {
|
|
45
|
+
DEFAULT: "hsl(var(--popover))",
|
|
46
|
+
foreground: "hsl(var(--popover-foreground))",
|
|
47
|
+
},
|
|
48
|
+
card: {
|
|
49
|
+
DEFAULT: "hsl(var(--card))",
|
|
50
|
+
foreground: "hsl(var(--card-foreground))",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
borderRadius: {
|
|
54
|
+
lg: "var(--radius)",
|
|
55
|
+
md: "calc(var(--radius) - 2px)",
|
|
56
|
+
sm: "calc(var(--radius) - 4px)",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
plugins: [
|
|
61
|
+
require("tailwindcss-animate"),
|
|
62
|
+
],
|
|
63
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
// https://vitejs.dev/config/
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [react()],
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
// ⚡️ DX: Fix Shadcn component imports in the monorepo source
|
|
11
|
+
"@/ui": path.resolve(__dirname, "../../packages/components/src/ui"),
|
|
12
|
+
"@/lib/utils": path.resolve(__dirname, "../../packages/components/src/lib/utils"),
|
|
13
|
+
"@/hooks": path.resolve(__dirname, "../../packages/components/src/hooks"),
|
|
14
|
+
|
|
15
|
+
"@": path.resolve(__dirname, "./src"),
|
|
16
|
+
// ⚡️ DX: App Data Symlink
|
|
17
|
+
"@app": path.resolve(__dirname, "./src/app-data"),
|
|
18
|
+
|
|
19
|
+
// ⚡️ DX: Map imports to source code for Hot Module Replacement
|
|
20
|
+
"@object-ui/components": path.resolve(__dirname, "../../packages/components/src"),
|
|
21
|
+
"@object-ui/react": path.resolve(__dirname, "../../packages/react/src"),
|
|
22
|
+
"@object-ui/core": path.resolve(__dirname, "../../packages/core/src"),
|
|
23
|
+
"@object-ui/types": path.resolve(__dirname, "../../packages/types/src"),
|
|
24
|
+
"@object-ui/data-objectql": path.resolve(__dirname, "../../packages/data-objectql/src"),
|
|
25
|
+
"@object-ui/plugin-kanban": path.resolve(__dirname, "../../packages/plugin-kanban/src"),
|
|
26
|
+
"@object-ui/plugin-charts": path.resolve(__dirname, "../../packages/plugin-charts/src"),
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
})
|