portosaurus 3.0.2 → 4.0.1
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/README.md +26 -126
- package/bin/portosaurus.mjs +8 -0
- package/package.json +6 -3
- package/src/assets/img/icon.png +0 -0
- package/src/assets/img/{icon.svg → svg/icon.svg} +35 -37
- package/src/assets/img/svg/project-blank.svg +140 -0
- package/src/assets/sample-resume.pdf +0 -0
- package/src/cli/build.mjs +2 -5
- package/src/cli/dev.mjs +27 -5
- package/src/cli/init.mjs +6 -12
- package/src/cli/schema.mjs +211 -0
- package/src/core/buildDocuConfig.mjs +306 -189
- package/src/core/constants.mjs +7 -1
- package/src/template/config.yml +150 -0
- package/src/template/notes/welcome.mdx +6 -0
- package/src/template/package.json +3 -3
- package/src/theme/MDXComponents.js +0 -1
- package/src/theme/components/AboutSection/index.js +39 -17
- package/src/theme/components/AboutSection/styles.module.css +151 -344
- package/src/theme/components/ContactSection/index.js +29 -14
- package/src/theme/components/ContactSection/styles.module.css +19 -8
- package/src/theme/components/ExperienceSection/index.js +19 -5
- package/src/theme/components/HeroSection/index.js +11 -4
- package/src/theme/components/HeroSection/styles.module.css +17 -16
- package/src/theme/components/NavArrow/index.js +114 -0
- package/src/theme/components/NavArrow/styles.module.css +107 -0
- package/src/theme/components/NoteIndex/index.js +66 -95
- package/src/theme/components/NoteIndex/styles.module.css +85 -89
- package/src/theme/components/Preview/components/FeedbackStates.js +3 -1
- package/src/theme/components/Preview/components/PreviewContent.js +91 -0
- package/src/theme/components/Preview/components/PreviewHeader.js +41 -33
- package/src/theme/components/Preview/components/Triggers/Pv.js +129 -72
- package/src/theme/components/Preview/components/ViewerWindow.js +198 -234
- package/src/theme/components/Preview/hooks/useAdaptiveSizing.js +115 -0
- package/src/theme/components/Preview/hooks/useDeepLinkHash.js +18 -23
- package/src/theme/components/Preview/hooks/useDockLayout.js +48 -8
- package/src/theme/components/Preview/hooks/useTouchZoom.js +118 -0
- package/src/theme/components/Preview/renderers/CodeRenderer.js +64 -25
- package/src/theme/components/Preview/state/index.js +70 -17
- package/src/theme/components/Preview/styles.module.css +181 -45
- package/src/theme/components/Preview/utils/index.js +11 -10
- package/src/theme/components/ProjectsSection/index.js +145 -148
- package/src/theme/components/ProjectsSection/styles.module.css +178 -112
- package/src/theme/components/SocialLinks/index.js +9 -7
- package/src/theme/components/Tooltip/index.js +31 -20
- package/src/theme/components/Tooltip/styles.module.css +101 -38
- package/src/theme/config/iconMappings.js +2 -0
- package/src/theme/css/custom.css +72 -0
- package/src/theme/hooks/useScrollReveal.js +30 -0
- package/src/theme/pages/index.js +7 -27
- package/src/theme/pages/notes.js +2 -2
- package/src/theme/pages/tasks.js +12 -11
- package/src/utils/cliUtils.mjs +23 -51
- package/src/utils/configUtils.mjs +95 -84
- package/src/utils/systemUtils.mjs +171 -0
- package/src/template/config.js +0 -68
- package/src/theme/components/ScrollToTop/index.js +0 -95
- package/src/theme/components/ScrollToTop/styles.module.css +0 -97
- package/src/theme/config/metaTags.js +0 -21
- /package/src/template/{.nojekyll → static/.nojekyll} +0 -0
package/src/cli/dev.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
writePortoConfigShim,
|
|
8
8
|
runDocusaurus,
|
|
9
9
|
} from "../utils/cliUtils.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import { PortoPkg } from "../core/constants.mjs";
|
|
11
11
|
|
|
12
12
|
export async function devCommand(siteDir, extraArgs) {
|
|
13
13
|
const UserRoot = siteDir
|
|
@@ -16,13 +16,35 @@ export async function devCommand(siteDir, extraArgs) {
|
|
|
16
16
|
validateProject(UserRoot);
|
|
17
17
|
ensureContentDirs(UserRoot);
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
21
|
-
|
|
22
|
-
logger.box("Portosaurus Dev Server", `v${packageJson.version}`);
|
|
19
|
+
logger.box("Portosaurus Dev Server", `v${PortoPkg.version}`);
|
|
23
20
|
logger.info("Starting development server...");
|
|
24
21
|
try {
|
|
25
22
|
const configPath = writePortoConfigShim(UserRoot);
|
|
23
|
+
|
|
24
|
+
// Watch for config.yml changes to trigger Docusaurus reload
|
|
25
|
+
const configYaml = ["config.yaml", "config.yml"].find((f) =>
|
|
26
|
+
fs.existsSync(path.join(UserRoot, f)),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
if (configYaml) {
|
|
30
|
+
const configYamlPath = path.join(UserRoot, configYaml);
|
|
31
|
+
logger.debug(`Watching ${configYaml} for changes...`);
|
|
32
|
+
|
|
33
|
+
const watcher = fs.watch(configYamlPath, (eventType) => {
|
|
34
|
+
if (eventType === "change") {
|
|
35
|
+
logger.info(`Detected change in ${configYaml}, reloading...`);
|
|
36
|
+
// Touch the shim config to trigger Docusaurus reload
|
|
37
|
+
const now = new Date();
|
|
38
|
+
fs.utimesSync(configPath, now, now);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
process.on("SIGINT", () => {
|
|
43
|
+
watcher.close();
|
|
44
|
+
process.exit();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
26
48
|
await runDocusaurus("start", extraArgs || [], UserRoot, configPath);
|
|
27
49
|
} catch (error) {
|
|
28
50
|
logger.error(`Failed to start: ${error.message}`);
|
package/src/cli/init.mjs
CHANGED
|
@@ -2,21 +2,18 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { logger } from "../utils/logger.mjs";
|
|
4
4
|
import { getPackageManager } from "../utils/packageManager.mjs";
|
|
5
|
-
import { mirrorSync } from "../utils/
|
|
6
|
-
import { PortoRoot } from "../core/constants.mjs";
|
|
5
|
+
import { mirrorSync } from "../utils/systemUtils.mjs";
|
|
6
|
+
import { PortoRoot, PortoPkg } from "../core/constants.mjs";
|
|
7
7
|
|
|
8
8
|
export async function initCommand(projectName, options) {
|
|
9
9
|
const UsrProjDir = path.resolve(process.cwd(), projectName);
|
|
10
10
|
const templateDir = path.resolve(PortoRoot, "src/template");
|
|
11
|
-
const packageJson = JSON.parse(
|
|
12
|
-
fs.readFileSync(path.resolve(PortoRoot, "package.json"), "utf8"),
|
|
13
|
-
);
|
|
14
11
|
|
|
15
12
|
const TemplateVars = {
|
|
16
13
|
projectName: projectName,
|
|
17
|
-
portoVer:
|
|
18
|
-
portoHome:
|
|
19
|
-
portoRepo:
|
|
14
|
+
portoVer: PortoPkg.version,
|
|
15
|
+
portoHome: PortoPkg.homepage,
|
|
16
|
+
portoRepo: PortoPkg.repository?.url || "",
|
|
20
17
|
};
|
|
21
18
|
|
|
22
19
|
const ignoreList = [
|
|
@@ -38,10 +35,7 @@ export async function initCommand(projectName, options) {
|
|
|
38
35
|
process.exit(1);
|
|
39
36
|
}
|
|
40
37
|
|
|
41
|
-
logger.box(
|
|
42
|
-
"Initializing New Portosaurus Project",
|
|
43
|
-
` v${packageJson.version} `,
|
|
44
|
-
);
|
|
38
|
+
logger.box("Initializing New Portosaurus Project", ` v${PortoPkg.version} `);
|
|
45
39
|
|
|
46
40
|
logger.info(`Creating new project in ${projectName}...`);
|
|
47
41
|
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { logger } from "../utils/logger.mjs";
|
|
4
|
+
import { PortoRoot } from "../core/constants.mjs";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Portosaurus Discovery-Based Schema Generator
|
|
8
|
+
*
|
|
9
|
+
* This command "discovers" the configuration schema by running the actual
|
|
10
|
+
* buildDocuConfig logic with a Spy Proxy. Every key accessed by the framework
|
|
11
|
+
* is recorded and mapped to a JSON schema.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export async function schemaCommand(outPath, srcPath) {
|
|
15
|
+
const SOURCE_FILE = srcPath
|
|
16
|
+
? path.resolve(process.cwd(), srcPath)
|
|
17
|
+
: path.resolve(PortoRoot, "src/core/buildDocuConfig.mjs");
|
|
18
|
+
|
|
19
|
+
const OUTPUT_FILE = outPath
|
|
20
|
+
? path.resolve(process.cwd(), outPath)
|
|
21
|
+
: path.resolve(PortoRoot, "configSchema.json");
|
|
22
|
+
const discoveredSchema = {
|
|
23
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
24
|
+
title: "Portosaurus Project Configuration",
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: {},
|
|
27
|
+
required: [],
|
|
28
|
+
additionalProperties: true,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
logger.info("Initializing Schema Discovery Engine...");
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
logger.info(`Discovering keys from ${SOURCE_FILE}...`);
|
|
35
|
+
|
|
36
|
+
const sourceCode = fs.readFileSync(SOURCE_FILE, "utf8");
|
|
37
|
+
|
|
38
|
+
// State-Aware Balanced Parenthesis Walker
|
|
39
|
+
const getStartRegex = /get\(\s*["']([^"']+)["']\s*,\s*/g;
|
|
40
|
+
let match;
|
|
41
|
+
|
|
42
|
+
while ((match = getStartRegex.exec(sourceCode)) !== null) {
|
|
43
|
+
const keyPath = match[1];
|
|
44
|
+
const startIdx = match.index + match[0].length;
|
|
45
|
+
|
|
46
|
+
let braceCount = 1;
|
|
47
|
+
let currentIdx = startIdx;
|
|
48
|
+
let defaultValueRaw = "";
|
|
49
|
+
|
|
50
|
+
let inString = null; // ', ", or `
|
|
51
|
+
let inComment = null; // // or /*
|
|
52
|
+
let escaped = false;
|
|
53
|
+
|
|
54
|
+
while (braceCount > 0 && currentIdx < sourceCode.length) {
|
|
55
|
+
const char = sourceCode[currentIdx];
|
|
56
|
+
const nextChar = sourceCode[currentIdx + 1];
|
|
57
|
+
|
|
58
|
+
if (escaped) {
|
|
59
|
+
escaped = false;
|
|
60
|
+
} else if (char === "\\") {
|
|
61
|
+
escaped = true;
|
|
62
|
+
} else if (!inString && !inComment) {
|
|
63
|
+
if (char === "'" || char === '"' || char === "`") inString = char;
|
|
64
|
+
else if (char === "/" && nextChar === "/") inComment = "//";
|
|
65
|
+
else if (char === "/" && nextChar === "*") inComment = "/*";
|
|
66
|
+
else if (char === "(") braceCount++;
|
|
67
|
+
else if (char === ")") braceCount--;
|
|
68
|
+
} else if (inString) {
|
|
69
|
+
if (char === inString) inString = null;
|
|
70
|
+
} else if (inComment === "//") {
|
|
71
|
+
if (char === "\n") inComment = null;
|
|
72
|
+
} else if (inComment === "/*") {
|
|
73
|
+
if (char === "*" && nextChar === "/") {
|
|
74
|
+
inComment = null;
|
|
75
|
+
defaultValueRaw += "*/";
|
|
76
|
+
currentIdx += 2;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (braceCount > 0) {
|
|
82
|
+
defaultValueRaw += char;
|
|
83
|
+
}
|
|
84
|
+
currentIdx++;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Extraction of comments (Description)
|
|
88
|
+
let description = "";
|
|
89
|
+
const linesBefore = sourceCode.slice(0, match.index).split("\n");
|
|
90
|
+
let i = linesBefore.length - 1;
|
|
91
|
+
|
|
92
|
+
// Look for a comment on the line immediately preceding
|
|
93
|
+
// We look back up to 5 lines for a docstring or single comment
|
|
94
|
+
let foundComment = [];
|
|
95
|
+
let inDocBlock = false;
|
|
96
|
+
|
|
97
|
+
while (i >= 0 && foundComment.length < 15) {
|
|
98
|
+
let line = linesBefore[i].trim();
|
|
99
|
+
|
|
100
|
+
// Stop if we hit an empty line (unless we are inside a DocBlock)
|
|
101
|
+
if (!line && !inDocBlock) break;
|
|
102
|
+
|
|
103
|
+
if (line.endsWith("*/")) inDocBlock = true;
|
|
104
|
+
|
|
105
|
+
if (inDocBlock) {
|
|
106
|
+
const content = line.replace(/^\/\*\*?|\*\/|\*/g, "").trim();
|
|
107
|
+
if (content) foundComment.unshift(content);
|
|
108
|
+
if (line.startsWith("/*") || line.startsWith("/**"))
|
|
109
|
+
inDocBlock = false;
|
|
110
|
+
} else if (line.startsWith("//")) {
|
|
111
|
+
let content = line.replace(/^\/\/\s?/, "").trim();
|
|
112
|
+
if (!content.match(/^(TODO|FIXME|NOTE|SECTION|---)/i)) {
|
|
113
|
+
foundComment.unshift(content);
|
|
114
|
+
}
|
|
115
|
+
} else if (line && !line.startsWith("/") && !line.startsWith("*")) {
|
|
116
|
+
// WE HIT CODE! Stop immediately.
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
i--;
|
|
120
|
+
}
|
|
121
|
+
description = foundComment.join("\n").trim();
|
|
122
|
+
|
|
123
|
+
// Basic type inference and Default Value cleaning
|
|
124
|
+
let type = "string";
|
|
125
|
+
let defaultValue = undefined;
|
|
126
|
+
|
|
127
|
+
// Handle multi-argument get(key, fall1, fall2, finalDefault)
|
|
128
|
+
// We need to find the final argument as the default
|
|
129
|
+
let args = [];
|
|
130
|
+
let currentArg = "";
|
|
131
|
+
let depth = 0;
|
|
132
|
+
let argInString = null;
|
|
133
|
+
|
|
134
|
+
for (let i = 0; i < defaultValueRaw.length; i++) {
|
|
135
|
+
const c = defaultValueRaw[i];
|
|
136
|
+
if (!argInString) {
|
|
137
|
+
if (c === "'" || c === '"' || c === "`") argInString = c;
|
|
138
|
+
else if (c === "(" || c === "[" || c === "{") depth++;
|
|
139
|
+
else if (c === ")" || c === "]" || c === "}") depth--;
|
|
140
|
+
else if (c === "," && depth === 0) {
|
|
141
|
+
args.push(currentArg.trim());
|
|
142
|
+
currentArg = "";
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
} else if (c === argInString && defaultValueRaw[i - 1] !== "\\") {
|
|
146
|
+
argInString = null;
|
|
147
|
+
}
|
|
148
|
+
currentArg += c;
|
|
149
|
+
}
|
|
150
|
+
if (currentArg.trim()) args.push(currentArg.trim());
|
|
151
|
+
|
|
152
|
+
// We use the last argument as the primary default value for the schema
|
|
153
|
+
let val = (args[args.length - 1] || "").trim();
|
|
154
|
+
|
|
155
|
+
if (val === "true" || val === "false") {
|
|
156
|
+
type = "boolean";
|
|
157
|
+
defaultValue = val === "true";
|
|
158
|
+
} else if (!isNaN(val) && val !== "") {
|
|
159
|
+
type = "number";
|
|
160
|
+
defaultValue = Number(val);
|
|
161
|
+
} else if (
|
|
162
|
+
val.startsWith("[") ||
|
|
163
|
+
val.includes(".map(") ||
|
|
164
|
+
val.includes(".filter(") ||
|
|
165
|
+
val.includes(".slice(") ||
|
|
166
|
+
val.startsWith("require")
|
|
167
|
+
) {
|
|
168
|
+
type = "array";
|
|
169
|
+
} else if (val.startsWith("{")) {
|
|
170
|
+
type = "object";
|
|
171
|
+
} else if (val) {
|
|
172
|
+
// It's a string, remove surrounding quotes and unescape
|
|
173
|
+
defaultValue = val.replace(/^["'`](.*)["'`]$/s, "$1").trim();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const parts = keyPath.split(".");
|
|
177
|
+
let current = discoveredSchema.properties;
|
|
178
|
+
|
|
179
|
+
parts.forEach((part, index) => {
|
|
180
|
+
const isLast = index === parts.length - 1;
|
|
181
|
+
|
|
182
|
+
if (!current[part]) {
|
|
183
|
+
if (isLast) {
|
|
184
|
+
current[part] = { type };
|
|
185
|
+
if (description) current[part].description = description;
|
|
186
|
+
if (defaultValue !== undefined)
|
|
187
|
+
current[part].default = defaultValue;
|
|
188
|
+
} else {
|
|
189
|
+
current[part] = { type: "object", properties: {} };
|
|
190
|
+
}
|
|
191
|
+
} else if (!isLast && current[part].type !== "object") {
|
|
192
|
+
// Upgrade to object if it was previously a leaf node but now has children
|
|
193
|
+
current[part] = { type: "object", properties: {} };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!isLast) {
|
|
197
|
+
if (!current[part].properties) current[part].properties = {};
|
|
198
|
+
current = current[part].properties;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(discoveredSchema, null, 2));
|
|
204
|
+
logger.success(
|
|
205
|
+
`Successfully discovered and wrote schema to: ${OUTPUT_FILE}`,
|
|
206
|
+
);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
logger.error(`Discovery failed: ${error.message}`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
}
|