@mtldev514/retro-portfolio-maker 1.0.4 → 1.0.7

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": "@mtldev514/retro-portfolio-maker",
3
- "version": "1.0.4",
3
+ "version": "1.0.7",
4
4
  "description": "Retro portfolio maker - Site-as-a-Package. Install the engine, provide your data, build your 90s-aesthetic portfolio.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/scripts/init.js CHANGED
@@ -221,10 +221,10 @@ jobs:
221
221
 
222
222
  - name: šŸ“Š Build summary
223
223
  run: |
224
- echo "### šŸŽØ Build Complete" >> \\$GITHUB_STEP_SUMMARY
225
- echo "" >> \\$GITHUB_STEP_SUMMARY
226
- echo "**Build date:** \\$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> \\$GITHUB_STEP_SUMMARY
227
- echo "**Output:** dist/" >> \\$GITHUB_STEP_SUMMARY
224
+ echo "### šŸŽØ Build Complete" >> $GITHUB_STEP_SUMMARY
225
+ echo "" >> $GITHUB_STEP_SUMMARY
226
+ echo "**Build date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_STEP_SUMMARY
227
+ echo "**Output:** dist/" >> $GITHUB_STEP_SUMMARY
228
228
 
229
229
  - name: šŸ“¤ Upload artifact
230
230
  uses: actions/upload-pages-artifact@v3
@@ -237,9 +237,9 @@ jobs:
237
237
 
238
238
  - name: āœ… Deployment complete
239
239
  run: |
240
- echo "### šŸŽ‰ Site deployed!" >> \\$GITHUB_STEP_SUMMARY
241
- echo "" >> \\$GITHUB_STEP_SUMMARY
242
- echo "**URL:** \\${{ steps.deployment.outputs.page_url }}" >> \\$GITHUB_STEP_SUMMARY
240
+ echo "### šŸŽ‰ Site deployed!" >> $GITHUB_STEP_SUMMARY
241
+ echo "" >> $GITHUB_STEP_SUMMARY
242
+ echo "**URL:** $` + '{{ steps.deployment.outputs.page_url }}' + `" >> $GITHUB_STEP_SUMMARY
243
243
  `;
244
244
 
245
245
  await fs.writeFile(path.join(workflowDir, 'deploy.yml'), deployWorkflow);
@@ -1,331 +0,0 @@
1
- /**
2
- * Init Script
3
- * Creates a new portfolio with template data structure
4
- */
5
-
6
- const fs = require('fs-extra');
7
- const path = require('path');
8
- const chalk = require('chalk');
9
-
10
- async function init(targetDir, options = {}) {
11
- console.log(chalk.blue('šŸŽØ Initializing Retro Portfolio...\n'));
12
-
13
- const targetPath = path.resolve(process.cwd(), targetDir);
14
- const templatePath = path.join(__dirname, '../templates/user-portfolio');
15
-
16
- // Check if directory exists
17
- if (fs.existsSync(targetPath) && fs.readdirSync(targetPath).length > 0) {
18
- if (!options.force) {
19
- throw new Error(
20
- `Directory ${targetDir} is not empty. Use --force to overwrite.`
21
- );
22
- }
23
- }
24
-
25
- // Create directory structure
26
- console.log(chalk.cyan('šŸ“ Creating directory structure...'));
27
-
28
- const dirs = ['config', 'data', 'lang', 'assets'];
29
- for (const dir of dirs) {
30
- const dirPath = path.join(targetPath, dir);
31
- await fs.ensureDir(dirPath);
32
- console.log(chalk.green(' āœ“'), dir + '/');
33
- }
34
-
35
- // Copy template files
36
- console.log(chalk.cyan('\nšŸ“„ Creating template files...'));
37
-
38
- // package.json
39
- const packageJson = {
40
- name: path.basename(targetPath),
41
- version: '1.0.0',
42
- private: true,
43
- scripts: {
44
- build: 'retro-portfolio build',
45
- dev: 'retro-portfolio dev',
46
- admin: 'retro-portfolio admin',
47
- start: 'npm run dev & npm run admin',
48
- deploy: 'retro-portfolio deploy',
49
- postinstall: 'pip3 install flask flask-cors 2>/dev/null || pip install flask flask-cors 2>/dev/null || echo "āš ļø Please install Flask manually: pip install flask flask-cors"'
50
- },
51
- dependencies: {
52
- '@mtldev514/retro-portfolio-engine': '^1.0.0'
53
- }
54
- };
55
-
56
- await fs.writeJson(path.join(targetPath, 'package.json'), packageJson, {
57
- spaces: 2
58
- });
59
- console.log(chalk.green(' āœ“'), 'package.json');
60
-
61
- // .gitignore
62
- const gitignore = `# Dependencies
63
- node_modules/
64
-
65
- # Build output
66
- dist/
67
-
68
- # Environment
69
- .env
70
- .env.local
71
-
72
- # Editor
73
- .vscode/
74
- .idea/
75
- *.swp
76
-
77
- # OS
78
- .DS_Store
79
- Thumbs.db
80
-
81
- # Temp
82
- temp_uploads/
83
- .cache/
84
- `;
85
-
86
- await fs.writeFile(path.join(targetPath, '.gitignore'), gitignore);
87
- console.log(chalk.green(' āœ“'), '.gitignore');
88
-
89
- // .env.example
90
- const envExample = `# Cloudinary Configuration (for media uploads)
91
- CLOUDINARY_CLOUD_NAME=your_cloud_name
92
- CLOUDINARY_API_KEY=your_api_key
93
- CLOUDINARY_API_SECRET=your_api_secret
94
-
95
- # Optional: Custom engine version
96
- # ENGINE_VERSION=1.0.0
97
- `;
98
-
99
- await fs.writeFile(path.join(targetPath, '.env.example'), envExample);
100
- console.log(chalk.green(' āœ“'), '.env.example');
101
-
102
- // Create config files
103
- const configFiles = {
104
- 'config/app.json': {
105
- site: {
106
- name: 'My Retro Portfolio',
107
- description: 'A nostalgic web presence',
108
- author: 'Your Name'
109
- },
110
- theme: {
111
- default: 'jr16'
112
- }
113
- },
114
- 'config/languages.json': {
115
- defaultLanguage: 'en',
116
- supportedLanguages: [
117
- { code: 'en', name: 'English', flag: 'šŸ‡¬šŸ‡§' },
118
- { code: 'fr', name: 'FranƧais', flag: 'šŸ‡«šŸ‡·' }
119
- ]
120
- },
121
- 'config/categories.json': {
122
- contentTypes: [
123
- {
124
- id: 'painting',
125
- name: { en: 'Painting', fr: 'Peinture' },
126
- icon: 'šŸŽØ',
127
- mediaType: 'image',
128
- dataFile: 'data/painting.json'
129
- },
130
- {
131
- id: 'projects',
132
- name: { en: 'Projects', fr: 'Projets' },
133
- icon: 'šŸ’»',
134
- mediaType: 'code',
135
- dataFile: 'data/projects.json'
136
- }
137
- ]
138
- },
139
- 'config/media-types.json': {
140
- mediaTypes: [
141
- {
142
- id: 'image',
143
- name: 'Image',
144
- supportsGallery: true,
145
- acceptedFormats: ['jpg', 'png', 'gif', 'webp']
146
- },
147
- {
148
- id: 'code',
149
- name: 'Code Project',
150
- supportsGallery: false
151
- }
152
- ]
153
- }
154
- };
155
-
156
- for (const [filePath, content] of Object.entries(configFiles)) {
157
- const fullPath = path.join(targetPath, filePath);
158
- await fs.writeJson(fullPath, content, { spaces: 2 });
159
- console.log(chalk.green(' āœ“'), filePath);
160
- }
161
-
162
- // Create empty data files
163
- const dataFiles = ['painting', 'projects'];
164
- for (const file of dataFiles) {
165
- const filePath = path.join(targetPath, 'data', `${file}.json`);
166
- await fs.writeJson(filePath, { items: [] }, { spaces: 2 });
167
- console.log(chalk.green(' āœ“'), `data/${file}.json`);
168
- }
169
-
170
- // Create language files
171
- const langFiles = {
172
- 'lang/en.json': {
173
- header_title: 'My Portfolio',
174
- nav_painting: 'Painting',
175
- nav_projects: 'Projects',
176
- footer_copy: 'Ā© 2026 My Portfolio'
177
- },
178
- 'lang/fr.json': {
179
- header_title: 'Mon Portfolio',
180
- nav_painting: 'Peinture',
181
- nav_projects: 'Projets',
182
- footer_copy: 'Ā© 2026 Mon Portfolio'
183
- }
184
- };
185
-
186
- for (const [filePath, content] of Object.entries(langFiles)) {
187
- const fullPath = path.join(targetPath, filePath);
188
- await fs.writeJson(fullPath, content, { spaces: 2 });
189
- console.log(chalk.green(' āœ“'), filePath);
190
- }
191
-
192
- // Create README
193
- const readme = `# ${path.basename(targetPath)}
194
-
195
- A retro-styled portfolio powered by [@mtldev514/retro-portfolio-engine](https://www.npmjs.com/package/@mtldev514/retro-portfolio-engine).
196
-
197
- ## šŸš€ Quick Start
198
-
199
- \`\`\`bash
200
- # Install dependencies (includes Python Flask auto-install)
201
- npm install
202
-
203
- # Launch site + admin in parallel (recommended)
204
- npm start
205
- # → Site: http://localhost:8000
206
- # → Admin: http://localhost:5001/admin.html
207
-
208
- # Or launch them separately:
209
- npm run dev # Site only (http://localhost:8000)
210
- npm run admin # Admin only (http://localhost:5001/admin.html)
211
- \`\`\`
212
-
213
- ## šŸ“ Project Structure
214
-
215
- - \`config/\` - Site configuration (app, languages, categories)
216
- - \`data/\` - Your portfolio content (JSON files)
217
- - \`lang/\` - Translations (en.json, fr.json, etc.)
218
- - \`assets/\` - Your images and media files
219
-
220
- ## šŸŽØ Admin Interface
221
-
222
- The admin interface allows you to:
223
- - Upload and manage images
224
- - Edit content in all languages
225
- - Add/edit/delete portfolio items
226
- - Manage translations
227
-
228
- Access it at **http://localhost:5001/admin.html** after running \`npm start\` or \`npm run admin\`.
229
-
230
- ## šŸ—ļø Building for Production
231
-
232
- \`\`\`bash
233
- # Build the static site
234
- npm run build
235
-
236
- # Output will be in dist/ folder
237
- # Deploy dist/ to GitHub Pages, Netlify, Vercel, etc.
238
- \`\`\`
239
-
240
- ## 🌐 Deployment
241
-
242
- ### GitHub Pages (Automated)
243
-
244
- This project includes a GitHub Action for automatic deployment.
245
-
246
- 1. Push your code to GitHub
247
- 2. Enable GitHub Pages in repository settings
248
- 3. On every push to \`main\`, the site will automatically build and deploy
249
-
250
- ### Manual Deployment
251
-
252
- \`\`\`bash
253
- npm run build
254
- # Then deploy the dist/ folder to your hosting provider
255
- \`\`\`
256
-
257
- ## šŸ”§ Configuration
258
-
259
- ### Cloudinary (for image uploads)
260
-
261
- 1. Create a free account at [Cloudinary](https://cloudinary.com)
262
- 2. Copy \`.env.example\` to \`.env\`
263
- 3. Add your Cloudinary credentials to \`.env\`
264
-
265
- \`\`\`bash
266
- cp .env.example .env
267
- nano .env # Edit with your credentials
268
- \`\`\`
269
-
270
- ### Customization
271
-
272
- - **Site name**: Edit \`config/app.json\`
273
- - **Languages**: Edit \`config/languages.json\`
274
- - **Categories**: Edit \`config/categories.json\`
275
- - **Content**: Use the admin interface or edit JSON files in \`data/\`
276
-
277
- ## šŸ“š Available Commands
278
-
279
- - \`npm start\` - Launch site + admin together
280
- - \`npm run dev\` - Development server (site only)
281
- - \`npm run admin\` - Admin interface
282
- - \`npm run build\` - Build for production
283
- - \`npm run deploy\` - Deploy to GitHub Pages
284
-
285
- ## šŸ†˜ Troubleshooting
286
-
287
- ### Admin won't start
288
-
289
- Make sure Flask is installed:
290
-
291
- \`\`\`bash
292
- pip install flask flask-cors
293
- \`\`\`
294
-
295
- ### Images won't upload
296
-
297
- Check your \`.env\` file has valid Cloudinary credentials.
298
-
299
- ### Site won't build
300
-
301
- Make sure all required files exist in \`config/\`, \`data/\`, and \`lang/\` directories.
302
-
303
- ## šŸ“– Documentation
304
-
305
- - [Engine Documentation](https://github.com/mtldev514/retro-portfolio-engine)
306
- - [NPM Package](https://www.npmjs.com/package/@mtldev514/retro-portfolio-engine)
307
-
308
- ## šŸ“„ License
309
-
310
- MIT
311
-
312
- ---
313
-
314
- **Made with šŸ’œ using @mtldev514/retro-portfolio-engine**
315
- `;
316
-
317
- await fs.writeFile(path.join(targetPath, 'README.md'), readme);
318
- console.log(chalk.green(' āœ“'), 'README.md');
319
-
320
- // Success message
321
- console.log(chalk.green('\n✨ Portfolio initialized successfully!\n'));
322
- console.log(chalk.cyan('Next steps:\n'));
323
- console.log(` cd ${targetDir}`);
324
- console.log(' npm install');
325
- console.log(' npm run dev\n');
326
- console.log(chalk.gray('Happy creating! šŸŽØ\n'));
327
-
328
- return true;
329
- }
330
-
331
- module.exports = init;
@@ -1,331 +0,0 @@
1
- /**
2
- * Init Script
3
- * Creates a new portfolio with template data structure
4
- */
5
-
6
- const fs = require('fs-extra');
7
- const path = require('path');
8
- const chalk = require('chalk');
9
-
10
- async function init(targetDir, options = {}) {
11
- console.log(chalk.blue('šŸŽØ Initializing Retro Portfolio...\n'));
12
-
13
- const targetPath = path.resolve(process.cwd(), targetDir);
14
- const templatePath = path.join(__dirname, '../templates/user-portfolio');
15
-
16
- // Check if directory exists
17
- if (fs.existsSync(targetPath) && fs.readdirSync(targetPath).length > 0) {
18
- if (!options.force) {
19
- throw new Error(
20
- `Directory ${targetDir} is not empty. Use --force to overwrite.`
21
- );
22
- }
23
- }
24
-
25
- // Create directory structure
26
- console.log(chalk.cyan('šŸ“ Creating directory structure...'));
27
-
28
- const dirs = ['config', 'data', 'lang', 'assets'];
29
- for (const dir of dirs) {
30
- const dirPath = path.join(targetPath, dir);
31
- await fs.ensureDir(dirPath);
32
- console.log(chalk.green(' āœ“'), dir + '/');
33
- }
34
-
35
- // Copy template files
36
- console.log(chalk.cyan('\nšŸ“„ Creating template files...'));
37
-
38
- // package.json
39
- const packageJson = {
40
- name: path.basename(targetPath),
41
- version: '1.0.0',
42
- private: true,
43
- scripts: {
44
- build: 'npx retro-portfolio build',
45
- dev: 'npx retro-portfolio dev',
46
- admin: 'npx retro-portfolio admin',
47
- start: 'npm run dev & npm run admin',
48
- deploy: 'npx retro-portfolio deploy',
49
- postinstall: 'pip3 install flask flask-cors 2>/dev/null || pip install flask flask-cors 2>/dev/null || echo "āš ļø Please install Flask manually: pip install flask flask-cors"'
50
- },
51
- dependencies: {
52
- '@mtldev514/retro-portfolio-engine': '^1.0.0'
53
- }
54
- };
55
-
56
- await fs.writeJson(path.join(targetPath, 'package.json'), packageJson, {
57
- spaces: 2
58
- });
59
- console.log(chalk.green(' āœ“'), 'package.json');
60
-
61
- // .gitignore
62
- const gitignore = `# Dependencies
63
- node_modules/
64
-
65
- # Build output
66
- dist/
67
-
68
- # Environment
69
- .env
70
- .env.local
71
-
72
- # Editor
73
- .vscode/
74
- .idea/
75
- *.swp
76
-
77
- # OS
78
- .DS_Store
79
- Thumbs.db
80
-
81
- # Temp
82
- temp_uploads/
83
- .cache/
84
- `;
85
-
86
- await fs.writeFile(path.join(targetPath, '.gitignore'), gitignore);
87
- console.log(chalk.green(' āœ“'), '.gitignore');
88
-
89
- // .env.example
90
- const envExample = `# Cloudinary Configuration (for media uploads)
91
- CLOUDINARY_CLOUD_NAME=your_cloud_name
92
- CLOUDINARY_API_KEY=your_api_key
93
- CLOUDINARY_API_SECRET=your_api_secret
94
-
95
- # Optional: Custom engine version
96
- # ENGINE_VERSION=1.0.0
97
- `;
98
-
99
- await fs.writeFile(path.join(targetPath, '.env.example'), envExample);
100
- console.log(chalk.green(' āœ“'), '.env.example');
101
-
102
- // Create config files
103
- const configFiles = {
104
- 'config/app.json': {
105
- site: {
106
- name: 'My Retro Portfolio',
107
- description: 'A nostalgic web presence',
108
- author: 'Your Name'
109
- },
110
- theme: {
111
- default: 'jr16'
112
- }
113
- },
114
- 'config/languages.json': {
115
- defaultLanguage: 'en',
116
- supportedLanguages: [
117
- { code: 'en', name: 'English', flag: 'šŸ‡¬šŸ‡§' },
118
- { code: 'fr', name: 'FranƧais', flag: 'šŸ‡«šŸ‡·' }
119
- ]
120
- },
121
- 'config/categories.json': {
122
- contentTypes: [
123
- {
124
- id: 'painting',
125
- name: { en: 'Painting', fr: 'Peinture' },
126
- icon: 'šŸŽØ',
127
- mediaType: 'image',
128
- dataFile: 'data/painting.json'
129
- },
130
- {
131
- id: 'projects',
132
- name: { en: 'Projects', fr: 'Projets' },
133
- icon: 'šŸ’»',
134
- mediaType: 'code',
135
- dataFile: 'data/projects.json'
136
- }
137
- ]
138
- },
139
- 'config/media-types.json': {
140
- mediaTypes: [
141
- {
142
- id: 'image',
143
- name: 'Image',
144
- supportsGallery: true,
145
- acceptedFormats: ['jpg', 'png', 'gif', 'webp']
146
- },
147
- {
148
- id: 'code',
149
- name: 'Code Project',
150
- supportsGallery: false
151
- }
152
- ]
153
- }
154
- };
155
-
156
- for (const [filePath, content] of Object.entries(configFiles)) {
157
- const fullPath = path.join(targetPath, filePath);
158
- await fs.writeJson(fullPath, content, { spaces: 2 });
159
- console.log(chalk.green(' āœ“'), filePath);
160
- }
161
-
162
- // Create empty data files
163
- const dataFiles = ['painting', 'projects'];
164
- for (const file of dataFiles) {
165
- const filePath = path.join(targetPath, 'data', `${file}.json`);
166
- await fs.writeJson(filePath, { items: [] }, { spaces: 2 });
167
- console.log(chalk.green(' āœ“'), `data/${file}.json`);
168
- }
169
-
170
- // Create language files
171
- const langFiles = {
172
- 'lang/en.json': {
173
- header_title: 'My Portfolio',
174
- nav_painting: 'Painting',
175
- nav_projects: 'Projects',
176
- footer_copy: 'Ā© 2026 My Portfolio'
177
- },
178
- 'lang/fr.json': {
179
- header_title: 'Mon Portfolio',
180
- nav_painting: 'Peinture',
181
- nav_projects: 'Projets',
182
- footer_copy: 'Ā© 2026 Mon Portfolio'
183
- }
184
- };
185
-
186
- for (const [filePath, content] of Object.entries(langFiles)) {
187
- const fullPath = path.join(targetPath, filePath);
188
- await fs.writeJson(fullPath, content, { spaces: 2 });
189
- console.log(chalk.green(' āœ“'), filePath);
190
- }
191
-
192
- // Create README
193
- const readme = `# ${path.basename(targetPath)}
194
-
195
- A retro-styled portfolio powered by [@mtldev514/retro-portfolio-engine](https://www.npmjs.com/package/@mtldev514/retro-portfolio-engine).
196
-
197
- ## šŸš€ Quick Start
198
-
199
- \`\`\`bash
200
- # Install dependencies (includes Python Flask auto-install)
201
- npm install
202
-
203
- # Launch site + admin in parallel (recommended)
204
- npm start
205
- # → Site: http://localhost:8000
206
- # → Admin: http://localhost:5001/admin.html
207
-
208
- # Or launch them separately:
209
- npm run dev # Site only (http://localhost:8000)
210
- npm run admin # Admin only (http://localhost:5001/admin.html)
211
- \`\`\`
212
-
213
- ## šŸ“ Project Structure
214
-
215
- - \`config/\` - Site configuration (app, languages, categories)
216
- - \`data/\` - Your portfolio content (JSON files)
217
- - \`lang/\` - Translations (en.json, fr.json, etc.)
218
- - \`assets/\` - Your images and media files
219
-
220
- ## šŸŽØ Admin Interface
221
-
222
- The admin interface allows you to:
223
- - Upload and manage images
224
- - Edit content in all languages
225
- - Add/edit/delete portfolio items
226
- - Manage translations
227
-
228
- Access it at **http://localhost:5001/admin.html** after running \`npm start\` or \`npm run admin\`.
229
-
230
- ## šŸ—ļø Building for Production
231
-
232
- \`\`\`bash
233
- # Build the static site
234
- npm run build
235
-
236
- # Output will be in dist/ folder
237
- # Deploy dist/ to GitHub Pages, Netlify, Vercel, etc.
238
- \`\`\`
239
-
240
- ## 🌐 Deployment
241
-
242
- ### GitHub Pages (Automated)
243
-
244
- This project includes a GitHub Action for automatic deployment.
245
-
246
- 1. Push your code to GitHub
247
- 2. Enable GitHub Pages in repository settings
248
- 3. On every push to \`main\`, the site will automatically build and deploy
249
-
250
- ### Manual Deployment
251
-
252
- \`\`\`bash
253
- npm run build
254
- # Then deploy the dist/ folder to your hosting provider
255
- \`\`\`
256
-
257
- ## šŸ”§ Configuration
258
-
259
- ### Cloudinary (for image uploads)
260
-
261
- 1. Create a free account at [Cloudinary](https://cloudinary.com)
262
- 2. Copy \`.env.example\` to \`.env\`
263
- 3. Add your Cloudinary credentials to \`.env\`
264
-
265
- \`\`\`bash
266
- cp .env.example .env
267
- nano .env # Edit with your credentials
268
- \`\`\`
269
-
270
- ### Customization
271
-
272
- - **Site name**: Edit \`config/app.json\`
273
- - **Languages**: Edit \`config/languages.json\`
274
- - **Categories**: Edit \`config/categories.json\`
275
- - **Content**: Use the admin interface or edit JSON files in \`data/\`
276
-
277
- ## šŸ“š Available Commands
278
-
279
- - \`npm start\` - Launch site + admin together
280
- - \`npm run dev\` - Development server (site only)
281
- - \`npm run admin\` - Admin interface
282
- - \`npm run build\` - Build for production
283
- - \`npm run deploy\` - Deploy to GitHub Pages
284
-
285
- ## šŸ†˜ Troubleshooting
286
-
287
- ### Admin won't start
288
-
289
- Make sure Flask is installed:
290
-
291
- \`\`\`bash
292
- pip install flask flask-cors
293
- \`\`\`
294
-
295
- ### Images won't upload
296
-
297
- Check your \`.env\` file has valid Cloudinary credentials.
298
-
299
- ### Site won't build
300
-
301
- Make sure all required files exist in \`config/\`, \`data/\`, and \`lang/\` directories.
302
-
303
- ## šŸ“– Documentation
304
-
305
- - [Engine Documentation](https://github.com/mtldev514/retro-portfolio-engine)
306
- - [NPM Package](https://www.npmjs.com/package/@mtldev514/retro-portfolio-engine)
307
-
308
- ## šŸ“„ License
309
-
310
- MIT
311
-
312
- ---
313
-
314
- **Made with šŸ’œ using @mtldev514/retro-portfolio-engine**
315
- `;
316
-
317
- await fs.writeFile(path.join(targetPath, 'README.md'), readme);
318
- console.log(chalk.green(' āœ“'), 'README.md');
319
-
320
- // Success message
321
- console.log(chalk.green('\n✨ Portfolio initialized successfully!\n'));
322
- console.log(chalk.cyan('Next steps:\n'));
323
- console.log(` cd ${targetDir}`);
324
- console.log(' npm install');
325
- console.log(' npm run dev\n');
326
- console.log(chalk.gray('Happy creating! šŸŽØ\n'));
327
-
328
- return true;
329
- }
330
-
331
- module.exports = init;
@@ -1,331 +0,0 @@
1
- /**
2
- * Init Script
3
- * Creates a new portfolio with template data structure
4
- */
5
-
6
- const fs = require('fs-extra');
7
- const path = require('path');
8
- const chalk = require('chalk');
9
-
10
- async function init(targetDir, options = {}) {
11
- console.log(chalk.blue('šŸŽØ Initializing Retro Portfolio...\n'));
12
-
13
- const targetPath = path.resolve(process.cwd(), targetDir);
14
- const templatePath = path.join(__dirname, '../templates/user-portfolio');
15
-
16
- // Check if directory exists
17
- if (fs.existsSync(targetPath) && fs.readdirSync(targetPath).length > 0) {
18
- if (!options.force) {
19
- throw new Error(
20
- `Directory ${targetDir} is not empty. Use --force to overwrite.`
21
- );
22
- }
23
- }
24
-
25
- // Create directory structure
26
- console.log(chalk.cyan('šŸ“ Creating directory structure...'));
27
-
28
- const dirs = ['config', 'data', 'lang', 'assets'];
29
- for (const dir of dirs) {
30
- const dirPath = path.join(targetPath, dir);
31
- await fs.ensureDir(dirPath);
32
- console.log(chalk.green(' āœ“'), dir + '/');
33
- }
34
-
35
- // Copy template files
36
- console.log(chalk.cyan('\nšŸ“„ Creating template files...'));
37
-
38
- // package.json
39
- const packageJson = {
40
- name: path.basename(targetPath),
41
- version: '1.0.0',
42
- private: true,
43
- scripts: {
44
- build: 'node ./node_modules/@mtldev514/retro-portfolio-engine/bin/cli.js build',
45
- dev: 'node ./node_modules/@mtldev514/retro-portfolio-engine/bin/cli.js dev',
46
- admin: 'node ./node_modules/@mtldev514/retro-portfolio-engine/bin/cli.js admin',
47
- start: 'npm run dev & npm run admin',
48
- deploy: 'node ./node_modules/@mtldev514/retro-portfolio-engine/bin/cli.js deploy',
49
- postinstall: 'pip3 install flask flask-cors 2>/dev/null || pip install flask flask-cors 2>/dev/null || echo "āš ļø Please install Flask manually: pip install flask flask-cors"'
50
- },
51
- dependencies: {
52
- '@mtldev514/retro-portfolio-engine': '^1.0.0'
53
- }
54
- };
55
-
56
- await fs.writeJson(path.join(targetPath, 'package.json'), packageJson, {
57
- spaces: 2
58
- });
59
- console.log(chalk.green(' āœ“'), 'package.json');
60
-
61
- // .gitignore
62
- const gitignore = `# Dependencies
63
- node_modules/
64
-
65
- # Build output
66
- dist/
67
-
68
- # Environment
69
- .env
70
- .env.local
71
-
72
- # Editor
73
- .vscode/
74
- .idea/
75
- *.swp
76
-
77
- # OS
78
- .DS_Store
79
- Thumbs.db
80
-
81
- # Temp
82
- temp_uploads/
83
- .cache/
84
- `;
85
-
86
- await fs.writeFile(path.join(targetPath, '.gitignore'), gitignore);
87
- console.log(chalk.green(' āœ“'), '.gitignore');
88
-
89
- // .env.example
90
- const envExample = `# Cloudinary Configuration (for media uploads)
91
- CLOUDINARY_CLOUD_NAME=your_cloud_name
92
- CLOUDINARY_API_KEY=your_api_key
93
- CLOUDINARY_API_SECRET=your_api_secret
94
-
95
- # Optional: Custom engine version
96
- # ENGINE_VERSION=1.0.0
97
- `;
98
-
99
- await fs.writeFile(path.join(targetPath, '.env.example'), envExample);
100
- console.log(chalk.green(' āœ“'), '.env.example');
101
-
102
- // Create config files
103
- const configFiles = {
104
- 'config/app.json': {
105
- site: {
106
- name: 'My Retro Portfolio',
107
- description: 'A nostalgic web presence',
108
- author: 'Your Name'
109
- },
110
- theme: {
111
- default: 'jr16'
112
- }
113
- },
114
- 'config/languages.json': {
115
- defaultLanguage: 'en',
116
- supportedLanguages: [
117
- { code: 'en', name: 'English', flag: 'šŸ‡¬šŸ‡§' },
118
- { code: 'fr', name: 'FranƧais', flag: 'šŸ‡«šŸ‡·' }
119
- ]
120
- },
121
- 'config/categories.json': {
122
- contentTypes: [
123
- {
124
- id: 'painting',
125
- name: { en: 'Painting', fr: 'Peinture' },
126
- icon: 'šŸŽØ',
127
- mediaType: 'image',
128
- dataFile: 'data/painting.json'
129
- },
130
- {
131
- id: 'projects',
132
- name: { en: 'Projects', fr: 'Projets' },
133
- icon: 'šŸ’»',
134
- mediaType: 'code',
135
- dataFile: 'data/projects.json'
136
- }
137
- ]
138
- },
139
- 'config/media-types.json': {
140
- mediaTypes: [
141
- {
142
- id: 'image',
143
- name: 'Image',
144
- supportsGallery: true,
145
- acceptedFormats: ['jpg', 'png', 'gif', 'webp']
146
- },
147
- {
148
- id: 'code',
149
- name: 'Code Project',
150
- supportsGallery: false
151
- }
152
- ]
153
- }
154
- };
155
-
156
- for (const [filePath, content] of Object.entries(configFiles)) {
157
- const fullPath = path.join(targetPath, filePath);
158
- await fs.writeJson(fullPath, content, { spaces: 2 });
159
- console.log(chalk.green(' āœ“'), filePath);
160
- }
161
-
162
- // Create empty data files
163
- const dataFiles = ['painting', 'projects'];
164
- for (const file of dataFiles) {
165
- const filePath = path.join(targetPath, 'data', `${file}.json`);
166
- await fs.writeJson(filePath, { items: [] }, { spaces: 2 });
167
- console.log(chalk.green(' āœ“'), `data/${file}.json`);
168
- }
169
-
170
- // Create language files
171
- const langFiles = {
172
- 'lang/en.json': {
173
- header_title: 'My Portfolio',
174
- nav_painting: 'Painting',
175
- nav_projects: 'Projects',
176
- footer_copy: 'Ā© 2026 My Portfolio'
177
- },
178
- 'lang/fr.json': {
179
- header_title: 'Mon Portfolio',
180
- nav_painting: 'Peinture',
181
- nav_projects: 'Projets',
182
- footer_copy: 'Ā© 2026 Mon Portfolio'
183
- }
184
- };
185
-
186
- for (const [filePath, content] of Object.entries(langFiles)) {
187
- const fullPath = path.join(targetPath, filePath);
188
- await fs.writeJson(fullPath, content, { spaces: 2 });
189
- console.log(chalk.green(' āœ“'), filePath);
190
- }
191
-
192
- // Create README
193
- const readme = `# ${path.basename(targetPath)}
194
-
195
- A retro-styled portfolio powered by [@mtldev514/retro-portfolio-engine](https://www.npmjs.com/package/@mtldev514/retro-portfolio-engine).
196
-
197
- ## šŸš€ Quick Start
198
-
199
- \`\`\`bash
200
- # Install dependencies (includes Python Flask auto-install)
201
- npm install
202
-
203
- # Launch site + admin in parallel (recommended)
204
- npm start
205
- # → Site: http://localhost:8000
206
- # → Admin: http://localhost:5001/admin.html
207
-
208
- # Or launch them separately:
209
- npm run dev # Site only (http://localhost:8000)
210
- npm run admin # Admin only (http://localhost:5001/admin.html)
211
- \`\`\`
212
-
213
- ## šŸ“ Project Structure
214
-
215
- - \`config/\` - Site configuration (app, languages, categories)
216
- - \`data/\` - Your portfolio content (JSON files)
217
- - \`lang/\` - Translations (en.json, fr.json, etc.)
218
- - \`assets/\` - Your images and media files
219
-
220
- ## šŸŽØ Admin Interface
221
-
222
- The admin interface allows you to:
223
- - Upload and manage images
224
- - Edit content in all languages
225
- - Add/edit/delete portfolio items
226
- - Manage translations
227
-
228
- Access it at **http://localhost:5001/admin.html** after running \`npm start\` or \`npm run admin\`.
229
-
230
- ## šŸ—ļø Building for Production
231
-
232
- \`\`\`bash
233
- # Build the static site
234
- npm run build
235
-
236
- # Output will be in dist/ folder
237
- # Deploy dist/ to GitHub Pages, Netlify, Vercel, etc.
238
- \`\`\`
239
-
240
- ## 🌐 Deployment
241
-
242
- ### GitHub Pages (Automated)
243
-
244
- This project includes a GitHub Action for automatic deployment.
245
-
246
- 1. Push your code to GitHub
247
- 2. Enable GitHub Pages in repository settings
248
- 3. On every push to \`main\`, the site will automatically build and deploy
249
-
250
- ### Manual Deployment
251
-
252
- \`\`\`bash
253
- npm run build
254
- # Then deploy the dist/ folder to your hosting provider
255
- \`\`\`
256
-
257
- ## šŸ”§ Configuration
258
-
259
- ### Cloudinary (for image uploads)
260
-
261
- 1. Create a free account at [Cloudinary](https://cloudinary.com)
262
- 2. Copy \`.env.example\` to \`.env\`
263
- 3. Add your Cloudinary credentials to \`.env\`
264
-
265
- \`\`\`bash
266
- cp .env.example .env
267
- nano .env # Edit with your credentials
268
- \`\`\`
269
-
270
- ### Customization
271
-
272
- - **Site name**: Edit \`config/app.json\`
273
- - **Languages**: Edit \`config/languages.json\`
274
- - **Categories**: Edit \`config/categories.json\`
275
- - **Content**: Use the admin interface or edit JSON files in \`data/\`
276
-
277
- ## šŸ“š Available Commands
278
-
279
- - \`npm start\` - Launch site + admin together
280
- - \`npm run dev\` - Development server (site only)
281
- - \`npm run admin\` - Admin interface
282
- - \`npm run build\` - Build for production
283
- - \`npm run deploy\` - Deploy to GitHub Pages
284
-
285
- ## šŸ†˜ Troubleshooting
286
-
287
- ### Admin won't start
288
-
289
- Make sure Flask is installed:
290
-
291
- \`\`\`bash
292
- pip install flask flask-cors
293
- \`\`\`
294
-
295
- ### Images won't upload
296
-
297
- Check your \`.env\` file has valid Cloudinary credentials.
298
-
299
- ### Site won't build
300
-
301
- Make sure all required files exist in \`config/\`, \`data/\`, and \`lang/\` directories.
302
-
303
- ## šŸ“– Documentation
304
-
305
- - [Engine Documentation](https://github.com/mtldev514/retro-portfolio-engine)
306
- - [NPM Package](https://www.npmjs.com/package/@mtldev514/retro-portfolio-engine)
307
-
308
- ## šŸ“„ License
309
-
310
- MIT
311
-
312
- ---
313
-
314
- **Made with šŸ’œ using @mtldev514/retro-portfolio-engine**
315
- `;
316
-
317
- await fs.writeFile(path.join(targetPath, 'README.md'), readme);
318
- console.log(chalk.green(' āœ“'), 'README.md');
319
-
320
- // Success message
321
- console.log(chalk.green('\n✨ Portfolio initialized successfully!\n'));
322
- console.log(chalk.cyan('Next steps:\n'));
323
- console.log(` cd ${targetDir}`);
324
- console.log(' npm install');
325
- console.log(' npm run dev\n');
326
- console.log(chalk.gray('Happy creating! šŸŽØ\n'));
327
-
328
- return true;
329
- }
330
-
331
- module.exports = init;