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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uniweb",
3
- "version": "0.6.0",
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/build": "0.5.0",
44
- "@uniweb/core": "0.3.10",
45
- "@uniweb/kit": "0.4.11",
46
- "@uniweb/runtime": "0.5.11"
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
  }
@@ -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 withCollections = args.includes('--with-collections')
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 only)
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 (if --collections or --with-collections)
278
- if (collectionsOnly || withCollections) {
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 (extract/status/audit) Process only collections
1486
- --with-collections (extract/status/audit) Include collections with pages
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 --with-collections # Extract pages + collections
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
@@ -2,8 +2,10 @@
2
2
  * Template resolution and application for the CLI
3
3
  */
4
4
 
5
- import { rm } from 'node:fs/promises'
6
- import { join } from 'node:path'
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
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * {{projectName}} Default Foundation Configuration
2
+ * Default Foundation Configuration
3
3
  *
4
4
  * This file defines foundation-level configuration:
5
5
  * - vars: CSS custom properties that sites can override in theme.yml
@@ -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-dark'
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
- }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * {{projectName}} Foundation Configuration
2
+ * Foundation Configuration
3
3
  *
4
4
  * This file defines foundation-level configuration:
5
5
  * - vars: CSS custom properties that sites can override in theme.yml
@@ -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-dark'
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>