pni 1.0.1 → 1.0.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/dist/app.js +5 -1
- package/dist/template_code/css/tailwind.css.template +214 -0
- package/dist/template_code/nuxt/app.vue.template +25 -0
- package/dist/template_code/nuxt/nuxt.config.ts.template +90 -0
- package/dist/template_code/nuxt/pages/index.vue.template +14 -0
- package/dist/template_code/nuxt/pages/typography/index.vue.template +46 -0
- package/dist/template_code/postcss/postcss.config.js.template +7 -0
- package/dist/template_code/tailwind/tailwind.config.js.template +52 -0
- package/dist/template_code/vite/vite.config.ts.template +82 -0
- package/dist/utils/config-generator.d.ts +1 -0
- package/dist/utils/config-generator.js +52 -244
- package/dist/utils/css-variables.js +4 -263
- package/dist/utils/template-loader.d.ts +13 -0
- package/dist/utils/template-loader.js +52 -0
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -4,7 +4,7 @@ import { detectProjectType } from './utils/project-detection.js';
|
|
|
4
4
|
import { createApp } from './utils/app-creation.js';
|
|
5
5
|
import { detectPackageManager, getInstallCommand, getDevInstallCommand, } from './utils/package-manager.js';
|
|
6
6
|
import { getDependencies } from './utils/dependencies.js';
|
|
7
|
-
import { generateConfigFiles } from './utils/config-generator.js';
|
|
7
|
+
import { generateConfigFiles, setupNuxtAppStructure } from './utils/config-generator.js';
|
|
8
8
|
import { generateCSSVariables, updateIndexHtml, createTypographyPage } from './utils/css-variables.js';
|
|
9
9
|
import { setupShadcnNuxt } from './utils/shadcn-setup.js';
|
|
10
10
|
import FeatureSelector from './components/FeatureSelector.js';
|
|
@@ -71,6 +71,10 @@ export default function App({ nuxt = false, vue = false, threejs = false, cssVar
|
|
|
71
71
|
// Generate configuration files
|
|
72
72
|
setStep('configuring');
|
|
73
73
|
await generateConfigFiles(finalProjectType, workingPath, selectedFeatures.threejs, selectedFeatures.cssVars);
|
|
74
|
+
// Set up Nuxt app structure (app.vue, pages/index.vue, Lenis)
|
|
75
|
+
if (finalProjectType === 'nuxt') {
|
|
76
|
+
await setupNuxtAppStructure(workingPath);
|
|
77
|
+
}
|
|
74
78
|
// Generate CSS variables (always enabled - will be overwritten after shadcn-setup)
|
|
75
79
|
if (finalProjectType === 'nuxt') {
|
|
76
80
|
// For Nuxt, first create basic tailwind.css
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
|
|
4
|
+
@font-face {
|
|
5
|
+
font-family: 'Helvetica';
|
|
6
|
+
src: url('~/assets/fonts/Helvetica.ttf') format('truetype');
|
|
7
|
+
font-weight: normal;
|
|
8
|
+
font-style: normal;
|
|
9
|
+
font-display: swap;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@custom-variant dark (&:is(.dark *));
|
|
13
|
+
|
|
14
|
+
@theme inline {
|
|
15
|
+
--spacing: 4rem;
|
|
16
|
+
--font-helvetica: 'Helvetica', sans-serif;
|
|
17
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
18
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
19
|
+
--radius-lg: var(--radius);
|
|
20
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
21
|
+
--color-background: var(--background);
|
|
22
|
+
--color-foreground: var(--foreground);
|
|
23
|
+
--color-card: var(--card);
|
|
24
|
+
--color-card-foreground: var(--card-foreground);
|
|
25
|
+
--color-popover: var(--popover);
|
|
26
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
27
|
+
--color-primary: var(--primary);
|
|
28
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
29
|
+
--color-secondary: var(--secondary);
|
|
30
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
31
|
+
--color-muted: var(--muted);
|
|
32
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
33
|
+
--color-accent: var(--accent);
|
|
34
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
35
|
+
--color-destructive: var(--destructive);
|
|
36
|
+
--color-border: var(--border);
|
|
37
|
+
--color-input: var(--input);
|
|
38
|
+
--color-ring: var(--ring);
|
|
39
|
+
--color-chart-1: var(--chart-1);
|
|
40
|
+
--color-chart-2: var(--chart-2);
|
|
41
|
+
--color-chart-3: var(--chart-3);
|
|
42
|
+
--color-chart-4: var(--chart-4);
|
|
43
|
+
--color-chart-5: var(--chart-5);
|
|
44
|
+
--color-sidebar: var(--sidebar);
|
|
45
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
46
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
47
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
48
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
49
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
50
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
51
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
:root {
|
|
55
|
+
/* osmo scaling system starts here */
|
|
56
|
+
--size-unit: 16; /* body font-size in design - no px */
|
|
57
|
+
--size-container-ideal: 1440; /* screen-size in design - no px */
|
|
58
|
+
--size-container-min: 992px;
|
|
59
|
+
--size-container-max: 1920px;
|
|
60
|
+
--size-container: clamp(var(--size-container-min), 100vw, var(--size-container-max));
|
|
61
|
+
--size-font: calc(var(--size-container) / (var(--size-container-ideal) / var(--size-unit)));
|
|
62
|
+
|
|
63
|
+
/* 1 fluid pixel unit */
|
|
64
|
+
--fluid-px: calc(var(--size-font) / 16);
|
|
65
|
+
/* osmo scaling system ends here */
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
--radius: 0.625rem;
|
|
70
|
+
--background: oklch(1 0 0);
|
|
71
|
+
--foreground: oklch(0.145 0 0);
|
|
72
|
+
--card: oklch(1 0 0);
|
|
73
|
+
--card-foreground: oklch(0.145 0 0);
|
|
74
|
+
--popover: oklch(1 0 0);
|
|
75
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
76
|
+
--primary: oklch(0.205 0 0);
|
|
77
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
78
|
+
--secondary: oklch(0.97 0 0);
|
|
79
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
80
|
+
--muted: oklch(0.97 0 0);
|
|
81
|
+
--muted-foreground: oklch(0.556 0 0);
|
|
82
|
+
--accent: oklch(0.97 0 0);
|
|
83
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
84
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
85
|
+
--border: oklch(0.922 0 0);
|
|
86
|
+
--input: oklch(0.922 0 0);
|
|
87
|
+
--ring: oklch(0.708 0 0);
|
|
88
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
89
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
90
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
91
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
92
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
93
|
+
--sidebar: oklch(0.985 0 0);
|
|
94
|
+
--sidebar-foreground: oklch(0.145 0 0);
|
|
95
|
+
--sidebar-primary: oklch(0.205 0 0);
|
|
96
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
97
|
+
--sidebar-accent: oklch(0.97 0 0);
|
|
98
|
+
--sidebar-accent-foreground: oklch(0.205 0 0);
|
|
99
|
+
--sidebar-border: oklch(0.922 0 0);
|
|
100
|
+
--sidebar-ring: oklch(0.708 0 0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.dark {
|
|
104
|
+
--background: oklch(0.145 0 0);
|
|
105
|
+
--foreground: oklch(0.985 0 0);
|
|
106
|
+
--card: oklch(0.205 0 0);
|
|
107
|
+
--card-foreground: oklch(0.985 0 0);
|
|
108
|
+
--popover: oklch(0.205 0 0);
|
|
109
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
110
|
+
--primary: oklch(0.922 0 0);
|
|
111
|
+
--primary-foreground: oklch(0.205 0 0);
|
|
112
|
+
--secondary: oklch(0.269 0 0);
|
|
113
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
114
|
+
--muted: oklch(0.269 0 0);
|
|
115
|
+
--muted-foreground: oklch(0.708 0 0);
|
|
116
|
+
--accent: oklch(0.269 0 0);
|
|
117
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
118
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
119
|
+
--border: oklch(1 0 0 / 10%);
|
|
120
|
+
--input: oklch(1 0 0 / 15%);
|
|
121
|
+
--ring: oklch(0.556 0 0);
|
|
122
|
+
--chart-1: oklch(0.488 0.243 264.376);
|
|
123
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
124
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
125
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
126
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
127
|
+
--sidebar: oklch(0.205 0 0);
|
|
128
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
129
|
+
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
130
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
131
|
+
--sidebar-accent: oklch(0.269 0 0);
|
|
132
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
133
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
134
|
+
--sidebar-ring: oklch(0.556 0 0);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@layer base {
|
|
138
|
+
* {
|
|
139
|
+
@apply border-border outline-ring/50;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
body {
|
|
143
|
+
@apply bg-background text-foreground;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
html {
|
|
148
|
+
font-size: var(--fluid-px);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
body {
|
|
152
|
+
/* figma design 16px fontsize = 16rem fluid pixel unit */
|
|
153
|
+
font-size: 16rem;
|
|
154
|
+
font-family: var(--font-helvetica);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
/* osmo scaling system starts here */
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
.container {
|
|
162
|
+
max-width: var(--size-container);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.container.medium {
|
|
166
|
+
max-width: calc(var(--size-container) * 0.85);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.container.small {
|
|
170
|
+
max-width: calc(var(--size-container) * 0.7);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Tablet */
|
|
174
|
+
@media screen and (max-width: 991px) {
|
|
175
|
+
:root {
|
|
176
|
+
--size-container-ideal: 834;
|
|
177
|
+
/* screen-size in design - no px */
|
|
178
|
+
--size-container-min: 768px;
|
|
179
|
+
--size-container-max: 991px;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
body {
|
|
183
|
+
background-color: red;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* Mobile Landscape */
|
|
188
|
+
@media screen and (max-width: 767px) {
|
|
189
|
+
:root {
|
|
190
|
+
--size-container-ideal: 550;
|
|
191
|
+
/* screen-size in design - no px */
|
|
192
|
+
--size-container-min: 480px;
|
|
193
|
+
--size-container-max: 767px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
body {
|
|
197
|
+
background-color: blue;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* Mobile Portrait */
|
|
202
|
+
@media screen and (max-width: 479px) {
|
|
203
|
+
:root {
|
|
204
|
+
--size-container-ideal: 375;
|
|
205
|
+
/* screen-size in design - no px */
|
|
206
|
+
--size-container-min: 320px;
|
|
207
|
+
--size-container-max: 479px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
body {
|
|
211
|
+
background-color: green;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { VueLenis } from 'lenis/vue'
|
|
3
|
+
|
|
4
|
+
const lenisOptions = {
|
|
5
|
+
// Lenis options (optional)
|
|
6
|
+
duration: 1.2,
|
|
7
|
+
easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
|
|
8
|
+
orientation: 'vertical',
|
|
9
|
+
gestureOrientation: 'vertical',
|
|
10
|
+
smoothWheel: true,
|
|
11
|
+
wheelMultiplier: 1,
|
|
12
|
+
smoothTouch: false,
|
|
13
|
+
touchMultiplier: 2,
|
|
14
|
+
infinite: false,
|
|
15
|
+
}
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<VueLenis root :options="lenisOptions">
|
|
20
|
+
<NuxtLayout>
|
|
21
|
+
<NuxtPage />
|
|
22
|
+
</NuxtLayout>
|
|
23
|
+
</VueLenis>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{{TAILWIND_IMPORT}}// https://nuxt.com/docs/api/configuration/nuxt-config
|
|
2
|
+
export default defineNuxtConfig({
|
|
3
|
+
// 1. Updated to a realistic 2024/2025 date for Nuxt 4 features
|
|
4
|
+
compatibilityDate: '2024-11-01',
|
|
5
|
+
devtools: { enabled: true },
|
|
6
|
+
|
|
7
|
+
{{CSS_IMPORT}} ssr: true,
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// SEO: Centralizing data
|
|
11
|
+
site: {
|
|
12
|
+
name: 'New Setup',
|
|
13
|
+
url: 'https://newsetup.com',
|
|
14
|
+
description: 'A new setup for your project',
|
|
15
|
+
defaultLocale: 'en',
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
// App Config for UI-wide settings
|
|
19
|
+
app: {
|
|
20
|
+
head: {
|
|
21
|
+
charset: 'utf-8',
|
|
22
|
+
viewport: 'width=device-width, initial-scale=1',
|
|
23
|
+
meta: [
|
|
24
|
+
{ name: 'description', content: 'A new setup for your project' },
|
|
25
|
+
{ name: 'author', content: 'New Setup' },
|
|
26
|
+
{ property: 'og:type', content: 'website' },
|
|
27
|
+
{ name: 'msapplication-TileColor', content: '#000000' },
|
|
28
|
+
{ name: 'theme-color', content: '#000000' },
|
|
29
|
+
],
|
|
30
|
+
link: [
|
|
31
|
+
// { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
|
|
32
|
+
// { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon-180x180.png' },
|
|
33
|
+
// { rel: 'manifest', href: '/manifest.webmanifest' },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
{{VITE_CONFIG}} nitro: {
|
|
39
|
+
compressPublicAssets: {
|
|
40
|
+
brotli: true,
|
|
41
|
+
gzip: true,
|
|
42
|
+
},
|
|
43
|
+
// Enable crawling for SEO module compatibility
|
|
44
|
+
prerender: {
|
|
45
|
+
// set to true for production
|
|
46
|
+
crawlLinks: false,
|
|
47
|
+
routes: ['/']
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
modules: [{{MODULES}}],
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
// Image Optimization
|
|
55
|
+
image: {
|
|
56
|
+
quality: 95,
|
|
57
|
+
format: ['webp'],
|
|
58
|
+
screens: {
|
|
59
|
+
xs: 320,
|
|
60
|
+
sm: 640,
|
|
61
|
+
md: 768,
|
|
62
|
+
lg: 1200,
|
|
63
|
+
xl: 1400,
|
|
64
|
+
xxl: 1800,
|
|
65
|
+
'2xl': 2000,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// UI Framework: Shadcn
|
|
70
|
+
{{SHADCN_CONFIG}} ogImage: {
|
|
71
|
+
defaults: {
|
|
72
|
+
component: 'OgImageTemplate',
|
|
73
|
+
props: {
|
|
74
|
+
title: 'New Setup',
|
|
75
|
+
description: 'A new setup for your project',
|
|
76
|
+
image: 'https://newsetup.com/og-image.png',
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
robots: {
|
|
81
|
+
disallow: ['/api',],
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
sitemap: {
|
|
87
|
+
// sources: ['/api/__sitemap__/urls'] // Fetch from API
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
</script>
|
|
3
|
+
|
|
4
|
+
<template>
|
|
5
|
+
<div class="min-h-screen flex items-center justify-center">
|
|
6
|
+
<div class="text-center">
|
|
7
|
+
<h1 class="text-4xl font-bold mb-4">Welcome to Nuxt</h1>
|
|
8
|
+
<p class="text-lg text-muted-foreground">
|
|
9
|
+
Get started by editing <code class="px-2 py-1 bg-muted rounded">app/pages/index.vue</code>
|
|
10
|
+
</p>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
</script>
|
|
3
|
+
|
|
4
|
+
<template>
|
|
5
|
+
<section class="w-full py-20 px-4 min-h-screen flex items-center justify-center bg-[#DADADA] flex-col gap-16 ">
|
|
6
|
+
<div class="hero-container flex flex-col gap-16 leading-[1.2]">
|
|
7
|
+
<!-- figma design 120px fontsize -->
|
|
8
|
+
<h1 class="md:text-[120rem] text-[72rem]">Heading H1</h1>
|
|
9
|
+
<div class="divider"></div>
|
|
10
|
+
<!-- figma design 80px fontsize -->
|
|
11
|
+
<h2 class="md:text-[80rem] text-[64rem]">Heading H2</h2>
|
|
12
|
+
<div class="divider"></div>
|
|
13
|
+
<h3 class="md:text-[40rem] text-[32rem]">Heading H3</h3>
|
|
14
|
+
<!-- figma design 40px fontsize -->
|
|
15
|
+
<div class="divider"></div>
|
|
16
|
+
<h4 class="md:text-[28rem] text-[24rem]">Heading H4</h4>
|
|
17
|
+
<!-- figma design 28px fontsize -->
|
|
18
|
+
<div class="divider"></div>
|
|
19
|
+
<h5 class="md:text-[20rem] text-[18rem]">Heading H5</h5>
|
|
20
|
+
<!-- figma design 20px fontsize -->
|
|
21
|
+
<div class="divider"></div>
|
|
22
|
+
<!-- figma design 16px fontsize -->
|
|
23
|
+
<p class="text-[16rem] leading-[1.4] max-md:max-w-85.75 w-full font-helvetica">
|
|
24
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum
|
|
25
|
+
tristique. Duis cursus, all links in the website, eros dolor interdum nulla, ut commodo diam libero
|
|
26
|
+
vitae erat. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
|
|
27
|
+
laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae
|
|
28
|
+
vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
|
29
|
+
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
|
|
30
|
+
</p>
|
|
31
|
+
</div>
|
|
32
|
+
</section>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<style scoped>
|
|
36
|
+
.hero-container {
|
|
37
|
+
max-width: calc(1184em / 16);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.divider {
|
|
41
|
+
background-color: #969696;
|
|
42
|
+
height: 1px;
|
|
43
|
+
width: 100%;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
46
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
export default {
|
|
3
|
+
content: [
|
|
4
|
+
{{CONTENT_PATHS}}
|
|
5
|
+
],
|
|
6
|
+
theme: {
|
|
7
|
+
extend: {
|
|
8
|
+
colors: {
|
|
9
|
+
background: 'hsl(var(--background))',
|
|
10
|
+
foreground: 'hsl(var(--foreground))',
|
|
11
|
+
card: {
|
|
12
|
+
DEFAULT: 'hsl(var(--card))',
|
|
13
|
+
foreground: 'hsl(var(--card-foreground))',
|
|
14
|
+
},
|
|
15
|
+
popover: {
|
|
16
|
+
DEFAULT: 'hsl(var(--popover))',
|
|
17
|
+
foreground: 'hsl(var(--popover-foreground))',
|
|
18
|
+
},
|
|
19
|
+
primary: {
|
|
20
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
21
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
22
|
+
},
|
|
23
|
+
secondary: {
|
|
24
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
25
|
+
foreground: 'hsl(var(--secondary-foreground))',
|
|
26
|
+
},
|
|
27
|
+
muted: {
|
|
28
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
29
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
30
|
+
},
|
|
31
|
+
accent: {
|
|
32
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
33
|
+
foreground: 'hsl(var(--accent-foreground))',
|
|
34
|
+
},
|
|
35
|
+
destructive: {
|
|
36
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
37
|
+
foreground: 'hsl(var(--destructive-foreground))',
|
|
38
|
+
},
|
|
39
|
+
border: 'hsl(var(--border))',
|
|
40
|
+
input: 'hsl(var(--input))',
|
|
41
|
+
ring: 'hsl(var(--ring))',
|
|
42
|
+
},
|
|
43
|
+
borderRadius: {
|
|
44
|
+
lg: 'var(--radius)',
|
|
45
|
+
md: 'calc(var(--radius) - 2px)',
|
|
46
|
+
sm: 'calc(var(--radius) - 4px)',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
plugins: [],
|
|
51
|
+
}
|
|
52
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { fileURLToPath, URL } from 'node:url'
|
|
2
|
+
{{TAILWIND_IMPORT}}import { defineConfig } from 'vite'
|
|
3
|
+
import vue from '@vitejs/plugin-vue'
|
|
4
|
+
import vueDevTools from 'vite-plugin-vue-devtools'
|
|
5
|
+
import viteCompression from 'vite-plugin-compression'
|
|
6
|
+
import Sitemap from 'vite-plugin-sitemap'
|
|
7
|
+
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'
|
|
8
|
+
|
|
9
|
+
export default defineConfig(({ mode }) => {
|
|
10
|
+
const isProd = mode === 'production'
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
plugins: [
|
|
14
|
+
vue(),
|
|
15
|
+
{{TAILWIND_PLUGIN}} // 1. Only load DevTools in development
|
|
16
|
+
!isProd && vueDevTools(),
|
|
17
|
+
|
|
18
|
+
ViteImageOptimizer({
|
|
19
|
+
test: /\.(jpe?g|png|gif|tiff|webp|svg|avif)$/i,
|
|
20
|
+
includePublic: true,
|
|
21
|
+
logStats: true,
|
|
22
|
+
png: { quality: 75 },
|
|
23
|
+
jpeg: { quality: 75 },
|
|
24
|
+
jpg: { quality: 75 },
|
|
25
|
+
webp: { lossless: false, quality: 75 },
|
|
26
|
+
avif: { quality: 70 },
|
|
27
|
+
}),
|
|
28
|
+
|
|
29
|
+
Sitemap({
|
|
30
|
+
hostname: 'https://newsetup.com', // Don't forget to update this!
|
|
31
|
+
dynamicRoutes: [],
|
|
32
|
+
}),
|
|
33
|
+
|
|
34
|
+
// 2. Gzip Compression (Universal Fallback)
|
|
35
|
+
viteCompression({
|
|
36
|
+
algorithm: 'gzip',
|
|
37
|
+
ext: '.gz',
|
|
38
|
+
threshold: 10240,
|
|
39
|
+
deleteOriginFile: false,
|
|
40
|
+
}),
|
|
41
|
+
|
|
42
|
+
// 3. Brotli Compression (Modern Performance)
|
|
43
|
+
viteCompression({
|
|
44
|
+
algorithm: 'brotliCompress',
|
|
45
|
+
ext: '.br',
|
|
46
|
+
threshold: 10240,
|
|
47
|
+
deleteOriginFile: false,
|
|
48
|
+
}),
|
|
49
|
+
],
|
|
50
|
+
|
|
51
|
+
resolve: {
|
|
52
|
+
alias: {
|
|
53
|
+
'@': fileURLToPath(new URL('./src', import.meta.url))
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
build: {
|
|
58
|
+
cssMinify: 'lightningcss', // Ensure 'lightningcss' is in package.json
|
|
59
|
+
// 4. Split Chunks for better Browser Caching
|
|
60
|
+
rollupOptions: {
|
|
61
|
+
output: {
|
|
62
|
+
manualChunks(id) {
|
|
63
|
+
if (id.includes('node_modules')) {
|
|
64
|
+
// Split standard Vue dependencies into their own chunk
|
|
65
|
+
if (id.includes('vue') || id.includes('pinia') || id.includes('vue-router')) {
|
|
66
|
+
return 'vue-vendor';
|
|
67
|
+
}
|
|
68
|
+
{{THREEJS_CHUNK}}
|
|
69
|
+
|
|
70
|
+
return 'vendor';
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
esbuild: {
|
|
78
|
+
drop: isProd ? ['console', 'debugger'] : [],
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
@@ -3,4 +3,5 @@ export declare function generateNuxtConfig(projectPath: string, threejs: boolean
|
|
|
3
3
|
export declare function generateViteConfig(projectPath: string, threejs: boolean, cssVars?: boolean): Promise<void>;
|
|
4
4
|
export declare function generateTailwindConfig(projectPath: string, projectType: ProjectType): Promise<void>;
|
|
5
5
|
export declare function generatePostCSSConfig(projectPath: string): Promise<void>;
|
|
6
|
+
export declare function setupNuxtAppStructure(projectPath: string): Promise<void>;
|
|
6
7
|
export declare function generateConfigFiles(projectType: ProjectType, projectPath: string, threejs: boolean, cssVars: boolean): Promise<void>;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
+
import { loadTemplateWithReplacements, loadTemplate } from './template-loader.js';
|
|
3
4
|
export async function generateNuxtConfig(projectPath,
|
|
4
5
|
//@ts-ignore
|
|
5
6
|
threejs, cssVars) {
|
|
6
7
|
const configPath = join(projectPath, 'nuxt.config.ts');
|
|
7
8
|
// Always replace the config with the full template, regardless of whether it exists
|
|
8
|
-
// Generate full config template
|
|
9
9
|
const modules = [
|
|
10
|
+
'lenis/nuxt',
|
|
10
11
|
'shadcn-nuxt',
|
|
11
12
|
'@nuxtjs/seo',
|
|
12
13
|
'@nuxt/image',
|
|
@@ -17,44 +18,7 @@ threejs, cssVars) {
|
|
|
17
18
|
const tailwindImport = cssVars
|
|
18
19
|
? "import tailwindcss from '@tailwindcss/vite'\n\n"
|
|
19
20
|
: '';
|
|
20
|
-
const
|
|
21
|
-
export default defineNuxtConfig({
|
|
22
|
-
// 1. Updated to a realistic 2024/2025 date for Nuxt 4 features
|
|
23
|
-
compatibilityDate: '2024-11-01',
|
|
24
|
-
devtools: { enabled: true },
|
|
25
|
-
|
|
26
|
-
${cssVars ? ` css: ['${cssImport}'],\n\n` : ''} ssr: true,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// SEO: Centralizing data
|
|
30
|
-
site: {
|
|
31
|
-
name: 'New Setup',
|
|
32
|
-
url: 'https://newsetup.com',
|
|
33
|
-
description: 'A new setup for your project',
|
|
34
|
-
defaultLocale: 'en',
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
// App Config for UI-wide settings
|
|
38
|
-
app: {
|
|
39
|
-
head: {
|
|
40
|
-
charset: 'utf-8',
|
|
41
|
-
viewport: 'width=device-width, initial-scale=1',
|
|
42
|
-
meta: [
|
|
43
|
-
{ name: 'description', content: 'A new setup for your project' },
|
|
44
|
-
{ name: 'author', content: 'New Setup' },
|
|
45
|
-
{ property: 'og:type', content: 'website' },
|
|
46
|
-
{ name: 'msapplication-TileColor', content: '#000000' },
|
|
47
|
-
{ name: 'theme-color', content: '#000000' },
|
|
48
|
-
],
|
|
49
|
-
link: [
|
|
50
|
-
// { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
|
|
51
|
-
// { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon-180x180.png' },
|
|
52
|
-
// { rel: 'manifest', href: '/manifest.webmanifest' },
|
|
53
|
-
],
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
${cssVars
|
|
21
|
+
const viteConfig = cssVars
|
|
58
22
|
? ` vite: {
|
|
59
23
|
plugins: [tailwindcss()],
|
|
60
24
|
esbuild: {
|
|
@@ -67,39 +31,8 @@ ${cssVars
|
|
|
67
31
|
},
|
|
68
32
|
|
|
69
33
|
`
|
|
70
|
-
: ''
|
|
71
|
-
|
|
72
|
-
brotli: true,
|
|
73
|
-
gzip: true,
|
|
74
|
-
},
|
|
75
|
-
// Enable crawling for SEO module compatibility
|
|
76
|
-
prerender: {
|
|
77
|
-
// set to true for production
|
|
78
|
-
crawlLinks: false,
|
|
79
|
-
routes: ['/']
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
modules: [${modules.map(m => `'${m}'`).join(', ')}],
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// Image Optimization
|
|
87
|
-
image: {
|
|
88
|
-
quality: 95,
|
|
89
|
-
format: ['webp'],
|
|
90
|
-
screens: {
|
|
91
|
-
xs: 320,
|
|
92
|
-
sm: 640,
|
|
93
|
-
md: 768,
|
|
94
|
-
lg: 1200,
|
|
95
|
-
xl: 1400,
|
|
96
|
-
xxl: 1800,
|
|
97
|
-
'2xl': 2000,
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
// UI Framework: Shadcn
|
|
102
|
-
${cssVars
|
|
34
|
+
: '';
|
|
35
|
+
const shadcnConfig = cssVars
|
|
103
36
|
? ` shadcn: {
|
|
104
37
|
prefix: '',
|
|
105
38
|
componentDir: '@/components/ui',
|
|
@@ -107,27 +40,15 @@ ${cssVars
|
|
|
107
40
|
|
|
108
41
|
|
|
109
42
|
`
|
|
110
|
-
: ''
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
robots: {
|
|
121
|
-
disallow: ['/api',],
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
sitemap: {
|
|
127
|
-
// sources: ['/api/__sitemap__/urls'] // Fetch from API
|
|
128
|
-
},
|
|
129
|
-
})
|
|
130
|
-
`;
|
|
43
|
+
: '';
|
|
44
|
+
const cssImportLine = cssVars ? ` css: ['${cssImport}'],\n\n` : '';
|
|
45
|
+
const configContent = loadTemplateWithReplacements('nuxt/nuxt.config.ts.template', {
|
|
46
|
+
TAILWIND_IMPORT: tailwindImport,
|
|
47
|
+
CSS_IMPORT: cssImportLine,
|
|
48
|
+
VITE_CONFIG: viteConfig,
|
|
49
|
+
MODULES: modules.map(m => `'${m}'`).join(', '),
|
|
50
|
+
SHADCN_CONFIG: shadcnConfig,
|
|
51
|
+
});
|
|
131
52
|
// Always write the full config, replacing any existing one
|
|
132
53
|
writeFileSync(configPath, configContent, 'utf-8');
|
|
133
54
|
}
|
|
@@ -159,167 +80,54 @@ threejs, cssVars = false) {
|
|
|
159
80
|
? "import tailwindcss from '@tailwindcss/vite'\n"
|
|
160
81
|
: '';
|
|
161
82
|
const tailwindPlugin = cssVars ? ' tailwindcss(),\n' : '';
|
|
162
|
-
configContent =
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
import Sitemap from 'vite-plugin-sitemap'
|
|
168
|
-
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'
|
|
169
|
-
|
|
170
|
-
export default defineConfig(({ mode }) => {
|
|
171
|
-
const isProd = mode === 'production'
|
|
172
|
-
|
|
173
|
-
return {
|
|
174
|
-
plugins: [
|
|
175
|
-
vue(),
|
|
176
|
-
${tailwindPlugin} // 1. Only load DevTools in development
|
|
177
|
-
!isProd && vueDevTools(),
|
|
178
|
-
|
|
179
|
-
ViteImageOptimizer({
|
|
180
|
-
test: /\\.(jpe?g|png|gif|tiff|webp|svg|avif)$/i,
|
|
181
|
-
includePublic: true,
|
|
182
|
-
logStats: true,
|
|
183
|
-
png: { quality: 75 },
|
|
184
|
-
jpeg: { quality: 75 },
|
|
185
|
-
jpg: { quality: 75 },
|
|
186
|
-
webp: { lossless: false, quality: 75 },
|
|
187
|
-
avif: { quality: 70 },
|
|
188
|
-
}),
|
|
189
|
-
|
|
190
|
-
Sitemap({
|
|
191
|
-
hostname: 'https://newsetup.com', // Don't forget to update this!
|
|
192
|
-
dynamicRoutes: [],
|
|
193
|
-
}),
|
|
194
|
-
|
|
195
|
-
// 2. Gzip Compression (Universal Fallback)
|
|
196
|
-
viteCompression({
|
|
197
|
-
algorithm: 'gzip',
|
|
198
|
-
ext: '.gz',
|
|
199
|
-
threshold: 10240,
|
|
200
|
-
deleteOriginFile: false,
|
|
201
|
-
}),
|
|
202
|
-
|
|
203
|
-
// 3. Brotli Compression (Modern Performance)
|
|
204
|
-
viteCompression({
|
|
205
|
-
algorithm: 'brotliCompress',
|
|
206
|
-
ext: '.br',
|
|
207
|
-
threshold: 10240,
|
|
208
|
-
deleteOriginFile: false,
|
|
209
|
-
}),
|
|
210
|
-
],
|
|
211
|
-
|
|
212
|
-
resolve: {
|
|
213
|
-
alias: {
|
|
214
|
-
'@': fileURLToPath(new URL('./src', import.meta.url))
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
|
|
218
|
-
build: {
|
|
219
|
-
cssMinify: 'lightningcss', // Ensure 'lightningcss' is in package.json
|
|
220
|
-
// 4. Split Chunks for better Browser Caching
|
|
221
|
-
rollupOptions: {
|
|
222
|
-
output: {
|
|
223
|
-
manualChunks(id) {
|
|
224
|
-
if (id.includes('node_modules')) {
|
|
225
|
-
// Split standard Vue dependencies into their own chunk
|
|
226
|
-
if (id.includes('vue') || id.includes('pinia') || id.includes('vue-router')) {
|
|
227
|
-
return 'vue-vendor';
|
|
228
|
-
}
|
|
229
|
-
${threejsChunk}
|
|
230
|
-
|
|
231
|
-
return 'vendor';
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
},
|
|
237
|
-
|
|
238
|
-
esbuild: {
|
|
239
|
-
drop: isProd ? ['console', 'debugger'] : [],
|
|
240
|
-
},
|
|
241
|
-
}
|
|
242
|
-
})
|
|
243
|
-
`;
|
|
83
|
+
configContent = loadTemplateWithReplacements('vite/vite.config.ts.template', {
|
|
84
|
+
TAILWIND_IMPORT: tailwindImport,
|
|
85
|
+
TAILWIND_PLUGIN: tailwindPlugin,
|
|
86
|
+
THREEJS_CHUNK: threejsChunk,
|
|
87
|
+
});
|
|
244
88
|
}
|
|
245
89
|
writeFileSync(configPath, configContent, 'utf-8');
|
|
246
90
|
}
|
|
247
91
|
export async function generateTailwindConfig(projectPath, projectType) {
|
|
248
92
|
const configPath = join(projectPath, 'tailwind.config.js');
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
colors: {
|
|
266
|
-
background: 'hsl(var(--background))',
|
|
267
|
-
foreground: 'hsl(var(--foreground))',
|
|
268
|
-
card: {
|
|
269
|
-
DEFAULT: 'hsl(var(--card))',
|
|
270
|
-
foreground: 'hsl(var(--card-foreground))',
|
|
271
|
-
},
|
|
272
|
-
popover: {
|
|
273
|
-
DEFAULT: 'hsl(var(--popover))',
|
|
274
|
-
foreground: 'hsl(var(--popover-foreground))',
|
|
275
|
-
},
|
|
276
|
-
primary: {
|
|
277
|
-
DEFAULT: 'hsl(var(--primary))',
|
|
278
|
-
foreground: 'hsl(var(--primary-foreground))',
|
|
279
|
-
},
|
|
280
|
-
secondary: {
|
|
281
|
-
DEFAULT: 'hsl(var(--secondary))',
|
|
282
|
-
foreground: 'hsl(var(--secondary-foreground))',
|
|
283
|
-
},
|
|
284
|
-
muted: {
|
|
285
|
-
DEFAULT: 'hsl(var(--muted))',
|
|
286
|
-
foreground: 'hsl(var(--muted-foreground))',
|
|
287
|
-
},
|
|
288
|
-
accent: {
|
|
289
|
-
DEFAULT: 'hsl(var(--accent))',
|
|
290
|
-
foreground: 'hsl(var(--accent-foreground))',
|
|
291
|
-
},
|
|
292
|
-
destructive: {
|
|
293
|
-
DEFAULT: 'hsl(var(--destructive))',
|
|
294
|
-
foreground: 'hsl(var(--destructive-foreground))',
|
|
295
|
-
},
|
|
296
|
-
border: 'hsl(var(--border))',
|
|
297
|
-
input: 'hsl(var(--input))',
|
|
298
|
-
ring: 'hsl(var(--ring))',
|
|
299
|
-
},
|
|
300
|
-
borderRadius: {
|
|
301
|
-
lg: 'var(--radius)',
|
|
302
|
-
md: 'calc(var(--radius) - 2px)',
|
|
303
|
-
sm: 'calc(var(--radius) - 4px)',
|
|
304
|
-
},
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
plugins: [],
|
|
308
|
-
}
|
|
309
|
-
`;
|
|
93
|
+
let contentPaths;
|
|
94
|
+
if (projectType === 'nuxt') {
|
|
95
|
+
contentPaths = ` './components/**/*.{js,vue,ts}',
|
|
96
|
+
'./layouts/**/*.vue',
|
|
97
|
+
'./pages/**/*.vue',
|
|
98
|
+
'./plugins/**/*.{js,ts}',
|
|
99
|
+
'./app.vue',
|
|
100
|
+
'./error.vue',`;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
contentPaths = ` './index.html',
|
|
104
|
+
'./src/**/*.{vue,js,ts,jsx,tsx}',`;
|
|
105
|
+
}
|
|
106
|
+
const configContent = loadTemplateWithReplacements('tailwind/tailwind.config.js.template', {
|
|
107
|
+
CONTENT_PATHS: contentPaths,
|
|
108
|
+
});
|
|
310
109
|
writeFileSync(configPath, configContent, 'utf-8');
|
|
311
110
|
}
|
|
312
111
|
export async function generatePostCSSConfig(projectPath) {
|
|
313
112
|
const configPath = join(projectPath, 'postcss.config.js');
|
|
314
|
-
const configContent =
|
|
315
|
-
plugins: {
|
|
316
|
-
tailwindcss: {},
|
|
317
|
-
autoprefixer: {},
|
|
318
|
-
},
|
|
319
|
-
}
|
|
320
|
-
`;
|
|
113
|
+
const configContent = loadTemplate('postcss/postcss.config.js.template');
|
|
321
114
|
writeFileSync(configPath, configContent, 'utf-8');
|
|
322
115
|
}
|
|
116
|
+
export async function setupNuxtAppStructure(projectPath) {
|
|
117
|
+
// Set up app.vue with NuxtLayout, NuxtPage, and Lenis
|
|
118
|
+
const appVuePath = join(projectPath, 'app.vue');
|
|
119
|
+
const appVueContent = loadTemplate('nuxt/app.vue.template');
|
|
120
|
+
writeFileSync(appVuePath, appVueContent, 'utf-8');
|
|
121
|
+
// Create app/pages directory if it doesn't exist
|
|
122
|
+
const pagesDir = join(projectPath, 'app', 'pages');
|
|
123
|
+
if (!existsSync(pagesDir)) {
|
|
124
|
+
mkdirSync(pagesDir, { recursive: true });
|
|
125
|
+
}
|
|
126
|
+
// Create app/pages/index.vue
|
|
127
|
+
const indexPagePath = join(pagesDir, 'index.vue');
|
|
128
|
+
const indexPageContent = loadTemplate('nuxt/pages/index.vue.template');
|
|
129
|
+
writeFileSync(indexPagePath, indexPageContent, 'utf-8');
|
|
130
|
+
}
|
|
323
131
|
export async function generateConfigFiles(projectType, projectPath, threejs, cssVars) {
|
|
324
132
|
if (projectType === 'nuxt') {
|
|
325
133
|
await generateNuxtConfig(projectPath, threejs, cssVars);
|
|
@@ -1,221 +1,6 @@
|
|
|
1
1
|
import { writeFileSync, mkdirSync, readFileSync, existsSync } from 'fs';
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
|
-
|
|
4
|
-
@import "tailwindcss";
|
|
5
|
-
@import "tw-animate-css";
|
|
6
|
-
|
|
7
|
-
@font-face {
|
|
8
|
-
font-family: 'Helvetica';
|
|
9
|
-
src: url('~/assets/fonts/Helvetica.ttf') format('truetype');
|
|
10
|
-
font-weight: normal;
|
|
11
|
-
font-style: normal;
|
|
12
|
-
font-display: swap;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@custom-variant dark (&:is(.dark *));
|
|
16
|
-
|
|
17
|
-
@theme inline {
|
|
18
|
-
--spacing: 4rem;
|
|
19
|
-
--font-helvetica: 'Helvetica', sans-serif;
|
|
20
|
-
--radius-sm: calc(var(--radius) - 4px);
|
|
21
|
-
--radius-md: calc(var(--radius) - 2px);
|
|
22
|
-
--radius-lg: var(--radius);
|
|
23
|
-
--radius-xl: calc(var(--radius) + 4px);
|
|
24
|
-
--color-background: var(--background);
|
|
25
|
-
--color-foreground: var(--foreground);
|
|
26
|
-
--color-card: var(--card);
|
|
27
|
-
--color-card-foreground: var(--card-foreground);
|
|
28
|
-
--color-popover: var(--popover);
|
|
29
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
30
|
-
--color-primary: var(--primary);
|
|
31
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
32
|
-
--color-secondary: var(--secondary);
|
|
33
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
34
|
-
--color-muted: var(--muted);
|
|
35
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
36
|
-
--color-accent: var(--accent);
|
|
37
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
38
|
-
--color-destructive: var(--destructive);
|
|
39
|
-
--color-border: var(--border);
|
|
40
|
-
--color-input: var(--input);
|
|
41
|
-
--color-ring: var(--ring);
|
|
42
|
-
--color-chart-1: var(--chart-1);
|
|
43
|
-
--color-chart-2: var(--chart-2);
|
|
44
|
-
--color-chart-3: var(--chart-3);
|
|
45
|
-
--color-chart-4: var(--chart-4);
|
|
46
|
-
--color-chart-5: var(--chart-5);
|
|
47
|
-
--color-sidebar: var(--sidebar);
|
|
48
|
-
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
49
|
-
--color-sidebar-primary: var(--sidebar-primary);
|
|
50
|
-
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
51
|
-
--color-sidebar-accent: var(--sidebar-accent);
|
|
52
|
-
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
53
|
-
--color-sidebar-border: var(--sidebar-border);
|
|
54
|
-
--color-sidebar-ring: var(--sidebar-ring);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
:root {
|
|
58
|
-
/* osmo scaling system starts here */
|
|
59
|
-
--size-unit: 16; /* body font-size in design - no px */
|
|
60
|
-
--size-container-ideal: 1440; /* screen-size in design - no px */
|
|
61
|
-
--size-container-min: 992px;
|
|
62
|
-
--size-container-max: 1920px;
|
|
63
|
-
--size-container: clamp(var(--size-container-min), 100vw, var(--size-container-max));
|
|
64
|
-
--size-font: calc(var(--size-container) / (var(--size-container-ideal) / var(--size-unit)));
|
|
65
|
-
|
|
66
|
-
/* 1 fluid pixel unit */
|
|
67
|
-
--fluid-px: calc(var(--size-font) / 16);
|
|
68
|
-
/* osmo scaling system ends here */
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
--radius: 0.625rem;
|
|
73
|
-
--background: oklch(1 0 0);
|
|
74
|
-
--foreground: oklch(0.145 0 0);
|
|
75
|
-
--card: oklch(1 0 0);
|
|
76
|
-
--card-foreground: oklch(0.145 0 0);
|
|
77
|
-
--popover: oklch(1 0 0);
|
|
78
|
-
--popover-foreground: oklch(0.145 0 0);
|
|
79
|
-
--primary: oklch(0.205 0 0);
|
|
80
|
-
--primary-foreground: oklch(0.985 0 0);
|
|
81
|
-
--secondary: oklch(0.97 0 0);
|
|
82
|
-
--secondary-foreground: oklch(0.205 0 0);
|
|
83
|
-
--muted: oklch(0.97 0 0);
|
|
84
|
-
--muted-foreground: oklch(0.556 0 0);
|
|
85
|
-
--accent: oklch(0.97 0 0);
|
|
86
|
-
--accent-foreground: oklch(0.205 0 0);
|
|
87
|
-
--destructive: oklch(0.577 0.245 27.325);
|
|
88
|
-
--border: oklch(0.922 0 0);
|
|
89
|
-
--input: oklch(0.922 0 0);
|
|
90
|
-
--ring: oklch(0.708 0 0);
|
|
91
|
-
--chart-1: oklch(0.646 0.222 41.116);
|
|
92
|
-
--chart-2: oklch(0.6 0.118 184.704);
|
|
93
|
-
--chart-3: oklch(0.398 0.07 227.392);
|
|
94
|
-
--chart-4: oklch(0.828 0.189 84.429);
|
|
95
|
-
--chart-5: oklch(0.769 0.188 70.08);
|
|
96
|
-
--sidebar: oklch(0.985 0 0);
|
|
97
|
-
--sidebar-foreground: oklch(0.145 0 0);
|
|
98
|
-
--sidebar-primary: oklch(0.205 0 0);
|
|
99
|
-
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
100
|
-
--sidebar-accent: oklch(0.97 0 0);
|
|
101
|
-
--sidebar-accent-foreground: oklch(0.205 0 0);
|
|
102
|
-
--sidebar-border: oklch(0.922 0 0);
|
|
103
|
-
--sidebar-ring: oklch(0.708 0 0);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.dark {
|
|
107
|
-
--background: oklch(0.145 0 0);
|
|
108
|
-
--foreground: oklch(0.985 0 0);
|
|
109
|
-
--card: oklch(0.205 0 0);
|
|
110
|
-
--card-foreground: oklch(0.985 0 0);
|
|
111
|
-
--popover: oklch(0.205 0 0);
|
|
112
|
-
--popover-foreground: oklch(0.985 0 0);
|
|
113
|
-
--primary: oklch(0.922 0 0);
|
|
114
|
-
--primary-foreground: oklch(0.205 0 0);
|
|
115
|
-
--secondary: oklch(0.269 0 0);
|
|
116
|
-
--secondary-foreground: oklch(0.985 0 0);
|
|
117
|
-
--muted: oklch(0.269 0 0);
|
|
118
|
-
--muted-foreground: oklch(0.708 0 0);
|
|
119
|
-
--accent: oklch(0.269 0 0);
|
|
120
|
-
--accent-foreground: oklch(0.985 0 0);
|
|
121
|
-
--destructive: oklch(0.704 0.191 22.216);
|
|
122
|
-
--border: oklch(1 0 0 / 10%);
|
|
123
|
-
--input: oklch(1 0 0 / 15%);
|
|
124
|
-
--ring: oklch(0.556 0 0);
|
|
125
|
-
--chart-1: oklch(0.488 0.243 264.376);
|
|
126
|
-
--chart-2: oklch(0.696 0.17 162.48);
|
|
127
|
-
--chart-3: oklch(0.769 0.188 70.08);
|
|
128
|
-
--chart-4: oklch(0.627 0.265 303.9);
|
|
129
|
-
--chart-5: oklch(0.645 0.246 16.439);
|
|
130
|
-
--sidebar: oklch(0.205 0 0);
|
|
131
|
-
--sidebar-foreground: oklch(0.985 0 0);
|
|
132
|
-
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
133
|
-
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
134
|
-
--sidebar-accent: oklch(0.269 0 0);
|
|
135
|
-
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
136
|
-
--sidebar-border: oklch(1 0 0 / 10%);
|
|
137
|
-
--sidebar-ring: oklch(0.556 0 0);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
@layer base {
|
|
141
|
-
* {
|
|
142
|
-
@apply border-border outline-ring/50;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
body {
|
|
146
|
-
@apply bg-background text-foreground;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
html {
|
|
151
|
-
font-size: var(--fluid-px);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
body {
|
|
155
|
-
/* figma design 16px fontsize = 16rem fluid pixel unit */
|
|
156
|
-
font-size: 16rem;
|
|
157
|
-
font-family: var(--font-helvetica);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
/* osmo scaling system starts here */
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
.container {
|
|
165
|
-
max-width: var(--size-container);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
.container.medium {
|
|
169
|
-
max-width: calc(var(--size-container) * 0.85);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.container.small {
|
|
173
|
-
max-width: calc(var(--size-container) * 0.7);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/* Tablet */
|
|
177
|
-
@media screen and (max-width: 991px) {
|
|
178
|
-
:root {
|
|
179
|
-
--size-container-ideal: 834;
|
|
180
|
-
/* screen-size in design - no px */
|
|
181
|
-
--size-container-min: 768px;
|
|
182
|
-
--size-container-max: 991px;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
body {
|
|
186
|
-
background-color: red;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/* Mobile Landscape */
|
|
191
|
-
@media screen and (max-width: 767px) {
|
|
192
|
-
:root {
|
|
193
|
-
--size-container-ideal: 550;
|
|
194
|
-
/* screen-size in design - no px */
|
|
195
|
-
--size-container-min: 480px;
|
|
196
|
-
--size-container-max: 767px;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
body {
|
|
200
|
-
background-color: blue;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/* Mobile Portrait */
|
|
205
|
-
@media screen and (max-width: 479px) {
|
|
206
|
-
:root {
|
|
207
|
-
--size-container-ideal: 375;
|
|
208
|
-
/* screen-size in design - no px */
|
|
209
|
-
--size-container-min: 320px;
|
|
210
|
-
--size-container-max: 479px;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
body {
|
|
214
|
-
background-color: green;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
`;
|
|
3
|
+
import { loadTemplate } from './template-loader.js';
|
|
219
4
|
export async function generateCSSVariables(projectType, projectPath, initialSetup = false) {
|
|
220
5
|
let cssPath;
|
|
221
6
|
if (projectType === 'nuxt') {
|
|
@@ -234,7 +19,8 @@ export async function generateCSSVariables(projectType, projectPath, initialSetu
|
|
|
234
19
|
}
|
|
235
20
|
else {
|
|
236
21
|
// Overwrite the CSS file with full content
|
|
237
|
-
|
|
22
|
+
const cssContent = loadTemplate('css/tailwind.css.template');
|
|
23
|
+
writeFileSync(cssPath, cssContent.trim() + '\n', 'utf-8');
|
|
238
24
|
}
|
|
239
25
|
}
|
|
240
26
|
export async function updateIndexHtml(projectPath) {
|
|
@@ -270,51 +56,6 @@ export async function createTypographyPage(projectPath, projectType) {
|
|
|
270
56
|
const typographyPagePath = join(pagesDir, 'typography', 'index.vue');
|
|
271
57
|
// Ensure directory exists
|
|
272
58
|
mkdirSync(dirname(typographyPagePath), { recursive: true });
|
|
273
|
-
const typographyPageContent =
|
|
274
|
-
</script>
|
|
275
|
-
|
|
276
|
-
<template>
|
|
277
|
-
<section class="w-full py-20 px-4 min-h-screen flex items-center justify-center bg-[#DADADA] flex-col gap-16 ">
|
|
278
|
-
<div class="hero-container flex flex-col gap-16 leading-[1.2]">
|
|
279
|
-
<!-- figma design 120px fontsize -->
|
|
280
|
-
<h1 class="md:text-[120rem] text-[72rem]">Heading H1</h1>
|
|
281
|
-
<div class="divider"></div>
|
|
282
|
-
<!-- figma design 80px fontsize -->
|
|
283
|
-
<h2 class="md:text-[80rem] text-[64rem]">Heading H2</h2>
|
|
284
|
-
<div class="divider"></div>
|
|
285
|
-
<h3 class="md:text-[40rem] text-[32rem]">Heading H3</h3>
|
|
286
|
-
<!-- figma design 40px fontsize -->
|
|
287
|
-
<div class="divider"></div>
|
|
288
|
-
<h4 class="md:text-[28rem] text-[24rem]">Heading H4</h4>
|
|
289
|
-
<!-- figma design 28px fontsize -->
|
|
290
|
-
<div class="divider"></div>
|
|
291
|
-
<h5 class="md:text-[20rem] text-[18rem]">Heading H5</h5>
|
|
292
|
-
<!-- figma design 20px fontsize -->
|
|
293
|
-
<div class="divider"></div>
|
|
294
|
-
<!-- figma design 16px fontsize -->
|
|
295
|
-
<p class="text-[16rem] leading-[1.4] max-md:max-w-85.75 w-full font-helvetica">
|
|
296
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum
|
|
297
|
-
tristique. Duis cursus, all links in the website, eros dolor interdum nulla, ut commodo diam libero
|
|
298
|
-
vitae erat. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
|
|
299
|
-
laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae
|
|
300
|
-
vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
|
301
|
-
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
|
|
302
|
-
</p>
|
|
303
|
-
</div>
|
|
304
|
-
</section>
|
|
305
|
-
</template>
|
|
306
|
-
|
|
307
|
-
<style scoped>
|
|
308
|
-
.hero-container {
|
|
309
|
-
max-width: calc(1184em / 16);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
.divider {
|
|
313
|
-
background-color: #969696;
|
|
314
|
-
height: 1px;
|
|
315
|
-
width: 100%;
|
|
316
|
-
}
|
|
317
|
-
</style>
|
|
318
|
-
`;
|
|
59
|
+
const typographyPageContent = loadTemplate('nuxt/pages/typography/index.vue.template');
|
|
319
60
|
writeFileSync(typographyPagePath, typographyPageContent, 'utf-8');
|
|
320
61
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load a template file and return its content
|
|
3
|
+
* @param templatePath - Path to template file relative to template_code directory
|
|
4
|
+
* @returns Template content as string
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadTemplate(templatePath: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Load a template and replace placeholders
|
|
9
|
+
* @param templatePath - Path to template file relative to template_code directory
|
|
10
|
+
* @param replacements - Object with placeholder keys and replacement values
|
|
11
|
+
* @returns Template content with replacements applied
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadTemplateWithReplacements(templatePath: string, replacements: Record<string, string>): string;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = dirname(__filename);
|
|
6
|
+
/**
|
|
7
|
+
* Get the template directory path
|
|
8
|
+
* When compiled: dist/utils/template-loader.js -> dist/template_code
|
|
9
|
+
* When in source: source/utils/template-loader.ts -> source/template_code
|
|
10
|
+
*/
|
|
11
|
+
function getTemplateDir() {
|
|
12
|
+
let templateDir = join(__dirname, '..', 'template_code');
|
|
13
|
+
// Check if template directory exists, if not try source location
|
|
14
|
+
if (!existsSync(templateDir)) {
|
|
15
|
+
// Try from source location (for development/testing)
|
|
16
|
+
const sourceTemplateDir = join(__dirname, '..', '..', 'source', 'template_code');
|
|
17
|
+
if (existsSync(sourceTemplateDir)) {
|
|
18
|
+
return sourceTemplateDir;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return templateDir;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Load a template file and return its content
|
|
25
|
+
* @param templatePath - Path to template file relative to template_code directory
|
|
26
|
+
* @returns Template content as string
|
|
27
|
+
*/
|
|
28
|
+
export function loadTemplate(templatePath) {
|
|
29
|
+
const templateDir = getTemplateDir();
|
|
30
|
+
const fullPath = join(templateDir, templatePath);
|
|
31
|
+
try {
|
|
32
|
+
return readFileSync(fullPath, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw new Error(`Template not found: ${fullPath}. Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load a template and replace placeholders
|
|
40
|
+
* @param templatePath - Path to template file relative to template_code directory
|
|
41
|
+
* @param replacements - Object with placeholder keys and replacement values
|
|
42
|
+
* @returns Template content with replacements applied
|
|
43
|
+
*/
|
|
44
|
+
export function loadTemplateWithReplacements(templatePath, replacements) {
|
|
45
|
+
let content = loadTemplate(templatePath);
|
|
46
|
+
// Replace all placeholders in format {{KEY}}
|
|
47
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
48
|
+
const placeholder = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
|
|
49
|
+
content = content.replace(placeholder, value);
|
|
50
|
+
}
|
|
51
|
+
return content;
|
|
52
|
+
}
|