@mtldev514/retro-portfolio-engine 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +408 -0
  2. package/bin/cli.js +103 -0
  3. package/engine/admin/admin.css +720 -0
  4. package/engine/admin/admin.html +801 -0
  5. package/engine/admin/admin_api.py +230 -0
  6. package/engine/admin/scripts/backup.sh +116 -0
  7. package/engine/admin/scripts/config_loader.py +180 -0
  8. package/engine/admin/scripts/init.sh +141 -0
  9. package/engine/admin/scripts/manager.py +308 -0
  10. package/engine/admin/scripts/restore.sh +121 -0
  11. package/engine/admin/scripts/server.py +41 -0
  12. package/engine/admin/scripts/update.sh +321 -0
  13. package/engine/admin/scripts/validate_json.py +62 -0
  14. package/engine/fonts.css +37 -0
  15. package/engine/index.html +190 -0
  16. package/engine/js/config-loader.js +370 -0
  17. package/engine/js/config.js +173 -0
  18. package/engine/js/counter.js +17 -0
  19. package/engine/js/effects.js +97 -0
  20. package/engine/js/i18n.js +68 -0
  21. package/engine/js/init.js +107 -0
  22. package/engine/js/media.js +264 -0
  23. package/engine/js/render.js +282 -0
  24. package/engine/js/router.js +133 -0
  25. package/engine/js/sparkle.js +123 -0
  26. package/engine/js/themes.js +607 -0
  27. package/engine/style.css +2037 -0
  28. package/index.js +35 -0
  29. package/package.json +48 -0
  30. package/scripts/admin.js +67 -0
  31. package/scripts/build.js +142 -0
  32. package/scripts/init.js +237 -0
  33. package/scripts/post-install.js +16 -0
  34. package/scripts/serve.js +54 -0
  35. package/templates/user-portfolio/.github/workflows/deploy.yml +57 -0
  36. package/templates/user-portfolio/config/app.json +36 -0
  37. package/templates/user-portfolio/config/categories.json +241 -0
  38. package/templates/user-portfolio/config/languages.json +15 -0
  39. package/templates/user-portfolio/config/media-types.json +59 -0
  40. package/templates/user-portfolio/data/painting.json +3 -0
  41. package/templates/user-portfolio/data/projects.json +3 -0
  42. package/templates/user-portfolio/lang/en.json +114 -0
  43. package/templates/user-portfolio/lang/fr.json +114 -0
package/index.js ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @retro-portfolio/engine
3
+ * Main entry point for the package
4
+ */
5
+
6
+ const path = require('path');
7
+
8
+ module.exports = {
9
+ // Path to engine files
10
+ enginePath: path.join(__dirname, 'engine'),
11
+
12
+ // Package version
13
+ version: require('./package.json').version,
14
+
15
+ /**
16
+ * Get path to engine directory
17
+ */
18
+ getEnginePath() {
19
+ return this.enginePath;
20
+ },
21
+
22
+ /**
23
+ * Get package version
24
+ */
25
+ getVersion() {
26
+ return this.version;
27
+ },
28
+
29
+ /**
30
+ * Get path to a specific engine file
31
+ */
32
+ getEngineFile(filePath) {
33
+ return path.join(this.enginePath, filePath);
34
+ }
35
+ };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@mtldev514/retro-portfolio-engine",
3
+ "version": "1.0.0",
4
+ "description": "Retro portfolio site engine - Package as a Service. Users install this package and provide their own data.",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "retro-portfolio": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "prepare": "node scripts/post-install.js"
11
+ },
12
+ "keywords": [
13
+ "portfolio",
14
+ "retro",
15
+ "static-site-generator",
16
+ "site-as-a-package",
17
+ "90s-aesthetic",
18
+ "personal-website"
19
+ ],
20
+ "author": "Alex",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/mtldev514/retro-portfolio-engine"
25
+ },
26
+ "files": [
27
+ "engine/",
28
+ "scripts/",
29
+ "bin/",
30
+ "templates/",
31
+ "index.js"
32
+ ],
33
+ "engines": {
34
+ "node": ">=14.0.0"
35
+ },
36
+ "dependencies": {
37
+ "chalk": "^4.1.2",
38
+ "commander": "^11.0.0",
39
+ "fs-extra": "^11.1.1"
40
+ },
41
+ "devDependencies": {
42
+ "http-server": "^14.1.1"
43
+ },
44
+ "peerDependencies": {},
45
+ "publishConfig": {
46
+ "access": "restricted"
47
+ }
48
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Admin Script
3
+ * Launches admin interface for content management
4
+ */
5
+
6
+ const { spawn } = require('child_process');
7
+ const chalk = require('chalk');
8
+ const path = require('path');
9
+ const fs = require('fs-extra');
10
+
11
+ async function admin(options = {}) {
12
+ const port = options.port || 5001;
13
+ const cwd = process.cwd();
14
+
15
+ console.log(chalk.blue('šŸ”§ Starting admin interface...\n'));
16
+
17
+ // Check if admin_api.py exists in engine
18
+ const adminApiPath = path.join(__dirname, '../engine/admin_api.py');
19
+ const userDataPath = cwd;
20
+
21
+ if (!fs.existsSync(adminApiPath)) {
22
+ console.log(chalk.red('āŒ Admin API not found in engine.'));
23
+ console.log(chalk.yellow('\nThe admin interface will be added in a future update.'));
24
+ console.log(chalk.gray('For now, you can edit JSON files in data/ and lang/ directly.\n'));
25
+ return;
26
+ }
27
+
28
+ // Set environment variable to point to user data
29
+ const env = {
30
+ ...process.env,
31
+ DATA_DIR: path.join(userDataPath, 'data'),
32
+ CONFIG_DIR: path.join(userDataPath, 'config'),
33
+ LANG_DIR: path.join(userDataPath, 'lang'),
34
+ PORT: port
35
+ };
36
+
37
+ console.log(chalk.cyan('Starting admin API...'));
38
+
39
+ // Start Flask API
40
+ const apiProcess = spawn('python3', [adminApiPath], {
41
+ env,
42
+ stdio: 'inherit'
43
+ });
44
+
45
+ console.log(chalk.green('\n✨ Admin interface running!\n'));
46
+ console.log(chalk.cyan('URL:'), `http://localhost:${port}/admin.html`);
47
+ console.log(chalk.gray('\nPress CTRL+C to stop\n'));
48
+
49
+ // Handle process termination
50
+ process.on('SIGINT', () => {
51
+ console.log(chalk.yellow('\n\nšŸ‘‹ Shutting down admin...'));
52
+ apiProcess.kill();
53
+ process.exit(0);
54
+ });
55
+
56
+ // Auto-open browser if requested
57
+ if (options.open) {
58
+ setTimeout(async () => {
59
+ const open = require('open');
60
+ await open(`http://localhost:${port}/admin.html`);
61
+ }, 2000); // Wait for Flask to start
62
+ }
63
+
64
+ return apiProcess;
65
+ }
66
+
67
+ module.exports = admin;
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Build Script
3
+ * Merges engine files with user data to generate static site
4
+ */
5
+
6
+ const fs = require('fs-extra');
7
+ const path = require('path');
8
+ const chalk = require('chalk');
9
+
10
+ async function build(options = {}) {
11
+ console.log(chalk.blue('šŸ—ļø Building your portfolio...\n'));
12
+
13
+ const cwd = process.cwd();
14
+ const outputDir = path.join(cwd, options.output || 'dist');
15
+
16
+ // Validate user has required directories
17
+ const requiredDirs = ['config', 'data', 'lang'];
18
+ for (const dir of requiredDirs) {
19
+ if (!fs.existsSync(path.join(cwd, dir))) {
20
+ throw new Error(`Missing required directory: ${dir}/`);
21
+ }
22
+ }
23
+
24
+ console.log(chalk.cyan('šŸ“‹ Validating data files...'));
25
+
26
+ // Validate config files exist
27
+ const requiredConfigs = ['app.json', 'languages.json', 'categories.json'];
28
+ for (const config of requiredConfigs) {
29
+ const configPath = path.join(cwd, 'config', config);
30
+ if (!fs.existsSync(configPath)) {
31
+ throw new Error(`Missing config file: config/${config}`);
32
+ }
33
+ }
34
+
35
+ console.log(chalk.green(' āœ“ All data files present\n'));
36
+
37
+ // Clean output directory
38
+ console.log(chalk.cyan('🧹 Cleaning output directory...'));
39
+ await fs.emptyDir(outputDir);
40
+ console.log(chalk.green(' āœ“ Output directory cleaned\n'));
41
+
42
+ // Copy engine files
43
+ console.log(chalk.cyan('šŸ“¦ Copying engine files...'));
44
+
45
+ const enginePath = path.join(__dirname, '../engine');
46
+
47
+ if (!fs.existsSync(enginePath)) {
48
+ throw new Error('Engine files not found. Package may be corrupted.');
49
+ }
50
+
51
+ await fs.copy(enginePath, outputDir);
52
+
53
+ // Count files copied
54
+ const engineFiles = await fs.readdir(enginePath);
55
+ console.log(chalk.green(` āœ“ Copied ${engineFiles.length} engine files\n`));
56
+
57
+ // Copy user data
58
+ console.log(chalk.cyan('šŸ“„ Copying your data...'));
59
+
60
+ const dataDirs = ['config', 'data', 'lang'];
61
+ for (const dir of dataDirs) {
62
+ const srcPath = path.join(cwd, dir);
63
+ const destPath = path.join(outputDir, dir);
64
+
65
+ await fs.copy(srcPath, destPath);
66
+
67
+ const fileCount = (await fs.readdir(srcPath)).length;
68
+ console.log(chalk.green(' āœ“'), `${dir}/ (${fileCount} files)`);
69
+ }
70
+
71
+ // Copy assets if exists
72
+ const assetsPath = path.join(cwd, 'assets');
73
+ if (fs.existsSync(assetsPath)) {
74
+ await fs.copy(assetsPath, path.join(outputDir, 'assets'));
75
+ const assetCount = (await fs.readdir(assetsPath)).length;
76
+ console.log(chalk.green(' āœ“'), `assets/ (${assetCount} files)`);
77
+ }
78
+
79
+ // Create build info
80
+ const buildInfo = {
81
+ buildDate: new Date().toISOString(),
82
+ engine: {
83
+ name: '@retro-portfolio/engine',
84
+ version: require('../package.json').version
85
+ },
86
+ site: {
87
+ name: path.basename(cwd)
88
+ }
89
+ };
90
+
91
+ await fs.writeJson(path.join(outputDir, 'build-info.json'), buildInfo, {
92
+ spaces: 2
93
+ });
94
+
95
+ console.log(chalk.green('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
96
+ console.log(chalk.green('✨ Build completed successfully!\n'));
97
+ console.log(chalk.cyan('Output:'), outputDir);
98
+ console.log(chalk.cyan('Size:'), await getDirSize(outputDir));
99
+ console.log(chalk.green('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
100
+
101
+ console.log(chalk.gray('Next steps:'));
102
+ console.log(chalk.gray(' • Test locally: npm run dev'));
103
+ console.log(chalk.gray(' • Deploy: npm run deploy\n'));
104
+
105
+ return outputDir;
106
+ }
107
+
108
+ /**
109
+ * Get directory size in human-readable format
110
+ */
111
+ async function getDirSize(dirPath) {
112
+ let size = 0;
113
+
114
+ async function calcSize(dir) {
115
+ const items = await fs.readdir(dir);
116
+
117
+ for (const item of items) {
118
+ const itemPath = path.join(dir, item);
119
+ const stats = await fs.stat(itemPath);
120
+
121
+ if (stats.isDirectory()) {
122
+ await calcSize(itemPath);
123
+ } else {
124
+ size += stats.size;
125
+ }
126
+ }
127
+ }
128
+
129
+ await calcSize(dirPath);
130
+
131
+ // Convert to human-readable
132
+ const units = ['B', 'KB', 'MB', 'GB'];
133
+ let unitIndex = 0;
134
+ while (size >= 1024 && unitIndex < units.length - 1) {
135
+ size /= 1024;
136
+ unitIndex++;
137
+ }
138
+
139
+ return `${size.toFixed(2)} ${units[unitIndex]}`;
140
+ }
141
+
142
+ module.exports = build;
@@ -0,0 +1,237 @@
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
+ deploy: 'retro-portfolio deploy'
48
+ },
49
+ dependencies: {
50
+ '@retro-portfolio/engine': '^1.0.0'
51
+ }
52
+ };
53
+
54
+ await fs.writeJson(path.join(targetPath, 'package.json'), packageJson, {
55
+ spaces: 2
56
+ });
57
+ console.log(chalk.green(' āœ“'), 'package.json');
58
+
59
+ // .gitignore
60
+ const gitignore = `# Dependencies
61
+ node_modules/
62
+
63
+ # Build output
64
+ dist/
65
+
66
+ # Environment
67
+ .env
68
+ .env.local
69
+
70
+ # Editor
71
+ .vscode/
72
+ .idea/
73
+ *.swp
74
+
75
+ # OS
76
+ .DS_Store
77
+ Thumbs.db
78
+
79
+ # Temp
80
+ temp_uploads/
81
+ .cache/
82
+ `;
83
+
84
+ await fs.writeFile(path.join(targetPath, '.gitignore'), gitignore);
85
+ console.log(chalk.green(' āœ“'), '.gitignore');
86
+
87
+ // .env.example
88
+ const envExample = `# Cloudinary Configuration (for media uploads)
89
+ CLOUDINARY_CLOUD_NAME=your_cloud_name
90
+ CLOUDINARY_API_KEY=your_api_key
91
+ CLOUDINARY_API_SECRET=your_api_secret
92
+
93
+ # Optional: Custom engine version
94
+ # ENGINE_VERSION=1.0.0
95
+ `;
96
+
97
+ await fs.writeFile(path.join(targetPath, '.env.example'), envExample);
98
+ console.log(chalk.green(' āœ“'), '.env.example');
99
+
100
+ // Create config files
101
+ const configFiles = {
102
+ 'config/app.json': {
103
+ site: {
104
+ name: 'My Retro Portfolio',
105
+ description: 'A nostalgic web presence',
106
+ author: 'Your Name'
107
+ },
108
+ theme: {
109
+ default: 'jr16'
110
+ }
111
+ },
112
+ 'config/languages.json': {
113
+ defaultLanguage: 'en',
114
+ supportedLanguages: [
115
+ { code: 'en', name: 'English', flag: 'šŸ‡¬šŸ‡§' },
116
+ { code: 'fr', name: 'FranƧais', flag: 'šŸ‡«šŸ‡·' }
117
+ ]
118
+ },
119
+ 'config/categories.json': {
120
+ contentTypes: [
121
+ {
122
+ id: 'painting',
123
+ name: { en: 'Painting', fr: 'Peinture' },
124
+ icon: 'šŸŽØ',
125
+ mediaType: 'image',
126
+ dataFile: 'data/painting.json'
127
+ },
128
+ {
129
+ id: 'projects',
130
+ name: { en: 'Projects', fr: 'Projets' },
131
+ icon: 'šŸ’»',
132
+ mediaType: 'code',
133
+ dataFile: 'data/projects.json'
134
+ }
135
+ ]
136
+ },
137
+ 'config/media-types.json': {
138
+ mediaTypes: [
139
+ {
140
+ id: 'image',
141
+ name: 'Image',
142
+ supportsGallery: true,
143
+ acceptedFormats: ['jpg', 'png', 'gif', 'webp']
144
+ },
145
+ {
146
+ id: 'code',
147
+ name: 'Code Project',
148
+ supportsGallery: false
149
+ }
150
+ ]
151
+ }
152
+ };
153
+
154
+ for (const [filePath, content] of Object.entries(configFiles)) {
155
+ const fullPath = path.join(targetPath, filePath);
156
+ await fs.writeJson(fullPath, content, { spaces: 2 });
157
+ console.log(chalk.green(' āœ“'), filePath);
158
+ }
159
+
160
+ // Create empty data files
161
+ const dataFiles = ['painting', 'projects'];
162
+ for (const file of dataFiles) {
163
+ const filePath = path.join(targetPath, 'data', `${file}.json`);
164
+ await fs.writeJson(filePath, { items: [] }, { spaces: 2 });
165
+ console.log(chalk.green(' āœ“'), `data/${file}.json`);
166
+ }
167
+
168
+ // Create language files
169
+ const langFiles = {
170
+ 'lang/en.json': {
171
+ header_title: 'My Portfolio',
172
+ nav_painting: 'Painting',
173
+ nav_projects: 'Projects',
174
+ footer_copy: 'Ā© 2026 My Portfolio'
175
+ },
176
+ 'lang/fr.json': {
177
+ header_title: 'Mon Portfolio',
178
+ nav_painting: 'Peinture',
179
+ nav_projects: 'Projets',
180
+ footer_copy: 'Ā© 2026 Mon Portfolio'
181
+ }
182
+ };
183
+
184
+ for (const [filePath, content] of Object.entries(langFiles)) {
185
+ const fullPath = path.join(targetPath, filePath);
186
+ await fs.writeJson(fullPath, content, { spaces: 2 });
187
+ console.log(chalk.green(' āœ“'), filePath);
188
+ }
189
+
190
+ // Create README
191
+ const readme = `# My Retro Portfolio
192
+
193
+ A retro-styled portfolio powered by @retro-portfolio/engine.
194
+
195
+ ## Quick Start
196
+
197
+ \`\`\`bash
198
+ # Install dependencies
199
+ npm install
200
+
201
+ # Start development server
202
+ npm run dev
203
+
204
+ # Build for production
205
+ npm run build
206
+
207
+ # Launch admin interface
208
+ npm run admin
209
+ \`\`\`
210
+
211
+ ## Project Structure
212
+
213
+ - \`config/\` - Site configuration
214
+ - \`data/\` - Your portfolio content (JSON)
215
+ - \`lang/\` - Translations
216
+ - \`assets/\` - Your images, files, etc.
217
+
218
+ ## Documentation
219
+
220
+ Visit [retro-portfolio documentation](https://github.com/YOUR_USERNAME/retro-portfolio-engine) for more info.
221
+ `;
222
+
223
+ await fs.writeFile(path.join(targetPath, 'README.md'), readme);
224
+ console.log(chalk.green(' āœ“'), 'README.md');
225
+
226
+ // Success message
227
+ console.log(chalk.green('\n✨ Portfolio initialized successfully!\n'));
228
+ console.log(chalk.cyan('Next steps:\n'));
229
+ console.log(` cd ${targetDir}`);
230
+ console.log(' npm install');
231
+ console.log(' npm run dev\n');
232
+ console.log(chalk.gray('Happy creating! šŸŽØ\n'));
233
+
234
+ return true;
235
+ }
236
+
237
+ module.exports = init;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Post-install script
3
+ * Runs after npm install (optional setup)
4
+ */
5
+
6
+ // Nothing required for now - this can be used later for:
7
+ // - Creating default config files
8
+ // - Setting up initial directories
9
+ // - Showing welcome message
10
+
11
+ console.log('āœ… @retro-portfolio/engine installed successfully!');
12
+ console.log('\nGet started with:');
13
+ console.log(' npx retro-portfolio init my-portfolio');
14
+ console.log(' cd my-portfolio');
15
+ console.log(' npm install');
16
+ console.log(' npm run dev\n');
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Serve Script
3
+ * Local development server with live reload
4
+ */
5
+
6
+ const { spawn } = require('child_process');
7
+ const chalk = require('chalk');
8
+ const path = require('path');
9
+ const fs = require('fs-extra');
10
+
11
+ async function serve(options = {}) {
12
+ const port = options.port || 8000;
13
+ const cwd = process.cwd();
14
+ const distPath = path.join(cwd, 'dist');
15
+
16
+ console.log(chalk.blue('šŸš€ Starting development server...\n'));
17
+
18
+ // Check if dist exists, if not build first
19
+ if (!fs.existsSync(distPath)) {
20
+ console.log(chalk.yellow('āš ļø No build found. Building first...\n'));
21
+ const build = require('./build');
22
+ await build({ output: 'dist' });
23
+ console.log('');
24
+ }
25
+
26
+ // Start HTTP server
27
+ console.log(chalk.cyan('Starting server...'));
28
+
29
+ const serverProcess = spawn('python3', ['-m', 'http.server', port], {
30
+ cwd: distPath,
31
+ stdio: 'inherit'
32
+ });
33
+
34
+ console.log(chalk.green('\n✨ Server running!\n'));
35
+ console.log(chalk.cyan('Local:'), `http://localhost:${port}`);
36
+ console.log(chalk.gray('\nPress CTRL+C to stop\n'));
37
+
38
+ // Handle process termination
39
+ process.on('SIGINT', () => {
40
+ console.log(chalk.yellow('\n\nšŸ‘‹ Shutting down server...'));
41
+ serverProcess.kill();
42
+ process.exit(0);
43
+ });
44
+
45
+ // Auto-open browser if requested
46
+ if (options.open) {
47
+ const open = require('open');
48
+ await open(`http://localhost:${port}`);
49
+ }
50
+
51
+ return serverProcess;
52
+ }
53
+
54
+ module.exports = serve;
@@ -0,0 +1,57 @@
1
+ name: Build and Deploy to GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: "pages"
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ build-and-deploy:
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - name: šŸ“¦ Checkout
23
+ uses: actions/checkout@v4
24
+
25
+ - name: šŸ”§ Setup Node.js
26
+ uses: actions/setup-node@v4
27
+ with:
28
+ node-version: '18'
29
+ cache: 'npm'
30
+
31
+ - name: šŸ“„ Install dependencies
32
+ run: npm ci
33
+
34
+ - name: šŸ—ļø Build site
35
+ run: npm run build
36
+
37
+ - name: šŸ“Š Build summary
38
+ run: |
39
+ echo "### šŸŽØ Build Complete" >> $GITHUB_STEP_SUMMARY
40
+ echo "" >> $GITHUB_STEP_SUMMARY
41
+ echo "**Build date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_STEP_SUMMARY
42
+ echo "**Output:** dist/" >> $GITHUB_STEP_SUMMARY
43
+
44
+ - name: šŸ“¤ Upload artifact
45
+ uses: actions/upload-pages-artifact@v3
46
+ with:
47
+ path: ./dist
48
+
49
+ - name: šŸš€ Deploy to GitHub Pages
50
+ id: deployment
51
+ uses: actions/deploy-pages@v4
52
+
53
+ - name: āœ… Deployment complete
54
+ run: |
55
+ echo "### šŸŽ‰ Site deployed!" >> $GITHUB_STEP_SUMMARY
56
+ echo "" >> $GITHUB_STEP_SUMMARY
57
+ echo "**URL:** ${{ steps.deployment.outputs.page_url }}" >> $GITHUB_STEP_SUMMARY
@@ -0,0 +1,36 @@
1
+ {
2
+ "app": {
3
+ "name": "Retro Portfolio",
4
+ "version": "1.0",
5
+ "adminTitle": "PORTFOLIO MANAGER"
6
+ },
7
+ "api": {
8
+ "host": "127.0.0.1",
9
+ "port": 5001,
10
+ "baseUrl": "http://127.0.0.1:5001"
11
+ },
12
+ "paths": {
13
+ "dataDir": "data",
14
+ "langDir": "lang",
15
+ "pagesDir": "pages"
16
+ },
17
+ "github": {
18
+ "username": "yourusername",
19
+ "repoName": "retro-portfolio",
20
+ "mediaReleaseTag": "media",
21
+ "uploadCategories": [
22
+ "music"
23
+ ]
24
+ },
25
+ "counter": {
26
+ "apiUrl": "https://api.counterapi.dev/v1/retro-portfolio/visits/up"
27
+ },
28
+ "winamp": {
29
+ "title": "My Playlist",
30
+ "bitrate": "192",
31
+ "frequency": "44"
32
+ },
33
+ "pagination": {
34
+ "pageSize": 24
35
+ }
36
+ }