uniweb 0.6.0 → 0.6.2
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/package.json +5 -5
- package/src/commands/i18n.js +9 -8
- package/src/index.js +2 -0
- package/src/templates/index.js +47 -2
- package/src/templates/resolver.js +12 -1
- package/templates/multi/foundations/default/src/{foundation.js.hbs → foundation.js} +1 -1
- package/templates/multi/foundations/default/src/sections/Section/index.jsx +1 -1
- package/templates/multi/foundations/default/src/styles.css +1 -8
- package/templates/single/foundation/src/{foundation.js.hbs → foundation.js} +1 -1
- package/templates/single/foundation/src/sections/Section/index.jsx +1 -1
- package/templates/single/foundation/src/styles.css +1 -8
- package/templates/single/site/index.html.hbs +1 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"js-yaml": "^4.1.0",
|
|
41
41
|
"prompts": "^2.4.2",
|
|
42
42
|
"tar": "^7.0.0",
|
|
43
|
-
"@uniweb/
|
|
44
|
-
"@uniweb/core": "0.
|
|
45
|
-
"@uniweb/
|
|
46
|
-
"@uniweb/
|
|
43
|
+
"@uniweb/runtime": "0.5.12",
|
|
44
|
+
"@uniweb/core": "0.4.0",
|
|
45
|
+
"@uniweb/build": "0.6.0",
|
|
46
|
+
"@uniweb/kit": "0.5.0"
|
|
47
47
|
}
|
|
48
48
|
}
|
package/src/commands/i18n.js
CHANGED
|
@@ -228,10 +228,11 @@ async function loadSiteConfig(siteRoot) {
|
|
|
228
228
|
*/
|
|
229
229
|
async function runExtract(siteRoot, config, args) {
|
|
230
230
|
const verbose = args.includes('--verbose') || args.includes('-v')
|
|
231
|
-
const collectionsOnly = args.includes('--collections')
|
|
232
|
-
const
|
|
231
|
+
const collectionsOnly = args.includes('--collections-only') || args.includes('--collections')
|
|
232
|
+
const noCollections = args.includes('--no-collections')
|
|
233
|
+
// --with-collections is now a no-op (collections are included by default)
|
|
233
234
|
|
|
234
|
-
// Extract page content (unless --collections
|
|
235
|
+
// Extract page content (unless --collections-only)
|
|
235
236
|
if (!collectionsOnly) {
|
|
236
237
|
log(`\n${colors.cyan}Extracting translatable content...${colors.reset}\n`)
|
|
237
238
|
|
|
@@ -274,8 +275,8 @@ async function runExtract(siteRoot, config, args) {
|
|
|
274
275
|
}
|
|
275
276
|
}
|
|
276
277
|
|
|
277
|
-
// Extract collection content (
|
|
278
|
-
if (
|
|
278
|
+
// Extract collection content (by default, skip with --no-collections)
|
|
279
|
+
if (!noCollections) {
|
|
279
280
|
log(`\n${colors.cyan}Extracting collection content...${colors.reset}\n`)
|
|
280
281
|
|
|
281
282
|
// Check if collections exist
|
|
@@ -1482,8 +1483,8 @@ ${colors.bright}Options:${colors.reset}
|
|
|
1482
1483
|
--freeform (status/prune) Include free-form translation status
|
|
1483
1484
|
--json (status) Output as JSON for translation tools
|
|
1484
1485
|
--by-page (status --missing) Group missing strings by page
|
|
1485
|
-
--collections
|
|
1486
|
-
--
|
|
1486
|
+
--collections-only (extract/status/audit) Process only collections
|
|
1487
|
+
--no-collections (extract/status/audit) Skip collections (pages only)
|
|
1487
1488
|
--all-stale (update-hash) Update all stale translations at once
|
|
1488
1489
|
|
|
1489
1490
|
${colors.bright}Configuration:${colors.reset}
|
|
@@ -1520,7 +1521,7 @@ ${colors.bright}Examples:${colors.reset}
|
|
|
1520
1521
|
${colors.dim}# Hash-based workflow${colors.reset}
|
|
1521
1522
|
uniweb i18n extract # Extract all translatable strings
|
|
1522
1523
|
uniweb i18n extract --verbose # Show extracted strings
|
|
1523
|
-
uniweb i18n extract --
|
|
1524
|
+
uniweb i18n extract --no-collections # Pages only (skip collections)
|
|
1524
1525
|
uniweb i18n init es fr # Create starter files for Spanish and French
|
|
1525
1526
|
uniweb i18n init --empty # Create files with empty values (for translators)
|
|
1526
1527
|
uniweb i18n init --force # Overwrite existing locale files
|
package/src/index.js
CHANGED
|
@@ -388,6 +388,7 @@ ${colors.bright}Template Types:${colors.reset}
|
|
|
388
388
|
single One site + one foundation (default)
|
|
389
389
|
multi Multiple sites and foundations
|
|
390
390
|
marketing Official marketing template
|
|
391
|
+
./path/to/template Local directory
|
|
391
392
|
@scope/template-name npm package
|
|
392
393
|
github:user/repo GitHub repository
|
|
393
394
|
https://github.com/user/repo GitHub URL
|
|
@@ -397,6 +398,7 @@ ${colors.bright}Examples:${colors.reset}
|
|
|
397
398
|
npx uniweb create my-project --template single
|
|
398
399
|
npx uniweb create my-project --template marketing
|
|
399
400
|
npx uniweb create my-project --template marketing --variant tailwind3
|
|
401
|
+
npx uniweb create my-project --template ./my-template
|
|
400
402
|
npx uniweb create my-project --template github:myorg/template
|
|
401
403
|
npx uniweb build
|
|
402
404
|
npx uniweb build --target foundation
|
package/src/templates/index.js
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* Template resolution and application for the CLI
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { existsSync } from 'node:fs'
|
|
6
|
+
import { readFile, rm } from 'node:fs/promises'
|
|
7
|
+
import { join, resolve } from 'node:path'
|
|
8
|
+
import { homedir } from 'node:os'
|
|
7
9
|
|
|
8
10
|
import { parseTemplateId, getTemplateDisplayName, BUILTIN_TEMPLATES, OFFICIAL_TEMPLATES } from './resolver.js'
|
|
9
11
|
import { fetchNpmTemplate } from './fetchers/npm.js'
|
|
@@ -47,6 +49,9 @@ export async function resolveTemplate(identifier, options = {}) {
|
|
|
47
49
|
case 'github':
|
|
48
50
|
return resolveGitHubTemplate(parsed, options)
|
|
49
51
|
|
|
52
|
+
case 'local':
|
|
53
|
+
return resolveLocalTemplate(parsed.path, options)
|
|
54
|
+
|
|
50
55
|
default:
|
|
51
56
|
throw new Error(`Unknown template type: ${parsed.type}`)
|
|
52
57
|
}
|
|
@@ -118,6 +123,46 @@ async function resolveGitHubTemplate(parsed, options = {}) {
|
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Resolve a local template from a filesystem path
|
|
128
|
+
*/
|
|
129
|
+
async function resolveLocalTemplate(templatePath, options = {}) {
|
|
130
|
+
const { onProgress } = options
|
|
131
|
+
|
|
132
|
+
// Expand ~ to home directory
|
|
133
|
+
let resolvedPath = templatePath.startsWith('~')
|
|
134
|
+
? templatePath.replace(/^~/, homedir())
|
|
135
|
+
: templatePath
|
|
136
|
+
|
|
137
|
+
// Resolve to absolute path
|
|
138
|
+
resolvedPath = resolve(resolvedPath)
|
|
139
|
+
|
|
140
|
+
if (!existsSync(resolvedPath)) {
|
|
141
|
+
throw new Error(`Local template not found: ${resolvedPath}`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
onProgress?.(`Using local template: ${resolvedPath}`)
|
|
145
|
+
|
|
146
|
+
// Read template.json for name
|
|
147
|
+
const metaPath = join(resolvedPath, 'template.json')
|
|
148
|
+
let name = templatePath
|
|
149
|
+
if (existsSync(metaPath)) {
|
|
150
|
+
try {
|
|
151
|
+
const meta = JSON.parse(await readFile(metaPath, 'utf-8'))
|
|
152
|
+
name = meta.name || templatePath
|
|
153
|
+
} catch {
|
|
154
|
+
// Use path as name if template.json can't be parsed
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
type: 'local',
|
|
160
|
+
name,
|
|
161
|
+
path: resolvedPath,
|
|
162
|
+
cleanup: null,
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
121
166
|
/**
|
|
122
167
|
* Apply a template to a target directory
|
|
123
168
|
*
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export const BUILTIN_TEMPLATES = ['single', 'multi']
|
|
7
7
|
|
|
8
8
|
// Official templates from @uniweb/templates package (downloaded from GitHub releases)
|
|
9
|
-
export const OFFICIAL_TEMPLATES = ['marketing', 'academic', 'docs', 'international']
|
|
9
|
+
export const OFFICIAL_TEMPLATES = ['marketing', 'academic', 'docs', 'international', 'dynamic']
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Parse a template identifier and determine its source type
|
|
@@ -70,6 +70,15 @@ export function parseTemplateId(identifier) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// Local path (relative, absolute, or home directory)
|
|
74
|
+
if (identifier.startsWith('./') || identifier.startsWith('../') ||
|
|
75
|
+
identifier.startsWith('/') || identifier.startsWith('~')) {
|
|
76
|
+
return {
|
|
77
|
+
type: 'local',
|
|
78
|
+
path: identifier,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
// Unscoped name - assume it's an npm package with @uniweb/template- prefix
|
|
74
83
|
// This allows users to type `uniweb create foo --template blog` for @uniweb/template-blog
|
|
75
84
|
return {
|
|
@@ -110,6 +119,8 @@ export function getTemplateDisplayName(parsed) {
|
|
|
110
119
|
return parsed.package
|
|
111
120
|
case 'github':
|
|
112
121
|
return `${parsed.owner}/${parsed.repo}${parsed.ref ? `#${parsed.ref}` : ''}`
|
|
122
|
+
case 'local':
|
|
123
|
+
return `Local: ${parsed.path}`
|
|
113
124
|
default:
|
|
114
125
|
return 'Unknown'
|
|
115
126
|
}
|
|
@@ -90,7 +90,7 @@ export function Section({ content, params }) {
|
|
|
90
90
|
className={cn(
|
|
91
91
|
'inline-flex items-center px-6 py-3 font-medium rounded-lg transition-colors',
|
|
92
92
|
index === 0
|
|
93
|
-
? 'bg-primary text-white hover:bg-primary-
|
|
93
|
+
? 'bg-primary-600 text-white hover:bg-primary-700'
|
|
94
94
|
: 'border border-current hover:bg-gray-100'
|
|
95
95
|
)}
|
|
96
96
|
>
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
|
+
@import "@uniweb/kit/theme-tokens.css";
|
|
2
3
|
|
|
3
4
|
@source "./sections/**/*.{js,jsx}";
|
|
4
5
|
@source "../node_modules/@uniweb/kit/src/**/*.{js,jsx}";
|
|
5
|
-
|
|
6
|
-
@theme {
|
|
7
|
-
--color-primary: #3b82f6;
|
|
8
|
-
--color-primary-light: #60a5fa;
|
|
9
|
-
--color-primary-dark: #2563eb;
|
|
10
|
-
--color-secondary: #64748b;
|
|
11
|
-
--color-accent: #8b5cf6;
|
|
12
|
-
}
|
|
@@ -90,7 +90,7 @@ export function Section({ content, params }) {
|
|
|
90
90
|
className={cn(
|
|
91
91
|
'inline-flex items-center px-6 py-3 font-medium rounded-lg transition-colors',
|
|
92
92
|
index === 0
|
|
93
|
-
? 'bg-primary text-white hover:bg-primary-
|
|
93
|
+
? 'bg-primary-600 text-white hover:bg-primary-700'
|
|
94
94
|
: 'border border-current hover:bg-gray-100'
|
|
95
95
|
)}
|
|
96
96
|
>
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
|
+
@import "@uniweb/kit/theme-tokens.css";
|
|
2
3
|
|
|
3
4
|
@source "./sections/**/*.{js,jsx}";
|
|
4
5
|
@source "../node_modules/@uniweb/kit/src/**/*.{js,jsx}";
|
|
5
|
-
|
|
6
|
-
@theme {
|
|
7
|
-
--color-primary: #3b82f6;
|
|
8
|
-
--color-primary-light: #60a5fa;
|
|
9
|
-
--color-primary-dark: #2563eb;
|
|
10
|
-
--color-secondary: #64748b;
|
|
11
|
-
--color-accent: #8b5cf6;
|
|
12
|
-
}
|
|
@@ -5,15 +5,9 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>{{projectName}}</title>
|
|
8
|
-
<style>
|
|
9
|
-
body { margin: 0; font-family: system-ui, sans-serif; }
|
|
10
|
-
.loading { display: flex; align-items: center; justify-content: center; min-height: 100vh; color: #64748b; }
|
|
11
|
-
</style>
|
|
12
8
|
</head>
|
|
13
9
|
<body>
|
|
14
|
-
<div id="root">
|
|
15
|
-
<div class="loading">Loading...</div>
|
|
16
|
-
</div>
|
|
10
|
+
<div id="root"></div>
|
|
17
11
|
<script type="module" src="/main.js"></script>
|
|
18
12
|
</body>
|
|
19
13
|
</html>
|