portosaurus 2.0.2 → 2.1.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 (91) hide show
  1. package/bin/portosaurus.mjs +14 -327
  2. package/package.json +16 -11
  3. package/src/cli/build.mjs +43 -0
  4. package/src/cli/dev.mjs +31 -0
  5. package/src/cli/init.mjs +135 -0
  6. package/src/cli/serve.mjs +30 -0
  7. package/src/core/buildDocuConfig.mjs +664 -0
  8. package/src/core/{themePlugin.mjs → plugins/themePlugin.mjs} +1 -1
  9. package/src/template/.github/workflows/deploy.yml +52 -0
  10. package/src/template/.nojekyll +0 -0
  11. package/src/template/README.md +58 -0
  12. package/src/template/blog/authors.yml +1 -1
  13. package/src/template/blog/welcome.md +1 -1
  14. package/src/template/config.js +40 -23
  15. package/src/template/package.json +20 -0
  16. package/src/template/static/img/svg/icon-blog.svg +2 -0
  17. package/src/template/static/img/svg/icon-note.svg +2 -0
  18. package/src/{components → theme/components}/AboutSection/index.js +22 -13
  19. package/src/{components → theme/components}/AboutSection/styles.module.css +59 -48
  20. package/src/{components → theme/components}/ContactSection/index.js +31 -24
  21. package/src/{components → theme/components}/ContactSection/styles.module.css +31 -26
  22. package/src/{components → theme/components}/ExperienceSection/index.js +12 -7
  23. package/src/{components → theme/components}/ExperienceSection/styles.module.css +23 -20
  24. package/src/{components → theme/components}/HeroSection/index.js +9 -11
  25. package/src/{components → theme/components}/HeroSection/styles.module.css +44 -32
  26. package/src/{components → theme/components}/NoteIndex/index.js +10 -3
  27. package/src/{components → theme/components}/Preview/components/PreviewHeader.js +14 -8
  28. package/src/{components → theme/components}/Preview/components/Triggers/Pv.js +32 -7
  29. package/src/{components → theme/components}/Preview/components/Triggers/SrcPv.js +1 -5
  30. package/src/theme/components/Preview/index.js +3 -0
  31. package/src/{components → theme/components}/ProjectsSection/index.js +279 -224
  32. package/src/{components → theme/components}/ProjectsSection/styles.module.css +21 -17
  33. package/src/{components → theme/components}/ScrollToTop/index.js +18 -21
  34. package/src/{components → theme/components}/ScrollToTop/styles.module.css +10 -9
  35. package/src/theme/components/SocialLinks/index.js +125 -0
  36. package/src/{components → theme/components}/SocialLinks/styles.module.css +9 -7
  37. package/src/{components → theme/components}/Tooltip/index.js +4 -1
  38. package/src/theme/config/iconMappings.js +465 -0
  39. package/src/theme/config/metaTags.js +239 -0
  40. package/src/theme/config/prism.js +179 -0
  41. package/src/theme/config/sidebar.js +17 -0
  42. package/src/{css → theme/css}/bootstrap.css +0 -1
  43. package/src/theme/css/catppuccin.css +618 -0
  44. package/src/{css → theme/css}/custom.css +3 -9
  45. package/src/{css → theme/css}/tasks.css +43 -37
  46. package/src/theme/{MDXComponents.js → overrides/MDXComponents.js} +3 -3
  47. package/src/theme/{Root.js → overrides/Root.js} +2 -4
  48. package/src/{pages → theme/pages}/index.js +23 -39
  49. package/src/theme/pages/notes.js +83 -0
  50. package/src/{pages → theme/pages}/tasks.js +115 -56
  51. package/src/{core/client-utils → theme/utils}/HashNavigation.js +60 -49
  52. package/src/{core/client-utils → theme/utils}/updateTitle.js +21 -25
  53. package/src/{core/build-utils → utils/build}/cssUtils.mjs +5 -3
  54. package/src/{core/build-utils → utils/build}/generateFavicon.mjs +44 -12
  55. package/src/{core/build-utils → utils/build}/generateRobotsTxt.mjs +4 -3
  56. package/src/{core/build-utils → utils/build}/iconExtractor.mjs +7 -3
  57. package/src/utils/build/imageDownloader.mjs +159 -0
  58. package/src/{core/build-utils → utils/build}/imageProcessor.mjs +5 -6
  59. package/src/utils/helpers.mjs +153 -0
  60. package/src/utils/logger.mjs +53 -0
  61. package/src/utils/packageManager.mjs +88 -0
  62. package/src/components/Preview/index.js +0 -3
  63. package/src/components/SocialLinks/index.js +0 -130
  64. package/src/config/iconMappings.js +0 -329
  65. package/src/config/metaTags.js +0 -240
  66. package/src/config/prism.js +0 -179
  67. package/src/config/sidebar.js +0 -20
  68. package/src/core/build-utils/imageDownloader.mjs +0 -98
  69. package/src/core/createDocuConf.mjs +0 -490
  70. package/src/core/defaults.mjs +0 -67
  71. package/src/core/logger.mjs +0 -17
  72. package/src/core/packageManager.mjs +0 -72
  73. package/src/css/catppuccin.css +0 -632
  74. package/src/pages/notes.js +0 -87
  75. /package/src/template/notes/{welcome.md → welcome.mdx} +0 -0
  76. /package/src/{components → theme/components}/NoteIndex/styles.module.css +0 -0
  77. /package/src/{components → theme/components}/Preview/components/FeedbackStates.js +0 -0
  78. /package/src/{components → theme/components}/Preview/components/FileTabs.js +0 -0
  79. /package/src/{components → theme/components}/Preview/components/Triggers/index.js +0 -0
  80. /package/src/{components → theme/components}/Preview/components/ViewerWindow.js +0 -0
  81. /package/src/{components → theme/components}/Preview/hooks/useDeepLinkHash.js +0 -0
  82. /package/src/{components → theme/components}/Preview/hooks/useDockLayout.js +0 -0
  83. /package/src/{components → theme/components}/Preview/hooks/useFileFetch.js +0 -0
  84. /package/src/{components → theme/components}/Preview/renderers/CodeRenderer.js +0 -0
  85. /package/src/{components → theme/components}/Preview/renderers/ImageRenderer.js +0 -0
  86. /package/src/{components → theme/components}/Preview/renderers/PdfRenderer.js +0 -0
  87. /package/src/{components → theme/components}/Preview/renderers/WebRenderer.js +0 -0
  88. /package/src/{components → theme/components}/Preview/state/index.js +0 -0
  89. /package/src/{components → theme/components}/Preview/styles.module.css +0 -0
  90. /package/src/{components → theme/components}/Preview/utils/index.js +0 -0
  91. /package/src/{components → theme/components}/Tooltip/styles.module.css +0 -0
@@ -4,20 +4,17 @@ import { Command } from "commander";
4
4
  import fs from "fs";
5
5
  import path from "path";
6
6
  import { fileURLToPath } from "url";
7
- import { spawn, execSync } from "child_process";
8
7
 
9
- import { logger } from "../src/core/logger.mjs";
10
- import {
11
- detectPackageManager,
12
- getInstallCommand,
13
- findDocusaurusBin,
14
- } from "../src/core/packageManager.mjs";
8
+ import { initCommand } from "../src/cli/init.mjs";
9
+ import { devCommand } from "../src/cli/dev.mjs";
10
+ import { buildCommand } from "../src/cli/build.mjs";
11
+ import { serveCommand } from "../src/cli/serve.mjs";
15
12
 
16
13
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
- const portosaurusRoot = path.resolve(__dirname, "..");
14
+ const PortoRoot = path.resolve(__dirname, "..");
18
15
 
19
16
  const packageJson = JSON.parse(
20
- fs.readFileSync(path.resolve(portosaurusRoot, "package.json"), "utf8"),
17
+ fs.readFileSync(path.resolve(PortoRoot, "package.json"), "utf8"),
21
18
  );
22
19
 
23
20
  const program = new Command();
@@ -27,116 +24,7 @@ program
27
24
  .description("CLI for Portosaurus — The complete portfolio solution")
28
25
  .version(packageJson.version, "-v, --version", "output the current version");
29
26
 
30
- // ─── Helpers ────────────────────────────────────────────────
31
-
32
- /**
33
- * Write the ephemeral .portosaurus/docusaurus.config.mjs shim.
34
- * This tiny file imports the user's config.js and passes it
35
- * to the portosaurus config generator using absolute paths.
36
- */
37
- function writeConfigShim(projectRoot) {
38
- const dotDir = path.join(projectRoot, ".docusaurus", "portosaurus");
39
- fs.mkdirSync(dotDir, { recursive: true });
40
-
41
- const configJsAbsolute = path
42
- .join(projectRoot, "config.js")
43
- .replace(/\\/g, "/");
44
- const createDocuConfAbsolute = path
45
- .resolve(portosaurusRoot, "src/core/createDocuConf.mjs")
46
- .replace(/\\/g, "/");
47
-
48
- // Docusaurus 3 supports ESM and async config functions.
49
- const shimContent = `// Auto-generated by Portosaurus CLI — do not edit
50
- /** @type {import('@docusaurus/types').Config} */
51
- export default async function getConfig() {
52
- const { createDocuConf } = await import("file://${createDocuConfAbsolute}");
53
- const { usrConf } = await import("file://${configJsAbsolute}");
54
- return createDocuConf(usrConf, "${projectRoot.replace(/\\/g, "/")}");
55
- }
56
- `;
57
-
58
- const shimPath = path.join(dotDir, "docusaurus.config.js");
59
- fs.writeFileSync(shimPath, shimContent);
60
- logger.debug(`Config shim written to ${shimPath}`);
61
-
62
- return shimPath;
63
- }
64
-
65
- /**
66
- * Validate that the current directory is a Portosaurus project.
67
- */
68
- function validateProject(projectRoot) {
69
- const configPath = path.join(projectRoot, "config.js");
70
- if (!fs.existsSync(configPath)) {
71
- console.log();
72
- logger.error(
73
- "config.js not found. Are you in a Portosaurus project directory?",
74
- );
75
- process.exit(1);
76
- }
77
- }
78
-
79
- /**
80
- * Ensure essential user content directories exist.
81
- */
82
- function ensureContentDirs(projectRoot) {
83
- for (const dir of ["notes", "blog", "static"]) {
84
- fs.mkdirSync(path.join(projectRoot, dir), { recursive: true });
85
- }
86
-
87
- // Ensure notes has at least an index.mdx so Docusaurus doesn't error
88
- const notesIndex = path.join(projectRoot, "notes", "index.mdx");
89
- if (!fs.existsSync(notesIndex)) {
90
- fs.writeFileSync(
91
- notesIndex,
92
- `---\nhide_table_of_contents: true\n---\n\nimport NoteCards from "portosaurus/src/components/NoteIndex/index.js";\n\n# Notes\n\n<NoteCards />\n`,
93
- );
94
- logger.debug("Created default notes/index.mdx");
95
- }
96
- }
97
-
98
- /**
99
- * Spawn a Docusaurus command and wait for it to complete.
100
- */
101
- function runDocusaurus(command, extraArgs, projectRoot, configPath) {
102
- const {
103
- command: cmd,
104
- args: pmArgs,
105
- packageManager,
106
- } = findDocusaurusBin(projectRoot);
107
-
108
- logger.info(`Running docusaurus ${command} (via ${packageManager})`);
109
-
110
- // Use the dynamically detected package manager command instead of hardcoding
111
- const spawnCommand = cmd;
112
- const finalArgs = [
113
- ...pmArgs,
114
- command,
115
- projectRoot,
116
- "--config",
117
- configPath,
118
- ...extraArgs,
119
- ];
120
-
121
- const child = spawn(spawnCommand, finalArgs, {
122
- stdio: "inherit",
123
- cwd: projectRoot,
124
- env: { ...process.env, FORCE_COLOR: "true" },
125
- });
126
-
127
- return new Promise((resolve, reject) => {
128
- child.on("error", (err) => {
129
- logger.error(`Failed to run docusaurus ${command}: ${err.message}`);
130
- reject(err);
131
- });
132
- child.on("close", (code) => {
133
- if (code === 0) resolve();
134
- else process.exit(code);
135
- });
136
- });
137
- }
138
-
139
- // ─── INIT COMMAND ───────────────────────────────────────────
27
+ // ─── COMMANDS ───────────────────────────────────────────────
140
28
 
141
29
  program
142
30
  .command("init")
@@ -144,225 +32,24 @@ program
144
32
  .argument("<project-name>", "Name of the project directory")
145
33
  .option("--no-install", "Skip dependency installation")
146
34
  .option("--no-github-pages", "Skip GitHub Pages deployment setup")
147
- .action(async (projectName, options) => {
148
- const projectPath = path.resolve(process.cwd(), projectName);
149
-
150
- if (fs.existsSync(projectPath)) {
151
- logger.error(`Directory "${projectName}" already exists.`);
152
- process.exit(1);
153
- }
154
-
155
- logger.info(`Creating new Portosaurus project in ${projectName}...`);
156
-
157
- try {
158
- fs.mkdirSync(projectPath, { recursive: true });
159
-
160
- // Copy template files if they exist
161
- const templatePath = path.resolve(portosaurusRoot, "src/template");
162
- if (fs.existsSync(templatePath)) {
163
- copyDirSync(templatePath, projectPath);
164
- }
165
-
166
- // Ensure content directories
167
- for (const dir of ["blog", "notes", "static"]) {
168
- fs.mkdirSync(path.join(projectPath, dir), { recursive: true });
169
- }
170
-
171
- // Create a minimal config.js if the template didn't provide one
172
- const configDest = path.join(projectPath, "config.js");
173
- if (!fs.existsSync(configDest)) {
174
- fs.writeFileSync(
175
- configDest,
176
- `exports.usrConf = {\n dark_mode: true,\n site_url: "auto",\n site_path: "auto",\n\n hero_section: {\n title: "${projectName}",\n profession: "Your Profession",\n description: "Short description about you.",\n },\n};\n`,
177
- );
178
- }
179
-
180
- // Create package.json
181
- const pkg = {
182
- name: projectName,
183
- version: "0.0.1",
184
- private: true,
185
- scripts: {
186
- dev: "portosaurus dev",
187
- start: "portosaurus start",
188
- build: "portosaurus build",
189
- serve: "portosaurus serve",
190
- },
191
- dependencies: {
192
- portosaurus: `^${packageJson.version}`,
193
- },
194
- overrides: {
195
- webpack: "5.105.4",
196
- },
197
- resolutions: {
198
- webpack: "5.105.4",
199
- },
200
- };
201
- fs.writeFileSync(
202
- path.join(projectPath, "package.json"),
203
- JSON.stringify(pkg, null, 2),
204
- );
205
-
206
- // Create .gitignore
207
- fs.writeFileSync(
208
- path.join(projectPath, ".gitignore"),
209
- `node_modules/\nbuild/\n.docusaurus/\n.cache-loader/\n`,
210
- );
211
-
212
- // Git init
213
- try {
214
- execSync("git init", { cwd: projectPath, stdio: "ignore" });
215
- execSync("git add .", { cwd: projectPath, stdio: "ignore" });
216
- execSync('git commit -m "Initialize Portosaurus project"', {
217
- cwd: projectPath,
218
- stdio: "ignore",
219
- });
220
- } catch {
221
- logger.warn("Failed to initialize git repository.");
222
- }
223
-
224
- // GitHub Pages setup
225
- if (options.githubPages === false) {
226
- const ghDir = path.join(projectPath, ".github");
227
- if (fs.existsSync(ghDir)) {
228
- fs.rmSync(ghDir, { recursive: true, force: true });
229
- logger.info("Skipped GitHub Pages setup.");
230
- }
231
- } else {
232
- fs.writeFileSync(path.join(projectPath, "static", ".nojekyll"), "");
233
- logger.success("GitHub Pages deployment configured.");
234
- logger.tip(
235
- "Enable GitHub Pages: Settings > Pages > Source: GitHub Actions",
236
- );
237
- }
238
-
239
- logger.success(`Created ${projectName} at ${projectPath}`);
240
-
241
- // Install dependencies
242
- const pm = detectPackageManager(projectPath) || "npm";
243
- const installCmd = getInstallCommand(pm);
244
- const runCmd = pm === "npm" ? "npm run" : `${pm} run`;
245
-
246
- if (options.install !== false) {
247
- logger.info(`Running ${installCmd}...`);
248
- try {
249
- execSync(installCmd, { cwd: projectPath, stdio: "inherit" });
250
- logger.success("Dependencies installed!");
251
- } catch {
252
- logger.error("Failed to install dependencies.");
253
- }
254
- }
255
-
256
- logger.tip("You can now run:");
257
- logger.info(` cd ${projectName}`);
258
- logger.info(` ${runCmd} dev`);
259
- } catch (error) {
260
- logger.error(`Failed to initialize project: ${error.message}`);
261
- process.exit(1);
262
- }
263
- });
264
-
265
- // ─── DEV / START COMMAND ────────────────────────────────────
35
+ .action(initCommand);
266
36
 
267
37
  program
268
- .command("start [extraArgs...]")
38
+ .command("start [siteDir] [extraArgs...]")
269
39
  .alias("dev")
270
40
  .description("Start the development server")
271
41
  .allowUnknownOption()
272
- .action(async function (extraArgs) {
273
- const projectRoot = process.cwd();
274
- validateProject(projectRoot);
275
- ensureContentDirs(projectRoot);
276
-
277
- logger.info("Starting development server...");
278
- try {
279
- const configPath = writeConfigShim(projectRoot);
280
- runDocusaurus("start", extraArgs || [], projectRoot, configPath);
281
- } catch (error) {
282
- logger.error(`Failed to start: ${error.message}`);
283
- process.exit(1);
284
- }
285
- });
286
-
287
- // ─── BUILD COMMAND ──────────────────────────────────────────
42
+ .action(devCommand);
288
43
 
289
44
  program
290
- .command("build [extraArgs...]")
45
+ .command("build [siteDir] [extraArgs...]")
291
46
  .description("Build the static site")
292
47
  .allowUnknownOption()
293
- .action(async function (extraArgs) {
294
- const projectRoot = process.cwd();
295
- validateProject(projectRoot);
296
- ensureContentDirs(projectRoot);
297
-
298
- logger.info("Building Portosaurus site...");
299
- try {
300
- const configPath = writeConfigShim(projectRoot);
301
- const buildDir = path.join(projectRoot, "build");
302
- const args = ["--out-dir", buildDir, ...(extraArgs || [])];
303
-
304
- await runDocusaurus("build", args, projectRoot, configPath);
305
-
306
- // Create .nojekyll for GitHub Pages compatibility
307
- if (fs.existsSync(buildDir)) {
308
- fs.writeFileSync(path.join(buildDir, ".nojekyll"), "");
309
- logger.info("Created .nojekyll");
310
- }
311
-
312
- logger.success("Build completed successfully!");
313
- logger.info(`Output directory: ${buildDir}`);
314
- } catch (error) {
315
- logger.error(`Failed to build: ${error.message}`);
316
- process.exit(1);
317
- }
318
- });
319
-
320
- // ─── SERVE COMMAND ──────────────────────────────────────────
48
+ .action(buildCommand);
321
49
 
322
50
  program
323
- .command("serve")
51
+ .command("serve [siteDir]")
324
52
  .description("Serve the built static site locally")
325
- .action(async () => {
326
- const projectRoot = process.cwd();
327
- validateProject(projectRoot);
328
-
329
- const buildDir = path.join(projectRoot, "build");
330
- if (!fs.existsSync(buildDir)) {
331
- logger.error("Build directory not found. Run 'portosaurus build' first.");
332
- process.exit(1);
333
- }
334
-
335
- logger.info("Serving Portosaurus site...");
336
- try {
337
- const configPath = writeConfigShim(projectRoot);
338
- await runDocusaurus(
339
- "serve",
340
- ["--dir", buildDir],
341
- projectRoot,
342
- configPath,
343
- );
344
- } catch (error) {
345
- logger.error(`Failed to serve: ${error.message}`);
346
- process.exit(1);
347
- }
348
- });
349
-
350
- // ─── Utility ────────────────────────────────────────────────
351
-
352
- /**
353
- * Recursively copy a directory.
354
- */
355
- function copyDirSync(src, dest) {
356
- fs.mkdirSync(dest, { recursive: true });
357
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
358
- const srcPath = path.join(src, entry.name);
359
- const destPath = path.join(dest, entry.name);
360
- if (entry.isDirectory()) {
361
- copyDirSync(srcPath, destPath);
362
- } else {
363
- fs.copyFileSync(srcPath, destPath);
364
- }
365
- }
366
- }
53
+ .action(serveCommand);
367
54
 
368
55
  program.parse();
package/package.json CHANGED
@@ -1,25 +1,28 @@
1
1
  {
2
2
  "name": "portosaurus",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "private": false,
5
+ "homepage": "https://github.com/soymadip/portosaurus",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/soymadip/portosaurus.git"
9
+ },
5
10
  "bin": {
6
11
  "portosaurus": "bin/portosaurus.mjs"
7
12
  },
8
13
  "files": [
9
14
  "bin/",
10
- "src/components/",
11
- "src/config/",
15
+ "src/assets/",
16
+ "src/cli/",
12
17
  "src/core/",
13
- "src/css/",
14
- "src/pages/",
15
18
  "src/theme/",
16
- "src/template/",
17
- "src/assets/"
19
+ "src/utils/",
20
+ "src/template/"
18
21
  ],
19
22
  "scripts": {
20
- "dev": "$npm_execpath bin/portosaurus.mjs dev",
21
- "build": "$npm_execpath bin/portosaurus.mjs build",
22
- "serve": "$npm_execpath bin/portosaurus.mjs serve"
23
+ "test": "bun test",
24
+ "lint": "prettier --check .",
25
+ "format": "prettier --write ."
23
26
  },
24
27
  "dependencies": {
25
28
  "@docusaurus/core": "^3.10.0",
@@ -29,6 +32,7 @@
29
32
  "chalk": "^5.4.1",
30
33
  "clsx": "^2.1.1",
31
34
  "commander": "^13.1.0",
35
+ "consola": "^3.4.2",
32
36
  "favicons": "7.2.0",
33
37
  "framer-motion": "^12.38.0",
34
38
  "plugin-image-zoom": "github:flexanalytics/plugin-image-zoom",
@@ -44,7 +48,8 @@
44
48
  },
45
49
  "devDependencies": {
46
50
  "@docusaurus/module-type-aliases": "^3.10.0",
47
- "@docusaurus/types": "^3.10.0"
51
+ "@docusaurus/types": "^3.10.0",
52
+ "prettier": "^3.8.3"
48
53
  },
49
54
  "browserslist": {
50
55
  "production": [
@@ -0,0 +1,43 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { logger } from "../utils/logger.mjs";
4
+ import {
5
+ validateProject,
6
+ ensureContentDirs,
7
+ writePortoConfigShim,
8
+ runDocusaurus,
9
+ PortoRoot,
10
+ } from "../utils/helpers.mjs";
11
+
12
+ export async function buildCommand(siteDir, extraArgs) {
13
+ const UserRoot = siteDir
14
+ ? path.resolve(process.cwd(), siteDir)
15
+ : process.cwd();
16
+ validateProject(UserRoot);
17
+ ensureContentDirs(UserRoot);
18
+
19
+ const packageJsonPath = path.resolve(PortoRoot, "package.json");
20
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
21
+
22
+ logger.box("Portosaurus Build", `v${packageJson.version}`);
23
+ logger.info("Building Portosaurus site...");
24
+ try {
25
+ const configPath = writePortoConfigShim(UserRoot);
26
+ const buildDir = path.join(UserRoot, "build");
27
+ const args = ["--out-dir", buildDir, ...(extraArgs || [])];
28
+
29
+ await runDocusaurus("build", args, UserRoot, configPath);
30
+
31
+ // Create .nojekyll for GitHub Pages compatibility
32
+ if (fs.existsSync(buildDir)) {
33
+ fs.writeFileSync(path.join(buildDir, ".nojekyll"), "");
34
+ logger.info("Created .nojekyll");
35
+ }
36
+
37
+ logger.success("Build completed successfully!");
38
+ logger.info(`Output directory: ${buildDir}`);
39
+ } catch (error) {
40
+ logger.error(`Failed to build: ${error.message}`);
41
+ process.exit(1);
42
+ }
43
+ }
@@ -0,0 +1,31 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { logger } from "../utils/logger.mjs";
4
+ import {
5
+ validateProject,
6
+ ensureContentDirs,
7
+ writePortoConfigShim,
8
+ runDocusaurus,
9
+ PortoRoot,
10
+ } from "../utils/helpers.mjs";
11
+
12
+ export async function devCommand(siteDir, extraArgs) {
13
+ const UserRoot = siteDir
14
+ ? path.resolve(process.cwd(), siteDir)
15
+ : process.cwd();
16
+ validateProject(UserRoot);
17
+ ensureContentDirs(UserRoot);
18
+
19
+ const packageJsonPath = path.resolve(PortoRoot, "package.json");
20
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
21
+
22
+ logger.box("Portosaurus Dev Server", `v${packageJson.version}`);
23
+ logger.info("Starting development server...");
24
+ try {
25
+ const configPath = writePortoConfigShim(UserRoot);
26
+ await runDocusaurus("start", extraArgs || [], UserRoot, configPath);
27
+ } catch (error) {
28
+ logger.error(`Failed to start: ${error.message}`);
29
+ process.exit(1);
30
+ }
31
+ }
@@ -0,0 +1,135 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { logger } from "../utils/logger.mjs";
4
+ import { getPackageManager } from "../utils/packageManager.mjs";
5
+ import { PortoRoot, mirrorSync } from "../utils/helpers.mjs";
6
+
7
+ export async function initCommand(projectName, options) {
8
+ const projectDir = path.resolve(process.cwd(), projectName);
9
+ const templateDir = path.resolve(PortoRoot, "src/template");
10
+ const packageJson = JSON.parse(
11
+ fs.readFileSync(path.resolve(PortoRoot, "package.json"), "utf8"),
12
+ );
13
+
14
+ const TemplateVars = {
15
+ projectName: projectName,
16
+ portoVer: packageJson.version,
17
+ portoHome: packageJson.homepage,
18
+ portoRepo: packageJson.repository.url,
19
+ };
20
+
21
+ const ignoreList = [
22
+ "node_modules",
23
+ ".docusaurus",
24
+ ".cache-loader",
25
+ "build",
26
+ ".DS_Store",
27
+ ".git",
28
+ ];
29
+
30
+ const contentDirs = ["blog", "notes", "static"];
31
+
32
+ if (fs.existsSync(projectDir)) {
33
+ logger.error(`Target Directory "${projectName}" already exists.`);
34
+ process.exit(1);
35
+ }
36
+
37
+ logger.box(
38
+ "Initializing New Portosaurus Project",
39
+ ` v${packageJson.version} `,
40
+ );
41
+
42
+ logger.info(`Creating new project in ${projectName}...`);
43
+
44
+ try {
45
+ const { execSync } = await import("child_process");
46
+
47
+ // Create user project directory
48
+ fs.mkdirSync(projectDir, { recursive: true });
49
+
50
+ // Git Init
51
+ try {
52
+ execSync("git init", { cwd: projectDir, stdio: "ignore" });
53
+ } catch {
54
+ logger.warn("Failed to initialize git repository.");
55
+ process.exit(1);
56
+ }
57
+
58
+ // Make Content directories
59
+ for (const dir of contentDirs) {
60
+ fs.mkdirSync(path.join(projectDir, dir), { recursive: true });
61
+ }
62
+
63
+ // Copy template files, dirs
64
+ if (fs.existsSync(templateDir)) {
65
+ mirrorSync(templateDir, projectDir, TemplateVars, ignoreList);
66
+ } else {
67
+ logger.error(`Portosaurus template directory not found: ${templateDir}`);
68
+ process.exit(1);
69
+ }
70
+
71
+ // Initial Commit
72
+ try {
73
+ // Add all files to git
74
+ execSync("git add .", {
75
+ cwd: projectDir,
76
+ stdio: "ignore",
77
+ });
78
+
79
+ // Initial Commit
80
+ execSync('git commit -m "Initialize Portosaurus project"', {
81
+ cwd: projectDir,
82
+ stdio: "ignore",
83
+ });
84
+ } catch {
85
+ logger.warn(
86
+ "Failed to commit changes.\nPlease commit your changes manually.",
87
+ );
88
+ }
89
+
90
+ // GitHub Pages setup
91
+ if (options.githubPages === false) {
92
+ const ghDir = path.join(projectDir, ".github");
93
+
94
+ // Delete copied .github directory
95
+ if (fs.existsSync(ghDir)) {
96
+ fs.rmSync(ghDir, { recursive: true, force: true });
97
+ logger.info("Skipped GitHub Pages setup.");
98
+ }
99
+ } else {
100
+ logger.success("GitHub Pages deployment configured.");
101
+ logger.tip(
102
+ "Enable GitHub Pages in repo: Settings > Pages > Source: GitHub Actions",
103
+ );
104
+ }
105
+
106
+ logger.success(`Created ${projectName} at ${projectDir}`);
107
+
108
+ // Install dependencies
109
+ const pm = getPackageManager(projectDir);
110
+
111
+ logger.info(`Installing dependencies with ${pm.name}...`);
112
+
113
+ if (options.install !== false) {
114
+ logger.info(`Running ${pm.install}...`);
115
+ try {
116
+ const { execSync } = await import("child_process");
117
+ execSync(pm.install, { cwd: projectDir, stdio: "inherit" });
118
+ logger.success("Dependencies installed!");
119
+ } catch {
120
+ logger.error(
121
+ "Failed to install dependencies. You can run it manually later.",
122
+ );
123
+ }
124
+ }
125
+
126
+ logger.tip("You can now run:");
127
+ logger.info(` cd ${projectName}`);
128
+ logger.info(` ${pm.run} dev`);
129
+
130
+ // end
131
+ } catch (error) {
132
+ logger.error(`Failed to initialize project: ${error.message}`);
133
+ process.exit(1);
134
+ }
135
+ }
@@ -0,0 +1,30 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { logger } from "../utils/logger.mjs";
4
+ import {
5
+ validateProject,
6
+ writePortoConfigShim,
7
+ runDocusaurus,
8
+ } from "../utils/helpers.mjs";
9
+
10
+ export async function serveCommand(siteDir) {
11
+ const UserRoot = siteDir
12
+ ? path.resolve(process.cwd(), siteDir)
13
+ : process.cwd();
14
+ validateProject(UserRoot);
15
+
16
+ const buildDir = path.join(UserRoot, "build");
17
+ if (!fs.existsSync(buildDir)) {
18
+ logger.error("Build directory not found. Run 'portosaurus build' first.");
19
+ process.exit(1);
20
+ }
21
+
22
+ logger.info("Serving Portosaurus site...");
23
+ try {
24
+ const configPath = writePortoConfigShim(UserRoot);
25
+ await runDocusaurus("serve", ["--dir", buildDir], UserRoot, configPath);
26
+ } catch (error) {
27
+ logger.error(`Failed to serve: ${error.message}`);
28
+ process.exit(1);
29
+ }
30
+ }