@uniweb/templates 0.1.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.
Files changed (39) hide show
  1. package/package.json +32 -0
  2. package/src/index.js +120 -0
  3. package/src/processor.js +184 -0
  4. package/src/validator.js +206 -0
  5. package/templates/marketing/template/README.md.hbs +56 -0
  6. package/templates/marketing/template/foundation/package.json.hbs +34 -0
  7. package/templates/marketing/template/foundation/postcss.config.js +6 -0
  8. package/templates/marketing/template/foundation/src/components/CTA/index.jsx +75 -0
  9. package/templates/marketing/template/foundation/src/components/CTA/meta.js +46 -0
  10. package/templates/marketing/template/foundation/src/components/Features/index.jsx +81 -0
  11. package/templates/marketing/template/foundation/src/components/Features/meta.js +46 -0
  12. package/templates/marketing/template/foundation/src/components/Hero/index.jsx +73 -0
  13. package/templates/marketing/template/foundation/src/components/Hero/meta.js +46 -0
  14. package/templates/marketing/template/foundation/src/components/Pricing/index.jsx +108 -0
  15. package/templates/marketing/template/foundation/src/components/Pricing/meta.js +36 -0
  16. package/templates/marketing/template/foundation/src/components/Testimonials/index.jsx +96 -0
  17. package/templates/marketing/template/foundation/src/components/Testimonials/meta.js +44 -0
  18. package/templates/marketing/template/foundation/src/entry-runtime.js +3 -0
  19. package/templates/marketing/template/foundation/src/index.js +37 -0
  20. package/templates/marketing/template/foundation/src/meta.js.hbs +28 -0
  21. package/templates/marketing/template/foundation/src/styles.css +3 -0
  22. package/templates/marketing/template/foundation/tailwind.config.js +17 -0
  23. package/templates/marketing/template/foundation/vite.config.js +23 -0
  24. package/templates/marketing/template/package.json.hbs +13 -0
  25. package/templates/marketing/template/pnpm-workspace.yaml +3 -0
  26. package/templates/marketing/template/site/index.html.hbs +18 -0
  27. package/templates/marketing/template/site/package.json.hbs +27 -0
  28. package/templates/marketing/template/site/pages/home/1-hero.md +12 -0
  29. package/templates/marketing/template/site/pages/home/2-features.md +33 -0
  30. package/templates/marketing/template/site/pages/home/3-pricing.md +43 -0
  31. package/templates/marketing/template/site/pages/home/4-testimonials.md +27 -0
  32. package/templates/marketing/template/site/pages/home/5-cta.md +12 -0
  33. package/templates/marketing/template/site/pages/home/page.yml +2 -0
  34. package/templates/marketing/template/site/postcss.config.js +6 -0
  35. package/templates/marketing/template/site/site.yml.hbs +5 -0
  36. package/templates/marketing/template/site/src/main.jsx +19 -0
  37. package/templates/marketing/template/site/tailwind.config.js +24 -0
  38. package/templates/marketing/template/site/vite.config.js +42 -0
  39. package/templates/marketing/template.json +8 -0
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@uniweb/templates",
3
+ "version": "0.1.0",
4
+ "description": "Template processing engine and official templates for Uniweb",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js",
9
+ "./templates/*": "./templates/*"
10
+ },
11
+ "files": [
12
+ "src",
13
+ "templates"
14
+ ],
15
+ "keywords": [
16
+ "uniweb",
17
+ "templates",
18
+ "scaffolding"
19
+ ],
20
+ "author": "Uniweb",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/uniweb/templates.git"
25
+ },
26
+ "engines": {
27
+ "node": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "handlebars": "^4.7.8"
31
+ }
32
+ }
package/src/index.js ADDED
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @uniweb/templates - Template processing engine and official templates
3
+ *
4
+ * Provides utilities for applying file-based templates with Handlebars
5
+ * variable substitution and variant support.
6
+ */
7
+
8
+ import path from 'node:path'
9
+ import { existsSync } from 'node:fs'
10
+ import { fileURLToPath } from 'node:url'
11
+ import { copyTemplateDirectory, clearCache } from './processor.js'
12
+ import {
13
+ validateTemplate,
14
+ listTemplates,
15
+ satisfiesVersion,
16
+ ValidationError,
17
+ ErrorCodes
18
+ } from './validator.js'
19
+
20
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
21
+ const TEMPLATES_DIR = path.join(__dirname, '../templates')
22
+
23
+ /**
24
+ * Get the path to the built-in templates directory
25
+ */
26
+ export function getTemplatesDirectory() {
27
+ return TEMPLATES_DIR
28
+ }
29
+
30
+ /**
31
+ * Get a specific template by name from the built-in templates
32
+ *
33
+ * @param {string} name - Template name (e.g., 'marketing', 'docs')
34
+ * @returns {string|null} Path to template directory, or null if not found
35
+ */
36
+ export function getTemplatePath(name) {
37
+ const templatePath = path.join(TEMPLATES_DIR, name)
38
+ return templatePath
39
+ }
40
+
41
+ /**
42
+ * List all available built-in templates
43
+ *
44
+ * @returns {Promise<Array<Object>>} List of template metadata
45
+ */
46
+ export async function listBuiltinTemplates() {
47
+ return listTemplates(TEMPLATES_DIR)
48
+ }
49
+
50
+ /**
51
+ * Check if a built-in template exists
52
+ *
53
+ * @param {string} name - Template name
54
+ * @returns {boolean}
55
+ */
56
+ export function hasTemplate(name) {
57
+ const templatePath = path.join(TEMPLATES_DIR, name)
58
+ return existsSync(path.join(templatePath, 'template.json'))
59
+ }
60
+
61
+ /**
62
+ * Apply a template to a target directory
63
+ *
64
+ * @param {string} templatePath - Path to the template root (contains template.json)
65
+ * @param {string} targetPath - Destination directory for the scaffolded project
66
+ * @param {Object} data - Template variables
67
+ * @param {Object} options - Apply options
68
+ * @param {string} options.variant - Template variant to use
69
+ * @param {string} options.uniwebVersion - Current Uniweb version for compatibility check
70
+ * @param {Function} options.onWarning - Warning callback
71
+ * @param {Function} options.onProgress - Progress callback
72
+ * @returns {Promise<Object>} Template metadata
73
+ */
74
+ export async function applyTemplate(templatePath, targetPath, data = {}, options = {}) {
75
+ const { uniwebVersion, variant, onWarning, onProgress } = options
76
+
77
+ // Validate the template
78
+ const metadata = await validateTemplate(templatePath, { uniwebVersion })
79
+
80
+ // Apply default variables
81
+ const templateData = {
82
+ year: new Date().getFullYear(),
83
+ ...data
84
+ }
85
+
86
+ // Copy template files
87
+ await copyTemplateDirectory(
88
+ metadata.templateDir,
89
+ targetPath,
90
+ templateData,
91
+ { variant, onWarning, onProgress }
92
+ )
93
+
94
+ return metadata
95
+ }
96
+
97
+ /**
98
+ * Apply a built-in template by name
99
+ *
100
+ * @param {string} name - Template name (e.g., 'marketing')
101
+ * @param {string} targetPath - Destination directory
102
+ * @param {Object} data - Template variables
103
+ * @param {Object} options - Apply options
104
+ * @returns {Promise<Object>} Template metadata
105
+ */
106
+ export async function applyBuiltinTemplate(name, targetPath, data = {}, options = {}) {
107
+ const templatePath = getTemplatePath(name)
108
+ return applyTemplate(templatePath, targetPath, data, options)
109
+ }
110
+
111
+ // Re-export utilities
112
+ export {
113
+ copyTemplateDirectory,
114
+ clearCache,
115
+ validateTemplate,
116
+ listTemplates,
117
+ satisfiesVersion,
118
+ ValidationError,
119
+ ErrorCodes
120
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Template processor - handles file copying and Handlebars substitution
3
+ * Adapted from Proximify dev-tools template system
4
+ */
5
+
6
+ import fs from 'node:fs/promises'
7
+ import { existsSync } from 'node:fs'
8
+ import path from 'node:path'
9
+ import Handlebars from 'handlebars'
10
+
11
+ // Cache for compiled templates
12
+ const templateCache = new Map()
13
+
14
+ // Text file extensions that should be processed for variables
15
+ const TEXT_EXTENSIONS = new Set([
16
+ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
17
+ '.json', '.yml', '.yaml', '.md', '.mdx',
18
+ '.html', '.htm', '.css', '.scss', '.less',
19
+ '.txt', '.xml', '.svg', '.vue', '.astro'
20
+ ])
21
+
22
+ /**
23
+ * Check if a path is a directory
24
+ */
25
+ async function isDirectory(filePath) {
26
+ try {
27
+ const stats = await fs.stat(filePath)
28
+ return stats.isDirectory()
29
+ } catch {
30
+ return false
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Check if string contains unresolved Handlebars placeholders
36
+ */
37
+ function findUnresolvedPlaceholders(content) {
38
+ const patterns = [
39
+ /\{\{([^#/}>][^}]*)\}\}/g, // {{variable}} - not blocks or partials
40
+ ]
41
+
42
+ const unresolved = []
43
+ for (const pattern of patterns) {
44
+ const matches = content.matchAll(pattern)
45
+ for (const match of matches) {
46
+ const varName = match[1].trim()
47
+ // Skip helpers and expressions with spaces (likely intentional)
48
+ if (!varName.includes(' ')) {
49
+ unresolved.push(varName)
50
+ }
51
+ }
52
+ }
53
+ return [...new Set(unresolved)]
54
+ }
55
+
56
+ /**
57
+ * Load and compile a Handlebars template with caching
58
+ */
59
+ async function loadTemplate(templatePath) {
60
+ if (templateCache.has(templatePath)) {
61
+ return templateCache.get(templatePath)
62
+ }
63
+
64
+ const template = await fs.readFile(templatePath, 'utf8')
65
+ const compiled = Handlebars.compile(template)
66
+ templateCache.set(templatePath, compiled)
67
+ return compiled
68
+ }
69
+
70
+ /**
71
+ * Process a single file - either copy or apply Handlebars
72
+ */
73
+ async function processFile(sourcePath, targetPath, data, options = {}) {
74
+ const isHbs = sourcePath.endsWith('.hbs')
75
+ const ext = path.extname(isHbs ? sourcePath.slice(0, -4) : sourcePath)
76
+ const isTextFile = TEXT_EXTENSIONS.has(ext)
77
+
78
+ if (isHbs) {
79
+ // Process Handlebars template
80
+ const template = await loadTemplate(sourcePath)
81
+ const content = template(data)
82
+
83
+ // Check for unresolved placeholders
84
+ const unresolved = findUnresolvedPlaceholders(content)
85
+ if (unresolved.length > 0 && options.onWarning) {
86
+ options.onWarning(`Unresolved placeholders in ${path.basename(targetPath)}: ${unresolved.join(', ')}`)
87
+ }
88
+
89
+ await fs.writeFile(targetPath, content)
90
+ } else if (isTextFile && options.processAllText) {
91
+ // Optionally process non-hbs text files for simple replacements
92
+ let content = await fs.readFile(sourcePath, 'utf8')
93
+ // Simple {{var}} replacement without full Handlebars
94
+ for (const [key, value] of Object.entries(data)) {
95
+ if (typeof value === 'string') {
96
+ content = content.replaceAll(`{{${key}}}`, value)
97
+ }
98
+ }
99
+ await fs.writeFile(targetPath, content)
100
+ } else {
101
+ // Binary or non-template file - just copy
102
+ await fs.copyFile(sourcePath, targetPath)
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Copy a directory structure recursively, processing templates
108
+ *
109
+ * @param {string} sourcePath - Source template directory
110
+ * @param {string} targetPath - Destination directory
111
+ * @param {Object} data - Template variables
112
+ * @param {Object} options - Processing options
113
+ * @param {string|null} options.variant - Template variant to use
114
+ * @param {Function} options.onWarning - Warning callback
115
+ * @param {Function} options.onProgress - Progress callback
116
+ */
117
+ export async function copyTemplateDirectory(sourcePath, targetPath, data, options = {}) {
118
+ const { variant = null, onWarning, onProgress } = options
119
+
120
+ await fs.mkdir(targetPath, { recursive: true })
121
+ const entries = await fs.readdir(sourcePath, { withFileTypes: true })
122
+
123
+ for (const entry of entries) {
124
+ const sourceName = entry.name
125
+
126
+ // Check if this is a variant-specific item (e.g., "dir.variant" or "file.variant.ext")
127
+ const variantMatch = entry.isDirectory()
128
+ ? sourceName.match(/^(.+)\.([^.]+)$/)
129
+ : null
130
+
131
+ if (entry.isDirectory()) {
132
+ if (variantMatch) {
133
+ const [, baseName, dirVariant] = variantMatch
134
+
135
+ // Skip directories that don't match our variant
136
+ if (variant && dirVariant !== variant) {
137
+ continue
138
+ }
139
+
140
+ // Use the base name without variant suffix for the target
141
+ const sourceFullPath = path.join(sourcePath, sourceName)
142
+ const targetFullPath = path.join(targetPath, baseName)
143
+
144
+ await copyTemplateDirectory(sourceFullPath, targetFullPath, data, options)
145
+ } else {
146
+ // Regular directory
147
+ const sourceFullPath = path.join(sourcePath, sourceName)
148
+ const targetFullPath = path.join(targetPath, sourceName)
149
+
150
+ await copyTemplateDirectory(sourceFullPath, targetFullPath, data, options)
151
+ }
152
+ } else {
153
+ // File processing
154
+ // Remove .hbs extension for target filename
155
+ const targetName = sourceName.endsWith('.hbs')
156
+ ? sourceName.slice(0, -4)
157
+ : sourceName
158
+
159
+ const sourceFullPath = path.join(sourcePath, sourceName)
160
+ const targetFullPath = path.join(targetPath, targetName)
161
+
162
+ // Skip if target already exists (don't overwrite)
163
+ if (existsSync(targetFullPath)) {
164
+ if (onWarning) {
165
+ onWarning(`Skipping ${targetFullPath} - file already exists`)
166
+ }
167
+ continue
168
+ }
169
+
170
+ if (onProgress) {
171
+ onProgress(`Creating ${targetName}`)
172
+ }
173
+
174
+ await processFile(sourceFullPath, targetFullPath, data, { onWarning })
175
+ }
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Clear the template cache
181
+ */
182
+ export function clearCache() {
183
+ templateCache.clear()
184
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Template validation - checks template.json and compatibility
3
+ */
4
+
5
+ import fs from 'node:fs/promises'
6
+ import { existsSync } from 'node:fs'
7
+ import path from 'node:path'
8
+
9
+ /**
10
+ * Simple semver satisfaction check
11
+ * Supports: >=x.y.z, ^x.y.z, ~x.y.z, x.y.z, x.y.x, *, latest
12
+ */
13
+ export function satisfiesVersion(version, range) {
14
+ if (!range || range === '*' || range === 'latest') {
15
+ return true
16
+ }
17
+
18
+ const parseVersion = (v) => {
19
+ const match = v.match(/^(\d+)\.(\d+)\.(\d+)/)
20
+ if (!match) return null
21
+ return {
22
+ major: parseInt(match[1], 10),
23
+ minor: parseInt(match[2], 10),
24
+ patch: parseInt(match[3], 10)
25
+ }
26
+ }
27
+
28
+ const current = parseVersion(version)
29
+ if (!current) return true // Can't parse, assume compatible
30
+
31
+ // Handle different range formats
32
+ if (range.startsWith('>=')) {
33
+ const min = parseVersion(range.slice(2))
34
+ if (!min) return true
35
+ if (current.major > min.major) return true
36
+ if (current.major < min.major) return false
37
+ if (current.minor > min.minor) return true
38
+ if (current.minor < min.minor) return false
39
+ return current.patch >= min.patch
40
+ }
41
+
42
+ if (range.startsWith('^')) {
43
+ // ^x.y.z means >=x.y.z and <(x+1).0.0
44
+ const min = parseVersion(range.slice(1))
45
+ if (!min) return true
46
+ if (current.major !== min.major) return current.major > min.major && min.major === 0
47
+ if (current.minor > min.minor) return true
48
+ if (current.minor < min.minor) return false
49
+ return current.patch >= min.patch
50
+ }
51
+
52
+ if (range.startsWith('~')) {
53
+ // ~x.y.z means >=x.y.z and <x.(y+1).0
54
+ const min = parseVersion(range.slice(1))
55
+ if (!min) return true
56
+ if (current.major !== min.major) return false
57
+ if (current.minor !== min.minor) return false
58
+ return current.patch >= min.patch
59
+ }
60
+
61
+ // Exact version or x.y.x pattern
62
+ if (range.includes('x')) {
63
+ const parts = range.split('.')
64
+ const min = parseVersion(range.replace(/x/g, '0'))
65
+ if (!min) return true
66
+ if (parts[0] !== 'x' && current.major !== min.major) return false
67
+ if (parts[1] !== 'x' && current.minor !== min.minor) return false
68
+ return true
69
+ }
70
+
71
+ // Exact match
72
+ const exact = parseVersion(range)
73
+ if (!exact) return true
74
+ return current.major === exact.major &&
75
+ current.minor === exact.minor &&
76
+ current.patch === exact.patch
77
+ }
78
+
79
+ /**
80
+ * Validation error with structured details
81
+ */
82
+ export class ValidationError extends Error {
83
+ constructor(message, code, details = {}) {
84
+ super(message)
85
+ this.name = 'ValidationError'
86
+ this.code = code
87
+ this.details = details
88
+ }
89
+ }
90
+
91
+ export const ErrorCodes = {
92
+ MISSING_TEMPLATE_JSON: 'MISSING_TEMPLATE_JSON',
93
+ INVALID_TEMPLATE_JSON: 'INVALID_TEMPLATE_JSON',
94
+ MISSING_TEMPLATE_DIR: 'MISSING_TEMPLATE_DIR',
95
+ MISSING_REQUIRED_FIELD: 'MISSING_REQUIRED_FIELD',
96
+ VERSION_MISMATCH: 'VERSION_MISMATCH',
97
+ }
98
+
99
+ /**
100
+ * Validate a template directory structure and metadata
101
+ *
102
+ * @param {string} templateRoot - Path to the template root (contains template.json)
103
+ * @param {Object} options - Validation options
104
+ * @param {string} options.uniwebVersion - Current Uniweb version to check compatibility
105
+ * @returns {Object} Parsed and validated template metadata
106
+ */
107
+ export async function validateTemplate(templateRoot, options = {}) {
108
+ const { uniwebVersion } = options
109
+
110
+ // Check for template.json
111
+ const metadataPath = path.join(templateRoot, 'template.json')
112
+ if (!existsSync(metadataPath)) {
113
+ throw new ValidationError(
114
+ `Missing template.json in ${templateRoot}`,
115
+ ErrorCodes.MISSING_TEMPLATE_JSON,
116
+ { path: templateRoot }
117
+ )
118
+ }
119
+
120
+ // Parse template.json
121
+ let metadata
122
+ try {
123
+ const content = await fs.readFile(metadataPath, 'utf8')
124
+ metadata = JSON.parse(content)
125
+ } catch (err) {
126
+ throw new ValidationError(
127
+ `Invalid template.json: ${err.message}`,
128
+ ErrorCodes.INVALID_TEMPLATE_JSON,
129
+ { path: metadataPath, error: err.message }
130
+ )
131
+ }
132
+
133
+ // Check required fields
134
+ if (!metadata.name) {
135
+ throw new ValidationError(
136
+ 'template.json missing required field: name',
137
+ ErrorCodes.MISSING_REQUIRED_FIELD,
138
+ { field: 'name' }
139
+ )
140
+ }
141
+
142
+ // Check for template/ directory
143
+ const templateDir = path.join(templateRoot, 'template')
144
+ if (!existsSync(templateDir)) {
145
+ throw new ValidationError(
146
+ `Missing template/ directory in ${templateRoot}`,
147
+ ErrorCodes.MISSING_TEMPLATE_DIR,
148
+ { path: templateRoot }
149
+ )
150
+ }
151
+
152
+ // Check version compatibility
153
+ if (uniwebVersion && metadata.uniweb) {
154
+ if (!satisfiesVersion(uniwebVersion, metadata.uniweb)) {
155
+ throw new ValidationError(
156
+ `Template requires Uniweb ${metadata.uniweb}, but current version is ${uniwebVersion}`,
157
+ ErrorCodes.VERSION_MISMATCH,
158
+ { required: metadata.uniweb, current: uniwebVersion }
159
+ )
160
+ }
161
+ }
162
+
163
+ return {
164
+ ...metadata,
165
+ templateDir,
166
+ metadataPath
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Get list of available templates in a templates directory
172
+ *
173
+ * @param {string} templatesDir - Path to directory containing templates
174
+ * @returns {Array<Object>} List of template metadata
175
+ */
176
+ export async function listTemplates(templatesDir) {
177
+ if (!existsSync(templatesDir)) {
178
+ return []
179
+ }
180
+
181
+ const entries = await fs.readdir(templatesDir, { withFileTypes: true })
182
+ const templates = []
183
+
184
+ for (const entry of entries) {
185
+ if (!entry.isDirectory()) continue
186
+
187
+ const templatePath = path.join(templatesDir, entry.name)
188
+ const metadataPath = path.join(templatePath, 'template.json')
189
+
190
+ if (existsSync(metadataPath)) {
191
+ try {
192
+ const content = await fs.readFile(metadataPath, 'utf8')
193
+ const metadata = JSON.parse(content)
194
+ templates.push({
195
+ id: entry.name,
196
+ ...metadata,
197
+ path: templatePath
198
+ })
199
+ } catch {
200
+ // Skip invalid templates
201
+ }
202
+ }
203
+ }
204
+
205
+ return templates
206
+ }
@@ -0,0 +1,56 @@
1
+ # {{projectName}}
2
+
3
+ A marketing site built with [Uniweb](https://uniweb.io).
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ pnpm install
10
+
11
+ # Start development server
12
+ pnpm dev
13
+
14
+ # Build for production
15
+ pnpm build
16
+ ```
17
+
18
+ ## Project Structure
19
+
20
+ ```
21
+ {{projectName}}/
22
+ ├── foundation/ # Component library
23
+ │ └── src/
24
+ │ └── components/
25
+ │ ├── Hero/
26
+ │ ├── Features/
27
+ │ ├── Pricing/
28
+ │ ├── Testimonials/
29
+ │ └── CTA/
30
+ └── site/ # Marketing site
31
+ └── pages/
32
+ └── home/
33
+ ├── 1-hero.md
34
+ ├── 2-features.md
35
+ ├── 3-pricing.md
36
+ ├── 4-testimonials.md
37
+ └── 5-cta.md
38
+ ```
39
+
40
+ ## Components
41
+
42
+ - **Hero** - Eye-catching header with headline, description, and call-to-action
43
+ - **Features** - Showcase product features with icons and descriptions
44
+ - **Pricing** - Pricing table with multiple tiers
45
+ - **Testimonials** - Customer quotes and social proof
46
+ - **CTA** - Call-to-action section to drive conversions
47
+
48
+ ## Customization
49
+
50
+ Edit the markdown files in `site/pages/` to update content. Each section file has YAML frontmatter for configuration and markdown body for content.
51
+
52
+ Edit component styles in `foundation/src/components/*/index.jsx`.
53
+
54
+ ---
55
+
56
+ Created with the Uniweb Marketing Template
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "{{projectName}}-foundation",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./src/index.js",
6
+ "exports": {
7
+ ".": "./src/index.js",
8
+ "./styles": "./src/styles.css",
9
+ "./dist": "./dist/foundation.js",
10
+ "./dist/styles": "./dist/assets/style.css"
11
+ },
12
+ "files": ["dist", "src"],
13
+ "scripts": {
14
+ "dev": "vite",
15
+ "build": "uniweb build",
16
+ "build:vite": "vite build",
17
+ "preview": "vite preview"
18
+ },
19
+ "peerDependencies": {
20
+ "react": "^18.0.0",
21
+ "react-dom": "^18.0.0"
22
+ },
23
+ "devDependencies": {
24
+ "@vitejs/plugin-react": "^4.2.1",
25
+ "autoprefixer": "^10.4.18",
26
+ "postcss": "^8.4.35",
27
+ "react": "^18.2.0",
28
+ "react-dom": "^18.2.0",
29
+ "tailwindcss": "^3.4.1",
30
+ "uniweb": "^0.2.0",
31
+ "vite": "^5.1.0",
32
+ "vite-plugin-svgr": "^4.2.0"
33
+ }
34
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }