@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 +1 -1
- package/scripts/init.js +7 -7
- package/scripts/init.js.bak +0 -331
- package/scripts/init.js.bak2 +0 -331
- package/scripts/init.js.bak3 +0 -331
package/package.json
CHANGED
package/scripts/init.js
CHANGED
|
@@ -221,10 +221,10 @@ jobs:
|
|
|
221
221
|
|
|
222
222
|
- name: š Build summary
|
|
223
223
|
run: |
|
|
224
|
-
echo "### šØ Build Complete" >>
|
|
225
|
-
echo "" >>
|
|
226
|
-
echo "**Build date:**
|
|
227
|
-
echo "**Output:** dist/" >>
|
|
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!" >>
|
|
241
|
-
echo "" >>
|
|
242
|
-
echo "**URL:**
|
|
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);
|
package/scripts/init.js.bak
DELETED
|
@@ -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;
|
package/scripts/init.js.bak2
DELETED
|
@@ -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;
|
package/scripts/init.js.bak3
DELETED
|
@@ -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;
|