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.
- package/bin/portosaurus.mjs +14 -327
- package/package.json +16 -11
- package/src/cli/build.mjs +43 -0
- package/src/cli/dev.mjs +31 -0
- package/src/cli/init.mjs +135 -0
- package/src/cli/serve.mjs +30 -0
- package/src/core/buildDocuConfig.mjs +664 -0
- package/src/core/{themePlugin.mjs → plugins/themePlugin.mjs} +1 -1
- package/src/template/.github/workflows/deploy.yml +52 -0
- package/src/template/.nojekyll +0 -0
- package/src/template/README.md +58 -0
- package/src/template/blog/authors.yml +1 -1
- package/src/template/blog/welcome.md +1 -1
- package/src/template/config.js +40 -23
- package/src/template/package.json +20 -0
- package/src/template/static/img/svg/icon-blog.svg +2 -0
- package/src/template/static/img/svg/icon-note.svg +2 -0
- package/src/{components → theme/components}/AboutSection/index.js +22 -13
- package/src/{components → theme/components}/AboutSection/styles.module.css +59 -48
- package/src/{components → theme/components}/ContactSection/index.js +31 -24
- package/src/{components → theme/components}/ContactSection/styles.module.css +31 -26
- package/src/{components → theme/components}/ExperienceSection/index.js +12 -7
- package/src/{components → theme/components}/ExperienceSection/styles.module.css +23 -20
- package/src/{components → theme/components}/HeroSection/index.js +9 -11
- package/src/{components → theme/components}/HeroSection/styles.module.css +44 -32
- package/src/{components → theme/components}/NoteIndex/index.js +10 -3
- package/src/{components → theme/components}/Preview/components/PreviewHeader.js +14 -8
- package/src/{components → theme/components}/Preview/components/Triggers/Pv.js +32 -7
- package/src/{components → theme/components}/Preview/components/Triggers/SrcPv.js +1 -5
- package/src/theme/components/Preview/index.js +3 -0
- package/src/{components → theme/components}/ProjectsSection/index.js +279 -224
- package/src/{components → theme/components}/ProjectsSection/styles.module.css +21 -17
- package/src/{components → theme/components}/ScrollToTop/index.js +18 -21
- package/src/{components → theme/components}/ScrollToTop/styles.module.css +10 -9
- package/src/theme/components/SocialLinks/index.js +125 -0
- package/src/{components → theme/components}/SocialLinks/styles.module.css +9 -7
- package/src/{components → theme/components}/Tooltip/index.js +4 -1
- package/src/theme/config/iconMappings.js +465 -0
- package/src/theme/config/metaTags.js +239 -0
- package/src/theme/config/prism.js +179 -0
- package/src/theme/config/sidebar.js +17 -0
- package/src/{css → theme/css}/bootstrap.css +0 -1
- package/src/theme/css/catppuccin.css +618 -0
- package/src/{css → theme/css}/custom.css +3 -9
- package/src/{css → theme/css}/tasks.css +43 -37
- package/src/theme/{MDXComponents.js → overrides/MDXComponents.js} +3 -3
- package/src/theme/{Root.js → overrides/Root.js} +2 -4
- package/src/{pages → theme/pages}/index.js +23 -39
- package/src/theme/pages/notes.js +83 -0
- package/src/{pages → theme/pages}/tasks.js +115 -56
- package/src/{core/client-utils → theme/utils}/HashNavigation.js +60 -49
- package/src/{core/client-utils → theme/utils}/updateTitle.js +21 -25
- package/src/{core/build-utils → utils/build}/cssUtils.mjs +5 -3
- package/src/{core/build-utils → utils/build}/generateFavicon.mjs +44 -12
- package/src/{core/build-utils → utils/build}/generateRobotsTxt.mjs +4 -3
- package/src/{core/build-utils → utils/build}/iconExtractor.mjs +7 -3
- package/src/utils/build/imageDownloader.mjs +159 -0
- package/src/{core/build-utils → utils/build}/imageProcessor.mjs +5 -6
- package/src/utils/helpers.mjs +153 -0
- package/src/utils/logger.mjs +53 -0
- package/src/utils/packageManager.mjs +88 -0
- package/src/components/Preview/index.js +0 -3
- package/src/components/SocialLinks/index.js +0 -130
- package/src/config/iconMappings.js +0 -329
- package/src/config/metaTags.js +0 -240
- package/src/config/prism.js +0 -179
- package/src/config/sidebar.js +0 -20
- package/src/core/build-utils/imageDownloader.mjs +0 -98
- package/src/core/createDocuConf.mjs +0 -490
- package/src/core/defaults.mjs +0 -67
- package/src/core/logger.mjs +0 -17
- package/src/core/packageManager.mjs +0 -72
- package/src/css/catppuccin.css +0 -632
- package/src/pages/notes.js +0 -87
- /package/src/template/notes/{welcome.md → welcome.mdx} +0 -0
- /package/src/{components → theme/components}/NoteIndex/styles.module.css +0 -0
- /package/src/{components → theme/components}/Preview/components/FeedbackStates.js +0 -0
- /package/src/{components → theme/components}/Preview/components/FileTabs.js +0 -0
- /package/src/{components → theme/components}/Preview/components/Triggers/index.js +0 -0
- /package/src/{components → theme/components}/Preview/components/ViewerWindow.js +0 -0
- /package/src/{components → theme/components}/Preview/hooks/useDeepLinkHash.js +0 -0
- /package/src/{components → theme/components}/Preview/hooks/useDockLayout.js +0 -0
- /package/src/{components → theme/components}/Preview/hooks/useFileFetch.js +0 -0
- /package/src/{components → theme/components}/Preview/renderers/CodeRenderer.js +0 -0
- /package/src/{components → theme/components}/Preview/renderers/ImageRenderer.js +0 -0
- /package/src/{components → theme/components}/Preview/renderers/PdfRenderer.js +0 -0
- /package/src/{components → theme/components}/Preview/renderers/WebRenderer.js +0 -0
- /package/src/{components → theme/components}/Preview/state/index.js +0 -0
- /package/src/{components → theme/components}/Preview/styles.module.css +0 -0
- /package/src/{components → theme/components}/Preview/utils/index.js +0 -0
- /package/src/{components → theme/components}/Tooltip/styles.module.css +0 -0
package/bin/portosaurus.mjs
CHANGED
|
@@ -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 {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
14
|
+
const PortoRoot = path.resolve(__dirname, "..");
|
|
18
15
|
|
|
19
16
|
const packageJson = JSON.parse(
|
|
20
|
-
fs.readFileSync(path.resolve(
|
|
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
|
-
// ───
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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/
|
|
11
|
-
"src/
|
|
15
|
+
"src/assets/",
|
|
16
|
+
"src/cli/",
|
|
12
17
|
"src/core/",
|
|
13
|
-
"src/css/",
|
|
14
|
-
"src/pages/",
|
|
15
18
|
"src/theme/",
|
|
16
|
-
"src/
|
|
17
|
-
"src/
|
|
19
|
+
"src/utils/",
|
|
20
|
+
"src/template/"
|
|
18
21
|
],
|
|
19
22
|
"scripts": {
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
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
|
+
}
|
package/src/cli/dev.mjs
ADDED
|
@@ -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
|
+
}
|
package/src/cli/init.mjs
ADDED
|
@@ -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
|
+
}
|