portosaurus 1.14.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.
- package/LICENSE +674 -0
- package/README.md +116 -0
- package/bin/portosaurus.js +337 -0
- package/internal/notes/index.md +10 -0
- package/internal/sidebars.js +20 -0
- package/internal/src/components/AboutSection/index.js +67 -0
- package/internal/src/components/AboutSection/styles.module.css +492 -0
- package/internal/src/components/ContactSection/index.js +94 -0
- package/internal/src/components/ContactSection/styles.module.css +327 -0
- package/internal/src/components/ExperienceSection/index.js +25 -0
- package/internal/src/components/ExperienceSection/styles.module.css +180 -0
- package/internal/src/components/HeroSection/index.js +61 -0
- package/internal/src/components/HeroSection/styles.module.css +471 -0
- package/internal/src/components/NoteIndex/index.js +127 -0
- package/internal/src/components/NoteIndex/styles.module.css +143 -0
- package/internal/src/components/ProjectsSection/index.js +529 -0
- package/internal/src/components/ProjectsSection/styles.module.css +830 -0
- package/internal/src/components/ScrollToTop/index.js +98 -0
- package/internal/src/components/ScrollToTop/styles.module.css +96 -0
- package/internal/src/components/SocialLinks/index.js +129 -0
- package/internal/src/components/SocialLinks/styles.module.css +55 -0
- package/internal/src/components/Tooltip/index.js +30 -0
- package/internal/src/components/Tooltip/styles.module.css +92 -0
- package/internal/src/config/iconMappings.js +329 -0
- package/internal/src/config/metaTags.js +240 -0
- package/internal/src/config/prism.js +179 -0
- package/internal/src/config/sidebar.js +20 -0
- package/internal/src/css/bootstrap.css +6 -0
- package/internal/src/css/catppuccin.css +632 -0
- package/internal/src/css/custom.css +186 -0
- package/internal/src/css/tasks.css +868 -0
- package/internal/src/pages/index.js +98 -0
- package/internal/src/pages/notes.js +88 -0
- package/internal/src/pages/tasks.js +310 -0
- package/internal/src/utils/HashNavigation.js +250 -0
- package/internal/src/utils/appVersion.js +27 -0
- package/internal/src/utils/compileConfig.js +82 -0
- package/internal/src/utils/cssUtils.js +99 -0
- package/internal/src/utils/filterEnabledItems.js +21 -0
- package/internal/src/utils/generateFavicon.js +256 -0
- package/internal/src/utils/generateRobotsTxt.js +97 -0
- package/internal/src/utils/iconExtractor.js +159 -0
- package/internal/src/utils/imageDownloader.js +88 -0
- package/internal/src/utils/imageProcessor.js +134 -0
- package/internal/src/utils/linkShortner.js +0 -0
- package/internal/src/utils/updateTitle.js +107 -0
- package/package.json +51 -0
- package/template/.github/workflows/deploy.yml +57 -0
- package/template/README.md +70 -0
- package/template/blog/authors.yml +5 -0
- package/template/blog/welcome.md +10 -0
- package/template/config.js +233 -0
- package/template/notes/getting-started.md +7 -0
- package/template/static/README.md +33 -0
- package/utils/createConfig.js +227 -0
- package/utils/logger.js +19 -0
- package/utils/packageManager.js +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/soymadip/portosaurus/refs/heads/compiler/static/img/icon.png" width=150>
|
|
3
|
+
<h1>Portosaurus</h1>
|
|
4
|
+
<p>Complete portfolio cum personal website solution for your digital personality.</p>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<br/>
|
|
8
|
+
|
|
9
|
+
## 🧩 Features
|
|
10
|
+
|
|
11
|
+
- **📝 Full-featured Portfolio Site** — Showcase your work, skills, experience, social identity.
|
|
12
|
+
- **🎨 Beautiful UI** — Responsive design with Catppuccin color scheme.
|
|
13
|
+
- **🖼️ Project Showcase** — Interactive project cards with support for featured projects, project status badges, and tags
|
|
14
|
+
- **📚 Knowledge Base** — Integrated notes system with custom icons and categorization
|
|
15
|
+
- **✏️ Blog Platform** — Built-in blogging capabilities.
|
|
16
|
+
- **📋 Task Tracking** — Track your plans with priority levels and completion status
|
|
17
|
+
- **🛠️ Highly Configurable** — Extensive customization options in a central config file
|
|
18
|
+
- **🔍 Powerful Search** — Integrated search functionality for notes and blog content
|
|
19
|
+
- **📱 Mobile-Friendly** — Fully responsive design works on all devices
|
|
20
|
+
- **🚀 Auto Deployment** — Ready for GitHub Pages or any static hosting
|
|
21
|
+
|
|
22
|
+
<br/>
|
|
23
|
+
|
|
24
|
+
## � Getting Started
|
|
25
|
+
|
|
26
|
+
### 1. Create a New Project
|
|
27
|
+
|
|
28
|
+
Run the initialization command to set up your portfolio:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# With Bun
|
|
32
|
+
bunx portosaurus init my-portfolio
|
|
33
|
+
|
|
34
|
+
# with npm
|
|
35
|
+
npx portosaurus init my-portfolio
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Options:**
|
|
39
|
+
|
|
40
|
+
- `-gh`: Automatically sets up GitHub Actions workflow for deployment.
|
|
41
|
+
- `--install`: Installs dependencies automatically.
|
|
42
|
+
|
|
43
|
+
### 2. Start Development
|
|
44
|
+
|
|
45
|
+
Navigate to your project and start the development server:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cd my-portfolio
|
|
49
|
+
|
|
50
|
+
# With npm
|
|
51
|
+
npm run start
|
|
52
|
+
|
|
53
|
+
# With Bun
|
|
54
|
+
bun run start
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Your site will be available at `http://localhost:3000`.
|
|
58
|
+
|
|
59
|
+
### 3. Build & Deploy
|
|
60
|
+
|
|
61
|
+
To generate the static site for production:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# With Bun
|
|
65
|
+
bun run build
|
|
66
|
+
|
|
67
|
+
# With npm
|
|
68
|
+
npm run build
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The output will be in the `build/` directory.
|
|
72
|
+
|
|
73
|
+
#### GitHub Pages (Automated)
|
|
74
|
+
|
|
75
|
+
If you used the `-gh` flag during init, just push to your repository:
|
|
76
|
+
|
|
77
|
+
1. Create a repository on GitHub.
|
|
78
|
+
2. Push your code:
|
|
79
|
+
```bash
|
|
80
|
+
git remote add origin https://github.com/username/repo.git
|
|
81
|
+
git branch -M main
|
|
82
|
+
git push -u origin main
|
|
83
|
+
```
|
|
84
|
+
3. Go to GitHub Settings > Pages > Build and deployment > Source > **GitHub Actions**.
|
|
85
|
+
|
|
86
|
+
<br>
|
|
87
|
+
|
|
88
|
+
## ⚙️ Configuration
|
|
89
|
+
|
|
90
|
+
Portosaurus is configured via `config.js` in your project root.
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
module.exports = {
|
|
94
|
+
usrConf: {
|
|
95
|
+
hero_section: {
|
|
96
|
+
title: "Your Name",
|
|
97
|
+
description: "Software Engineer",
|
|
98
|
+
// ...
|
|
99
|
+
},
|
|
100
|
+
// ...
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
<br>
|
|
106
|
+
|
|
107
|
+
## 📄 Credits
|
|
108
|
+
|
|
109
|
+
- [Docusaurus](https://docusaurus.io/) - The static site builder framework this is built upon.
|
|
110
|
+
- [React](https://react.dev) - UI library for building the interactive components.
|
|
111
|
+
- [React Icons](https://react-icons.github.io/) - Icon library used throughout the site.
|
|
112
|
+
- Libraries listed in [package.json](https://github.com/soymadip/portosaurus/blob/compiler/package.json#L16) - Essential dependencies.
|
|
113
|
+
- [Hugo Profile](https://hugo-profile.netlify.app/) - Design inspiration.
|
|
114
|
+
- [Catppuccin](https://github.com/catppuccin/catppuccin) - Color scheme that inspired the site's palette.
|
|
115
|
+
- [Deepseek R1](https://www.deepseek.com/) hosted using [Ollama](https://ollama.com/library/deepseek-r1) - prism.js theme & project card component.
|
|
116
|
+
- Countless Internet forum posts - Filling me with information.
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import fs from "fs-extra";
|
|
5
|
+
const {
|
|
6
|
+
readFileSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
existsSync,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
mkdirpSync,
|
|
11
|
+
readdirSync,
|
|
12
|
+
copySync,
|
|
13
|
+
removeSync,
|
|
14
|
+
} = fs;
|
|
15
|
+
import path from "path";
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
import { fileURLToPath } from "url";
|
|
18
|
+
import { spawn, execSync } from "child_process";
|
|
19
|
+
import { createRequire } from "module";
|
|
20
|
+
|
|
21
|
+
import { logger } from "../utils/logger.js";
|
|
22
|
+
import { createConfig } from "../utils/createConfig.js";
|
|
23
|
+
|
|
24
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
|
|
26
|
+
const packageJson = JSON.parse(
|
|
27
|
+
readFileSync(new URL("../package.json", import.meta.url)),
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const program = new Command();
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.name("portosaurus")
|
|
34
|
+
.description("CLI for Portosaurus - The complete portfolio solution")
|
|
35
|
+
.version(packageJson.version);
|
|
36
|
+
|
|
37
|
+
// ----------- HELPERS -------------
|
|
38
|
+
|
|
39
|
+
async function prepareDocusaurusRun(projectRoot) {
|
|
40
|
+
const configPath = path.join(projectRoot, "config.js");
|
|
41
|
+
|
|
42
|
+
if (!existsSync(configPath)) {
|
|
43
|
+
console.log();
|
|
44
|
+
logger.error(
|
|
45
|
+
"config.js not found. Are you in a Portosaurus project directory?",
|
|
46
|
+
);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Ensure internal files are synced to .portosaurus
|
|
51
|
+
const internalSrc = path.join(__dirname, "../internal/src");
|
|
52
|
+
const internalSidebars = path.join(__dirname, "../internal/sidebars.js");
|
|
53
|
+
const internalNotesIndex = path.join(__dirname, "../internal/notes/index.md");
|
|
54
|
+
|
|
55
|
+
const dotPorto = path.join(projectRoot, ".portosaurus");
|
|
56
|
+
const userSrc = path.join(dotPorto, "src");
|
|
57
|
+
const userSidebars = path.join(dotPorto, "sidebars.js");
|
|
58
|
+
|
|
59
|
+
// Ensure .portosaurus exists
|
|
60
|
+
fs.ensureDirSync(dotPorto);
|
|
61
|
+
|
|
62
|
+
// Always copy/overwrite src/
|
|
63
|
+
fs.copySync(internalSrc, userSrc);
|
|
64
|
+
|
|
65
|
+
// Always copy/overwrite sidebars.js
|
|
66
|
+
fs.copySync(internalSidebars, userSidebars);
|
|
67
|
+
|
|
68
|
+
// Ensure user has essential folders
|
|
69
|
+
const userRootNotes = path.join(projectRoot, "notes");
|
|
70
|
+
const userRootBlog = path.join(projectRoot, "blog");
|
|
71
|
+
const userRootStatic = path.join(projectRoot, "static");
|
|
72
|
+
|
|
73
|
+
fs.ensureDirSync(userRootNotes);
|
|
74
|
+
fs.ensureDirSync(userRootBlog);
|
|
75
|
+
fs.ensureDirSync(userRootStatic);
|
|
76
|
+
|
|
77
|
+
// Always ensure index.md exists (framework-managed file)
|
|
78
|
+
const userNotesIndex = path.join(userRootNotes, "index.md");
|
|
79
|
+
if (!fs.existsSync(userNotesIndex)) {
|
|
80
|
+
fs.copySync(internalNotesIndex, userNotesIndex);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Load user config
|
|
84
|
+
const require = createRequire(import.meta.url);
|
|
85
|
+
|
|
86
|
+
let userConfig;
|
|
87
|
+
try {
|
|
88
|
+
userConfig = require(configPath);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
logger.error(`Failed to load config.js: ${e.message}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Ensure defaults if missing
|
|
95
|
+
if (!userConfig.usrConf) {
|
|
96
|
+
userConfig.usrConf = {};
|
|
97
|
+
}
|
|
98
|
+
if (!userConfig.usrConf.site_url) {
|
|
99
|
+
userConfig.usrConf.site_url = "auto";
|
|
100
|
+
}
|
|
101
|
+
if (!userConfig.usrConf.site_path) {
|
|
102
|
+
userConfig.usrConf.site_path = "auto";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Generate Docusaurus Config
|
|
106
|
+
const docusaurusConfig = createConfig(userConfig, projectRoot);
|
|
107
|
+
|
|
108
|
+
// Write temp config file INSIDE .portosaurus
|
|
109
|
+
const tempConfigPath = path.join(dotPorto, "docusaurus.config.js");
|
|
110
|
+
|
|
111
|
+
const configContent = `// Auto-generated by Portosaurus
|
|
112
|
+
module.exports = ${JSON.stringify(docusaurusConfig, null, 2)};`;
|
|
113
|
+
|
|
114
|
+
writeFileSync(tempConfigPath, configContent);
|
|
115
|
+
logger.success("Generated Docusaurus config in .portosaurus.");
|
|
116
|
+
|
|
117
|
+
return { dotPorto };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function runDocusaurus(command, args, dotPorto, projectRoot) {
|
|
121
|
+
// Detect package manager and find docusaurus binary
|
|
122
|
+
const { findDocusaurusBin } = await import("../utils/packageManager.js");
|
|
123
|
+
const docusaurus = findDocusaurusBin(projectRoot || process.cwd());
|
|
124
|
+
|
|
125
|
+
logger.info(
|
|
126
|
+
`Running docusaurus ${command} (via ${docusaurus.packageManager})`,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const child = spawn(
|
|
130
|
+
docusaurus.command,
|
|
131
|
+
[...docusaurus.args, command, dotPorto, ...args],
|
|
132
|
+
{
|
|
133
|
+
stdio: "inherit",
|
|
134
|
+
cwd: projectRoot,
|
|
135
|
+
env: { ...process.env, FORCE_COLOR: "true" },
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
child.on("error", (err) => {
|
|
141
|
+
logger.error(`Failed to run docusaurus ${command}: ${err.message}`);
|
|
142
|
+
reject(err);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
child.on("close", (code) => {
|
|
146
|
+
if (code === 0) resolve();
|
|
147
|
+
else {
|
|
148
|
+
process.exit(code);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// --- INIT COMMAND ---
|
|
155
|
+
|
|
156
|
+
program
|
|
157
|
+
.command("init")
|
|
158
|
+
.description("Initialize a new Portosaurus project")
|
|
159
|
+
.argument("<project-name>", "Name of the project directory")
|
|
160
|
+
.option("-ngh, --no-github-pages", "Skip GitHub Pages deployment setup")
|
|
161
|
+
.option("-ni, --no-install", "Skip dependency installation")
|
|
162
|
+
.action(async (projectName, options) => {
|
|
163
|
+
const projectPath = path.resolve(process.cwd(), projectName);
|
|
164
|
+
|
|
165
|
+
if (existsSync(projectPath)) {
|
|
166
|
+
logger.error(`Directory ${projectName} already exists.`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
logger.info(
|
|
171
|
+
`Creating new Portosaurus project in ${chalk.bold(projectName)}...`,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
// Create project directory
|
|
176
|
+
mkdirSync(projectPath);
|
|
177
|
+
|
|
178
|
+
// Copy template files
|
|
179
|
+
const templatePath = path.resolve(__dirname, "../template");
|
|
180
|
+
|
|
181
|
+
// Check if template exists (it might not be populated yet)
|
|
182
|
+
if (!existsSync(templatePath)) {
|
|
183
|
+
logger.warn("Template directory not found. Creating basic structure.");
|
|
184
|
+
|
|
185
|
+
// Fallback basic creation if template missing (during dev)
|
|
186
|
+
mkdirpSync(path.join(projectPath, "blog"));
|
|
187
|
+
mkdirpSync(path.join(projectPath, "notes"));
|
|
188
|
+
mkdirpSync(path.join(projectPath, "static"));
|
|
189
|
+
writeFileSync(
|
|
190
|
+
path.join(projectPath, "config.js"),
|
|
191
|
+
"module.exports = { /* TODO */ };",
|
|
192
|
+
);
|
|
193
|
+
} else {
|
|
194
|
+
// Copy all template files
|
|
195
|
+
const templateFiles = readdirSync(templatePath);
|
|
196
|
+
|
|
197
|
+
for (const file of templateFiles) {
|
|
198
|
+
const srcPath = path.join(templatePath, file);
|
|
199
|
+
const destPath = path.join(projectPath, file);
|
|
200
|
+
copySync(srcPath, destPath);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Create package.json
|
|
205
|
+
const packageJsonContent = {
|
|
206
|
+
name: projectName,
|
|
207
|
+
version: "0.0.1",
|
|
208
|
+
private: true,
|
|
209
|
+
scripts: {
|
|
210
|
+
start: "portosaurus start",
|
|
211
|
+
build: "portosaurus build",
|
|
212
|
+
},
|
|
213
|
+
dependencies: {
|
|
214
|
+
portosaurus: "latest",
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
writeFileSync(
|
|
219
|
+
path.join(projectPath, "package.json"),
|
|
220
|
+
JSON.stringify(packageJsonContent, null, 2),
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
// Git init
|
|
224
|
+
try {
|
|
225
|
+
execSync("git init", { cwd: projectPath, stdio: "ignore" });
|
|
226
|
+
} catch (e) {
|
|
227
|
+
logger.warn("Failed to initialize git repository.");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Remove GitHub Pages files if --no-github-pages flag is set
|
|
231
|
+
if (options.githubPages === false) {
|
|
232
|
+
const githubDir = path.join(projectPath, ".github");
|
|
233
|
+
if (existsSync(githubDir)) {
|
|
234
|
+
removeSync(githubDir);
|
|
235
|
+
logger.info("Skipped GitHub Pages setup");
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
// GitHub Pages is enabled by default
|
|
239
|
+
// Create .nojekyll in static directory
|
|
240
|
+
const nojekyllPath = path.join(projectPath, "static", ".nojekyll");
|
|
241
|
+
writeFileSync(nojekyllPath, "");
|
|
242
|
+
|
|
243
|
+
logger.success("GitHub Pages deployment configured");
|
|
244
|
+
logger.tip(
|
|
245
|
+
"Enable GitHub Pages: Settings > Pages > Source: GitHub Actions",
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
logger.success(`Success! Created ${projectName} at ${projectPath}`);
|
|
250
|
+
|
|
251
|
+
// Detect package manager for install instructions
|
|
252
|
+
const { detectPackageManager } =
|
|
253
|
+
await import("../utils/packageManager.js");
|
|
254
|
+
const pm = detectPackageManager(projectPath) || "npm";
|
|
255
|
+
const installCmd = pm === "npm" ? "npm install" : `${pm} install`;
|
|
256
|
+
const runCmd = pm === "npm" ? "npm run" : `${pm} run`;
|
|
257
|
+
|
|
258
|
+
if (options.install !== false) {
|
|
259
|
+
logger.info(`Running ${installCmd}...`);
|
|
260
|
+
try {
|
|
261
|
+
execSync(installCmd, {
|
|
262
|
+
cwd: projectPath,
|
|
263
|
+
stdio: "inherit",
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
logger.success("Dependencies installed!");
|
|
267
|
+
logger.tip("You can now run:");
|
|
268
|
+
logger.info(` cd ${projectName}`);
|
|
269
|
+
logger.info(` ${runCmd} start`);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
logger.error("Failed to install dependencies.");
|
|
272
|
+
logger.tip("You can install them manually:");
|
|
273
|
+
logger.info(` cd ${projectName}`);
|
|
274
|
+
logger.info(` ${installCmd}`);
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
logger.tip("Inside that directory, you can run:");
|
|
278
|
+
logger.info(` cd ${projectName}`);
|
|
279
|
+
logger.info(` ${installCmd}`);
|
|
280
|
+
logger.info(` ${runCmd} start`);
|
|
281
|
+
}
|
|
282
|
+
} catch (error) {
|
|
283
|
+
logger.error(`Failed to initialize project: ${error.message}`);
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// --- START COMMAND ---
|
|
289
|
+
|
|
290
|
+
program
|
|
291
|
+
.command("start")
|
|
292
|
+
.description("Start the development server")
|
|
293
|
+
.action(async () => {
|
|
294
|
+
const projectRoot = process.cwd();
|
|
295
|
+
logger.info("Starting development server...");
|
|
296
|
+
try {
|
|
297
|
+
const { dotPorto } = await prepareDocusaurusRun(projectRoot);
|
|
298
|
+
await runDocusaurus("start", [], dotPorto, projectRoot);
|
|
299
|
+
} catch (error) {
|
|
300
|
+
logger.error(`Failed to start: ${error.message}`);
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// --- BUILD COMMAND ---
|
|
306
|
+
|
|
307
|
+
program
|
|
308
|
+
.command("build")
|
|
309
|
+
.description("Build the static site")
|
|
310
|
+
.action(async () => {
|
|
311
|
+
const projectRoot = process.cwd();
|
|
312
|
+
logger.info("Building Portosaurus site...");
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
const { dotPorto } = await prepareDocusaurusRun(projectRoot);
|
|
316
|
+
|
|
317
|
+
const buildDir = path.join(projectRoot, "build");
|
|
318
|
+
const args = ["--out-dir", buildDir];
|
|
319
|
+
|
|
320
|
+
await runDocusaurus("build", args, dotPorto, projectRoot);
|
|
321
|
+
|
|
322
|
+
// Create .nojekyll for GitHub Pages compatibility
|
|
323
|
+
const nojekyllPath = path.join(buildDir, ".nojekyll");
|
|
324
|
+
if (existsSync(buildDir)) {
|
|
325
|
+
writeFileSync(nojekyllPath, "");
|
|
326
|
+
logger.info("Created .nojekyll");
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
logger.success("Build completed successfully!");
|
|
330
|
+
logger.info(`Output directory: ${buildDir}`);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
logger.error(`Failed to build: ${error.message}`);
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
program.parse();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default sidebars configuration for Portosaurus
|
|
3
|
+
* This file is auto-generated and copied to user projects
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
notes: [
|
|
8
|
+
{
|
|
9
|
+
type: "category",
|
|
10
|
+
label: "Notes",
|
|
11
|
+
link: { type: "doc", id: "index" },
|
|
12
|
+
items: [
|
|
13
|
+
{
|
|
14
|
+
type: "autogenerated",
|
|
15
|
+
dirName: ".",
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
2
|
+
import styles from './styles.module.css';
|
|
3
|
+
|
|
4
|
+
export default function AboutSection({ id, className}) {
|
|
5
|
+
const { siteConfig } = useDocusaurusContext();
|
|
6
|
+
const { customFields } = siteConfig;
|
|
7
|
+
const aboutMe = customFields.aboutMe || {};
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<div id={id} className={`${styles.aboutSection} ${className || ''}`} role="region" aria-label="About me section">
|
|
11
|
+
<div className={styles.aboutContainer}>
|
|
12
|
+
<div className={styles.aboutHeader}>
|
|
13
|
+
<h2 className={styles.aboutHeading}>{"About Me"}</h2>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div className={styles.aboutContent}>
|
|
17
|
+
<div className={styles.aboutBio}>
|
|
18
|
+
<div className={styles.bioImageContainer}>
|
|
19
|
+
{aboutMe.image && (
|
|
20
|
+
<div className={styles.imageWrapper}>
|
|
21
|
+
<img
|
|
22
|
+
src={aboutMe.image}
|
|
23
|
+
alt="About Me"
|
|
24
|
+
className={styles.aboutImage}
|
|
25
|
+
loading="lazy"
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
)}
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div className={styles.bioTextContainer}>
|
|
32
|
+
<div className={styles.bioText}>
|
|
33
|
+
{Array.isArray(aboutMe.description) ? (
|
|
34
|
+
aboutMe.description.map((paragraph, index) => (
|
|
35
|
+
<p key={index} className={styles.aboutParagraph}>{paragraph}</p>
|
|
36
|
+
))
|
|
37
|
+
) : (
|
|
38
|
+
<p className={styles.aboutParagraph}>
|
|
39
|
+
{aboutMe.description || "Information about me goes here."}
|
|
40
|
+
</p>
|
|
41
|
+
)}
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
{aboutMe.skills && aboutMe.skills.length > 0 && (
|
|
45
|
+
<div className={styles.skillsContainer}>
|
|
46
|
+
<h3 className={styles.skillsTitle} id="skills-heading">My Skills</h3>
|
|
47
|
+
<div className={styles.skillsGrid} role="list">
|
|
48
|
+
{aboutMe.skills.map((skill, index) => (
|
|
49
|
+
<div
|
|
50
|
+
key={index}
|
|
51
|
+
className={styles.skillBadge}
|
|
52
|
+
role="listitem"
|
|
53
|
+
style={{ animationDelay: `${index * 0.05}s` }}
|
|
54
|
+
>
|
|
55
|
+
{skill}
|
|
56
|
+
</div>
|
|
57
|
+
))}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|