pni 1.0.0 → 1.0.1

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 CHANGED
@@ -82,7 +82,7 @@ export default function App({ nuxt = false, vue = false, threejs = false, cssVar
82
82
  await generateCSSVariables(finalProjectType, workingPath, false);
83
83
  // Create typography page after CSS variables are set up
84
84
  if (selectedFeatures.cssVars) {
85
- await createTypographyPage(workingPath);
85
+ await createTypographyPage(workingPath, finalProjectType);
86
86
  }
87
87
  }
88
88
  else {
@@ -98,9 +98,24 @@ export async function addThree(currentDir) {
98
98
  mkdirSync(composablesTargetDir, { recursive: true });
99
99
  }
100
100
  // Calculate import path from composables/{directoryName} to three folder
101
- // In Nuxt/Vue, @/ resolves to project root (Nuxt) or src (Vue), so we use the path relative to project root
102
- const threePathRelative = relative(projectRoot, targetDir).replace(/\\/g, '/');
103
- const importPath = `@/${threePathRelative}/World.js`;
101
+ // The import path should be @/pages/{directoryName}/three/World.js when run in a pages directory
102
+ const currentPathRelative = relative(projectRoot, currentPath).replace(/\\/g, '/');
103
+ // Check if the current path is in a pages directory
104
+ let importPath;
105
+ if (currentPathRelative.startsWith('pages/')) {
106
+ // If we're in a pages directory (Vue), use @/pages/{directoryName}/three/World.js
107
+ importPath = `@/pages/${directoryName}/three/World.js`;
108
+ }
109
+ else if (currentPathRelative.startsWith('app/pages/')) {
110
+ // If we're in app/pages directory (Nuxt), use @/pages/{directoryName}/three/World.js
111
+ // Note: @/ in Nuxt resolves to project root, so app/pages becomes pages
112
+ importPath = `@/pages/${directoryName}/three/World.js`;
113
+ }
114
+ else {
115
+ // Otherwise, use the relative path from project root
116
+ const threePathRelative = relative(projectRoot, targetDir).replace(/\\/g, '/');
117
+ importPath = `@/${threePathRelative}/World.js`;
118
+ }
104
119
  // Determine file extension based on project type
105
120
  const fileExtension = projectType === 'vue' ? 'js' : 'ts';
106
121
  // Create usethree.{js|ts}
@@ -4,24 +4,20 @@ export async function generateNuxtConfig(projectPath,
4
4
  //@ts-ignore
5
5
  threejs, cssVars) {
6
6
  const configPath = join(projectPath, 'nuxt.config.ts');
7
- let configContent = '';
8
- if (existsSync(configPath)) {
9
- configContent = readFileSync(configPath, 'utf-8');
10
- }
11
- else {
12
- // Generate full config template
13
- const modules = [
14
- 'shadcn-nuxt',
15
- '@nuxtjs/seo',
16
- '@nuxt/image',
17
- '@nuxtjs/device',
18
- ];
19
- // Use assets/css/tailwind.css for Nuxt projects
20
- const cssImport = '~/assets/css/tailwind.css';
21
- const tailwindImport = cssVars
22
- ? "import tailwindcss from '@tailwindcss/vite'\n\n"
23
- : '';
24
- configContent = `${tailwindImport}// https://nuxt.com/docs/api/configuration/nuxt-config
7
+ // Always replace the config with the full template, regardless of whether it exists
8
+ // Generate full config template
9
+ const modules = [
10
+ 'shadcn-nuxt',
11
+ '@nuxtjs/seo',
12
+ '@nuxt/image',
13
+ '@nuxtjs/device',
14
+ ];
15
+ // Use assets/css/tailwind.css for Nuxt projects
16
+ const cssImport = '~/assets/css/tailwind.css';
17
+ const tailwindImport = cssVars
18
+ ? "import tailwindcss from '@tailwindcss/vite'\n\n"
19
+ : '';
20
+ const configContent = `${tailwindImport}// https://nuxt.com/docs/api/configuration/nuxt-config
25
21
  export default defineNuxtConfig({
26
22
  // 1. Updated to a realistic 2024/2025 date for Nuxt 4 features
27
23
  compatibilityDate: '2024-11-01',
@@ -59,7 +55,7 @@ ${cssVars ? ` css: ['${cssImport}'],\n\n` : ''} ssr: true,
59
55
  },
60
56
 
61
57
  ${cssVars
62
- ? ` vite: {
58
+ ? ` vite: {
63
59
  plugins: [tailwindcss()],
64
60
  esbuild: {
65
61
  drop: process.env.NODE_ENV === 'production' ? ['console', 'debugger'] : [],
@@ -71,7 +67,7 @@ ${cssVars
71
67
  },
72
68
 
73
69
  `
74
- : ''} nitro: {
70
+ : ''} nitro: {
75
71
  compressPublicAssets: {
76
72
  brotli: true,
77
73
  gzip: true,
@@ -104,14 +100,14 @@ ${cssVars
104
100
 
105
101
  // UI Framework: Shadcn
106
102
  ${cssVars
107
- ? ` shadcn: {
103
+ ? ` shadcn: {
108
104
  prefix: '',
109
105
  componentDir: '@/components/ui',
110
106
  },
111
107
 
112
108
 
113
109
  `
114
- : ''} ogImage: {
110
+ : ''} ogImage: {
115
111
  defaults: {
116
112
  component: 'OgImageTemplate',
117
113
  props: {
@@ -132,180 +128,7 @@ ${cssVars
132
128
  },
133
129
  })
134
130
  `;
135
- writeFileSync(configPath, configContent, 'utf-8');
136
- return;
137
- }
138
- // If config exists, merge new modules and settings
139
- const modules = [];
140
- if (cssVars && !configContent.includes('shadcn-nuxt')) {
141
- modules.push('shadcn-nuxt');
142
- }
143
- if (!configContent.includes('@nuxtjs/seo')) {
144
- modules.push('@nuxtjs/seo');
145
- }
146
- if (!configContent.includes('@nuxt/image')) {
147
- modules.push('@nuxt/image');
148
- }
149
- if (!configContent.includes('@nuxtjs/device')) {
150
- modules.push('@nuxtjs/device');
151
- }
152
- // Add compatibilityDate if not present
153
- if (!configContent.includes('compatibilityDate')) {
154
- configContent = configContent.replace(/export default defineNuxtConfig\(\{/, `export default defineNuxtConfig({
155
- // 1. Updated to a realistic 2024/2025 date for Nuxt 4 features
156
- compatibilityDate: '2024-11-01',`);
157
- }
158
- // Add ssr if not present
159
- if (!configContent.includes('ssr:')) {
160
- configContent = configContent.replace(/compatibilityDate:\s*'[^']*',/, `$&\n ssr: true,`);
161
- }
162
- // Add CSS import if cssVars is true
163
- if (cssVars) {
164
- // Use assets/css/tailwind.css for Nuxt projects
165
- const cssImport = '~/assets/css/tailwind.css';
166
- if (!configContent.includes('import tailwindcss')) {
167
- configContent = `import tailwindcss from '@tailwindcss/vite'\n\n${configContent}`;
168
- }
169
- if (!configContent.includes('css:')) {
170
- configContent = configContent.replace(/devtools:\s*\{[^}]*\},/, `$&\n\n css: ['${cssImport}'],`);
171
- }
172
- else if (!configContent.includes(cssImport)) {
173
- configContent = configContent.replace(/css:\s*\[/, `css: ['${cssImport}',`);
174
- }
175
- }
176
- // Add vite plugins for Tailwind if cssVars is true
177
- if (cssVars && !configContent.includes('@tailwindcss/vite')) {
178
- if (!configContent.includes('vite:')) {
179
- configContent = configContent.replace(/ssr:\s*true,/, `$&\n\n vite: {
180
- plugins: [tailwindcss()],
181
- esbuild: {
182
- drop: process.env.NODE_ENV === 'production' ? ['console', 'debugger'] : [],
183
- },
184
- build: {
185
- // Ensures CSS is also minified correctly by lightningcss (default in Vite 6)
186
- cssMinify: 'lightningcss'
187
- }
188
- },`);
189
- }
190
- else if (!configContent.includes('tailwindcss()')) {
191
- configContent = configContent.replace(/vite:\s*\{/, `vite: {
192
- plugins: [tailwindcss()],`);
193
- }
194
- }
195
- // Add modules
196
- if (modules.length > 0) {
197
- if (configContent.includes('modules:')) {
198
- // Add to existing modules array
199
- const existingModules = configContent.match(/modules:\s*\[([^\]]*)\]/);
200
- if (existingModules && existingModules[1]) {
201
- const existingModuleList = existingModules[1].trim();
202
- const allModules = [...modules];
203
- if (existingModuleList) {
204
- const existing = existingModuleList
205
- .split(',')
206
- .map(m => m.trim().replace(/['"]/g, ''));
207
- allModules.push(...existing);
208
- }
209
- const uniqueModules = [...new Set(allModules)];
210
- configContent = configContent.replace(/modules:\s*\[[^\]]*\]/, `modules: [${uniqueModules.map(m => `'${m}'`).join(', ')}]`);
211
- }
212
- }
213
- else {
214
- // Add new modules array
215
- configContent = configContent.replace(/ssr:\s*true,/, `$&\n\n modules: [${modules.map(m => `'${m}'`).join(', ')}],`);
216
- }
217
- }
218
- // Add app.head config if not present
219
- if (!configContent.includes('app:')) {
220
- configContent = configContent.replace(/site:\s*\{[^}]*\},/, `$&\n\n // App Config for UI-wide settings
221
- app: {
222
- head: {
223
- charset: 'utf-8',
224
- viewport: 'width=device-width, initial-scale=1',
225
- meta: [
226
- { name: 'description', content: 'A new setup for your project' },
227
- { name: 'author', content: 'New Setup' },
228
- { property: 'og:type', content: 'website' },
229
- { name: 'msapplication-TileColor', content: '#000000' },
230
- { name: 'theme-color', content: '#000000' },
231
- ],
232
- link: [
233
- // { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
234
- // { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon-180x180.png' },
235
- // { rel: 'manifest', href: '/manifest.webmanifest' },
236
- ],
237
- },
238
- },`);
239
- }
240
- // Add nitro config if not present
241
- if (!configContent.includes('nitro:')) {
242
- configContent = configContent.replace(/vite:\s*\{[^}]*\},/, `$&\n\n nitro: {
243
- compressPublicAssets: {
244
- brotli: true,
245
- gzip: true,
246
- },
247
- // Enable crawling for SEO module compatibility
248
- prerender: {
249
- // set to true for production
250
- crawlLinks: false,
251
- routes: ['/']
252
- }
253
- },`);
254
- }
255
- // Add image config if not present
256
- if (!configContent.includes('image:')) {
257
- configContent = configContent.replace(/modules:\s*\[[^\]]*\],/, `$&\n\n // Image Optimization
258
- image: {
259
- quality: 95,
260
- format: ['webp'],
261
- screens: {
262
- xs: 320,
263
- sm: 640,
264
- md: 768,
265
- lg: 1200,
266
- xl: 1400,
267
- xxl: 1800,
268
- '2xl': 2000,
269
- },
270
- },`);
271
- }
272
- // Add shadcn config if cssVars is true
273
- if (cssVars && !configContent.includes('shadcn:')) {
274
- configContent = configContent.replace(/image:\s*\{[^}]*\},/, `$&\n\n // UI Framework: Shadcn
275
- shadcn: {
276
- prefix: '',
277
- componentDir: '@/components/ui',
278
- },`);
279
- }
280
- // Update site config if not present
281
- if (!configContent.includes('site:')) {
282
- configContent = configContent.replace(/compatibilityDate:\s*'[^']*',/, `$&\n\n // SEO: Centralizing data
283
- site: {
284
- name: 'New Setup',
285
- url: 'https://newsetup.com',
286
- description: 'A new setup for your project',
287
- defaultLocale: 'en',
288
- },`);
289
- }
290
- // Update ogImage config if not present
291
- if (!configContent.includes('ogImage:')) {
292
- configContent = configContent.replace(/sitemap:\s*\{[^}]*\},/, `$&\n ogImage: {
293
- defaults: {
294
- component: 'OgImageTemplate',
295
- props: {
296
- title: 'New Setup',
297
- description: 'A new setup for your project',
298
- image: 'https://newsetup.com/og-image.png',
299
- },
300
- }
301
- },`);
302
- }
303
- // Update robots config if not present
304
- if (!configContent.includes('robots:')) {
305
- configContent = configContent.replace(/ogImage:\s*\{[^}]*\},/, `$&\n robots: {
306
- disallow: ['/api',],
307
- },`);
308
- }
131
+ // Always write the full config, replacing any existing one
309
132
  writeFileSync(configPath, configContent, 'utf-8');
310
133
  }
311
134
  export async function generateViteConfig(projectPath,
@@ -337,86 +160,86 @@ threejs, cssVars = false) {
337
160
  : '';
338
161
  const tailwindPlugin = cssVars ? ' tailwindcss(),\n' : '';
339
162
  configContent = `import { fileURLToPath, URL } from 'node:url'
340
- ${tailwindImport}import { defineConfig } from 'vite'
341
- import vue from '@vitejs/plugin-vue'
342
- import vueDevTools from 'vite-plugin-vue-devtools'
343
- import viteCompression from 'vite-plugin-compression'
344
- import Sitemap from 'vite-plugin-sitemap'
345
- import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'
163
+ ${tailwindImport}import { defineConfig } from 'vite'
164
+ import vue from '@vitejs/plugin-vue'
165
+ import vueDevTools from 'vite-plugin-vue-devtools'
166
+ import viteCompression from 'vite-plugin-compression'
167
+ import Sitemap from 'vite-plugin-sitemap'
168
+ import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'
346
169
 
347
- export default defineConfig(({ mode }) => {
348
- const isProd = mode === 'production'
170
+ export default defineConfig(({ mode }) => {
171
+ const isProd = mode === 'production'
349
172
 
350
- return {
351
- plugins: [
352
- vue(),
353
- ${tailwindPlugin} // 1. Only load DevTools in development
354
- !isProd && vueDevTools(),
173
+ return {
174
+ plugins: [
175
+ vue(),
176
+ ${tailwindPlugin} // 1. Only load DevTools in development
177
+ !isProd && vueDevTools(),
355
178
 
356
- ViteImageOptimizer({
357
- test: /\\.(jpe?g|png|gif|tiff|webp|svg|avif)$/i,
358
- includePublic: true,
359
- logStats: true,
360
- png: { quality: 75 },
361
- jpeg: { quality: 75 },
362
- jpg: { quality: 75 },
363
- webp: { lossless: false, quality: 75 },
364
- avif: { quality: 70 },
365
- }),
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
+ }),
366
189
 
367
- Sitemap({
368
- hostname: 'https://newsetup.com', // Don't forget to update this!
369
- dynamicRoutes: [],
370
- }),
190
+ Sitemap({
191
+ hostname: 'https://newsetup.com', // Don't forget to update this!
192
+ dynamicRoutes: [],
193
+ }),
371
194
 
372
- // 2. Gzip Compression (Universal Fallback)
373
- viteCompression({
374
- algorithm: 'gzip',
375
- ext: '.gz',
376
- threshold: 10240,
377
- deleteOriginFile: false,
378
- }),
195
+ // 2. Gzip Compression (Universal Fallback)
196
+ viteCompression({
197
+ algorithm: 'gzip',
198
+ ext: '.gz',
199
+ threshold: 10240,
200
+ deleteOriginFile: false,
201
+ }),
379
202
 
380
- // 3. Brotli Compression (Modern Performance)
381
- viteCompression({
382
- algorithm: 'brotliCompress',
383
- ext: '.br',
384
- threshold: 10240,
385
- deleteOriginFile: false,
386
- }),
387
- ],
203
+ // 3. Brotli Compression (Modern Performance)
204
+ viteCompression({
205
+ algorithm: 'brotliCompress',
206
+ ext: '.br',
207
+ threshold: 10240,
208
+ deleteOriginFile: false,
209
+ }),
210
+ ],
388
211
 
389
- resolve: {
390
- alias: {
391
- '@': fileURLToPath(new URL('./src', import.meta.url))
392
- },
393
- },
212
+ resolve: {
213
+ alias: {
214
+ '@': fileURLToPath(new URL('./src', import.meta.url))
215
+ },
216
+ },
394
217
 
395
- build: {
396
- cssMinify: 'lightningcss', // Ensure 'lightningcss' is in package.json
397
- // 4. Split Chunks for better Browser Caching
398
- rollupOptions: {
399
- output: {
400
- manualChunks(id) {
401
- if (id.includes('node_modules')) {
402
- // Split standard Vue dependencies into their own chunk
403
- if (id.includes('vue') || id.includes('pinia') || id.includes('vue-router')) {
404
- return 'vue-vendor';
405
- }
406
- ${threejsChunk}
407
-
408
- return 'vendor';
409
- }
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
+ },
410
236
  },
411
- },
412
- },
413
- },
414
237
 
415
- esbuild: {
416
- drop: isProd ? ['console', 'debugger'] : [],
417
- },
418
- }
419
- })
238
+ esbuild: {
239
+ drop: isProd ? ['console', 'debugger'] : [],
240
+ },
241
+ }
242
+ })
420
243
  `;
421
244
  }
422
245
  writeFileSync(configPath, configContent, 'utf-8');
@@ -1,4 +1,4 @@
1
1
  import type { ProjectType } from './project-detection.js';
2
2
  export declare function generateCSSVariables(projectType: ProjectType, projectPath: string, initialSetup?: boolean): Promise<void>;
3
3
  export declare function updateIndexHtml(projectPath: string): Promise<void>;
4
- export declare function createTypographyPage(projectPath: string): Promise<void>;
4
+ export declare function createTypographyPage(projectPath: string, projectType?: ProjectType): Promise<void>;
@@ -262,8 +262,12 @@ export async function updateIndexHtml(projectPath) {
262
262
  }
263
263
  writeFileSync(indexPath, htmlContent, 'utf-8');
264
264
  }
265
- export async function createTypographyPage(projectPath) {
266
- const typographyPagePath = join(projectPath, 'pages', 'typography', 'index.vue');
265
+ export async function createTypographyPage(projectPath, projectType) {
266
+ // For Nuxt, create in app/pages, for Vue use pages
267
+ const pagesDir = projectType === 'nuxt'
268
+ ? join(projectPath, 'app', 'pages')
269
+ : join(projectPath, 'pages');
270
+ const typographyPagePath = join(pagesDir, 'typography', 'index.vue');
267
271
  // Ensure directory exists
268
272
  mkdirSync(dirname(typographyPagePath), { recursive: true });
269
273
  const typographyPageContent = `<script setup lang="ts">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pni",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI tool for creating Nuxt/Vue projects with Three.js and CSS variables setup",
5
5
  "license": "MIT",
6
6
  "bin": {