@yoamigo.com/cli 0.1.17 → 0.1.20
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 +26 -1
- package/dist/index.js +190 -180
- package/package.json +4 -9
- package/templates/starter/package-lock.json +863 -7
- package/templates/starter/package.json +8 -1
- package/templates/starter/src/App.tsx +12 -11
- package/templates/starter/src/{content.json → content.ts} +2 -2
- package/templates/starter/src/lib/router/routes.tsx +103 -0
- package/templates/starter/src/main.tsx +1 -1
- package/templates/starter/src/pages/{AboutPage.tsx → about.tsx} +1 -1
- package/templates/starter/src/pages/{ContactPage.tsx → contact.tsx} +1 -1
- package/templates/starter/src/pages/{HomePage.tsx → index.tsx} +1 -1
- package/templates/starter/src/routes.ts +1 -0
- package/templates/starter/src/styles/globals.css +0 -1
- package/templates/starter/tsconfig.json +1 -0
|
@@ -9,7 +9,14 @@
|
|
|
9
9
|
"preview": "vite preview"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@
|
|
12
|
+
"@tiptap/core": "^3.11.1",
|
|
13
|
+
"@tiptap/extension-link": "^3.11.1",
|
|
14
|
+
"@tiptap/extension-text-style": "^3.11.1",
|
|
15
|
+
"@tiptap/pm": "^3.11.1",
|
|
16
|
+
"@tiptap/react": "^3.11.1",
|
|
17
|
+
"@tiptap/starter-kit": "^3.11.1",
|
|
18
|
+
"@yoamigo.com/core": "^0.1.7",
|
|
19
|
+
"dompurify": "^3.2.3",
|
|
13
20
|
"react": "^19.2.1",
|
|
14
21
|
"react-dom": "^19.2.1"
|
|
15
22
|
},
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ContentStoreProvider } from '@yoamigo.com/core'
|
|
2
|
+
import { Router } from '@yoamigo.com/core/router'
|
|
2
3
|
import { Header } from './components/Header'
|
|
3
4
|
import { Footer } from './components/Footer'
|
|
4
|
-
import {
|
|
5
|
-
import { AboutPage } from './pages/AboutPage'
|
|
6
|
-
import { ContactPage } from './pages/ContactPage'
|
|
5
|
+
import { AppRoutes, getAvailablePages } from './routes'
|
|
7
6
|
|
|
8
7
|
function Layout({ children }: { children: React.ReactNode }) {
|
|
9
8
|
return (
|
|
@@ -18,13 +17,15 @@ function Layout({ children }: { children: React.ReactNode }) {
|
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
export default function App() {
|
|
20
|
+
const pages = getAvailablePages()
|
|
21
|
+
|
|
21
22
|
return (
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</
|
|
28
|
-
</
|
|
23
|
+
<ContentStoreProvider pages={pages}>
|
|
24
|
+
<Router>
|
|
25
|
+
<Layout>
|
|
26
|
+
<AppRoutes />
|
|
27
|
+
</Layout>
|
|
28
|
+
</Router>
|
|
29
|
+
</ContentStoreProvider>
|
|
29
30
|
)
|
|
30
31
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{
|
|
1
|
+
export default {
|
|
2
2
|
"site.name": "My Website",
|
|
3
3
|
"hero.title": "Build Something Amazing",
|
|
4
4
|
"hero.subtitle": "Create beautiful, modern websites with our intuitive template system. Click any text to customize it in the builder.",
|
|
@@ -24,4 +24,4 @@
|
|
|
24
24
|
"contact.addressTitle": "Address",
|
|
25
25
|
"contact.addressValue": "123 Main Street, Suite 100\nSan Francisco, CA 94102",
|
|
26
26
|
"footer.copyright": "© 2025 My Website. All rights reserved."
|
|
27
|
-
}
|
|
27
|
+
} as const satisfies Record<string, string>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routes - Auto-discovery with wouter
|
|
3
|
+
*
|
|
4
|
+
* Auto-discovers pages from src/pages/ using import.meta.glob
|
|
5
|
+
* and generates wouter Route components.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { lazy, Suspense, ComponentType } from 'react'
|
|
9
|
+
import { Route, Switch } from 'wouter'
|
|
10
|
+
|
|
11
|
+
// Import all page modules
|
|
12
|
+
const pageModules = import.meta.glob<{ default: ComponentType }>('/src/pages/**/*.tsx')
|
|
13
|
+
|
|
14
|
+
interface RouteDefinition {
|
|
15
|
+
path: string
|
|
16
|
+
component: ComponentType
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function generateRoutes(): RouteDefinition[] {
|
|
20
|
+
const routes: RouteDefinition[] = []
|
|
21
|
+
|
|
22
|
+
for (const filePath in pageModules) {
|
|
23
|
+
// Skip component files that might be in pages
|
|
24
|
+
if (filePath.includes('/components/')) continue
|
|
25
|
+
if (filePath.includes('/_')) continue // Skip files starting with _
|
|
26
|
+
|
|
27
|
+
// Convert filesystem path to URL path
|
|
28
|
+
// /src/pages/index.tsx -> /
|
|
29
|
+
// /src/pages/contact.tsx -> /contact
|
|
30
|
+
// /src/pages/thank-you.tsx -> /thank-you
|
|
31
|
+
let routePath = filePath
|
|
32
|
+
.replace('/src/pages', '')
|
|
33
|
+
.replace(/\.tsx$/, '')
|
|
34
|
+
.replace(/\/index$/, '') || '/'
|
|
35
|
+
|
|
36
|
+
// Create lazy component
|
|
37
|
+
const Component = lazy(pageModules[filePath])
|
|
38
|
+
|
|
39
|
+
routes.push({ path: routePath, component: Component })
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Sort routes: exact paths before wildcards, longer paths first
|
|
43
|
+
routes.sort((a, b) => {
|
|
44
|
+
if (a.path === '/') return 1
|
|
45
|
+
if (b.path === '/') return -1
|
|
46
|
+
return b.path.length - a.path.length
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
return routes
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const routes = generateRoutes()
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Available routes for page selection
|
|
56
|
+
* Returns paths only (not lazy components) for use in UI
|
|
57
|
+
*/
|
|
58
|
+
export function getAvailablePages(): Array<{ path: string; label: string }> {
|
|
59
|
+
return routes.map(route => ({
|
|
60
|
+
path: route.path,
|
|
61
|
+
label: route.path === '/'
|
|
62
|
+
? 'Home'
|
|
63
|
+
: route.path
|
|
64
|
+
.slice(1) // Remove leading /
|
|
65
|
+
.split('-')
|
|
66
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
67
|
+
.join(' '),
|
|
68
|
+
}))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* PageLoader - Shown while lazy-loading page components
|
|
73
|
+
*/
|
|
74
|
+
function PageLoader() {
|
|
75
|
+
return (
|
|
76
|
+
<div className="min-h-screen flex items-center justify-center bg-white">
|
|
77
|
+
<div className="animate-pulse text-gray-600">Loading...</div>
|
|
78
|
+
</div>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* AppRoutes - Renders auto-discovered routes with Suspense
|
|
84
|
+
*/
|
|
85
|
+
export function AppRoutes() {
|
|
86
|
+
return (
|
|
87
|
+
<Suspense fallback={<PageLoader />}>
|
|
88
|
+
<Switch>
|
|
89
|
+
{routes.map(({ path, component: Component }) => (
|
|
90
|
+
<Route key={path} path={path}>
|
|
91
|
+
<Component />
|
|
92
|
+
</Route>
|
|
93
|
+
))}
|
|
94
|
+
{/* 404 fallback */}
|
|
95
|
+
<Route>
|
|
96
|
+
<div className="min-h-screen flex items-center justify-center bg-white">
|
|
97
|
+
<h1 className="text-2xl text-gray-900">Page Not Found</h1>
|
|
98
|
+
</div>
|
|
99
|
+
</Route>
|
|
100
|
+
</Switch>
|
|
101
|
+
</Suspense>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
@@ -2,7 +2,7 @@ import { StrictMode } from 'react'
|
|
|
2
2
|
import { createRoot } from 'react-dom/client'
|
|
3
3
|
import { ContentStoreProvider, registerContent } from '@yoamigo.com/core'
|
|
4
4
|
import App from './App'
|
|
5
|
-
import content from './content
|
|
5
|
+
import content from './content'
|
|
6
6
|
import './styles/globals.css'
|
|
7
7
|
|
|
8
8
|
// Register content for the content store
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AppRoutes, getAvailablePages } from './lib/router/routes'
|