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.
Files changed (60) hide show
  1. package/README.md +26 -126
  2. package/bin/portosaurus.mjs +8 -0
  3. package/package.json +6 -3
  4. package/src/assets/img/icon.png +0 -0
  5. package/src/assets/img/{icon.svg → svg/icon.svg} +35 -37
  6. package/src/assets/img/svg/project-blank.svg +140 -0
  7. package/src/assets/sample-resume.pdf +0 -0
  8. package/src/cli/build.mjs +2 -5
  9. package/src/cli/dev.mjs +27 -5
  10. package/src/cli/init.mjs +6 -12
  11. package/src/cli/schema.mjs +211 -0
  12. package/src/core/buildDocuConfig.mjs +306 -189
  13. package/src/core/constants.mjs +7 -1
  14. package/src/template/config.yml +150 -0
  15. package/src/template/notes/welcome.mdx +6 -0
  16. package/src/template/package.json +3 -3
  17. package/src/theme/MDXComponents.js +0 -1
  18. package/src/theme/components/AboutSection/index.js +39 -17
  19. package/src/theme/components/AboutSection/styles.module.css +151 -344
  20. package/src/theme/components/ContactSection/index.js +29 -14
  21. package/src/theme/components/ContactSection/styles.module.css +19 -8
  22. package/src/theme/components/ExperienceSection/index.js +19 -5
  23. package/src/theme/components/HeroSection/index.js +11 -4
  24. package/src/theme/components/HeroSection/styles.module.css +17 -16
  25. package/src/theme/components/NavArrow/index.js +114 -0
  26. package/src/theme/components/NavArrow/styles.module.css +107 -0
  27. package/src/theme/components/NoteIndex/index.js +66 -95
  28. package/src/theme/components/NoteIndex/styles.module.css +85 -89
  29. package/src/theme/components/Preview/components/FeedbackStates.js +3 -1
  30. package/src/theme/components/Preview/components/PreviewContent.js +91 -0
  31. package/src/theme/components/Preview/components/PreviewHeader.js +41 -33
  32. package/src/theme/components/Preview/components/Triggers/Pv.js +129 -72
  33. package/src/theme/components/Preview/components/ViewerWindow.js +198 -234
  34. package/src/theme/components/Preview/hooks/useAdaptiveSizing.js +115 -0
  35. package/src/theme/components/Preview/hooks/useDeepLinkHash.js +18 -23
  36. package/src/theme/components/Preview/hooks/useDockLayout.js +48 -8
  37. package/src/theme/components/Preview/hooks/useTouchZoom.js +118 -0
  38. package/src/theme/components/Preview/renderers/CodeRenderer.js +64 -25
  39. package/src/theme/components/Preview/state/index.js +70 -17
  40. package/src/theme/components/Preview/styles.module.css +181 -45
  41. package/src/theme/components/Preview/utils/index.js +11 -10
  42. package/src/theme/components/ProjectsSection/index.js +145 -148
  43. package/src/theme/components/ProjectsSection/styles.module.css +178 -112
  44. package/src/theme/components/SocialLinks/index.js +9 -7
  45. package/src/theme/components/Tooltip/index.js +31 -20
  46. package/src/theme/components/Tooltip/styles.module.css +101 -38
  47. package/src/theme/config/iconMappings.js +2 -0
  48. package/src/theme/css/custom.css +72 -0
  49. package/src/theme/hooks/useScrollReveal.js +30 -0
  50. package/src/theme/pages/index.js +7 -27
  51. package/src/theme/pages/notes.js +2 -2
  52. package/src/theme/pages/tasks.js +12 -11
  53. package/src/utils/cliUtils.mjs +23 -51
  54. package/src/utils/configUtils.mjs +95 -84
  55. package/src/utils/systemUtils.mjs +171 -0
  56. package/src/template/config.js +0 -68
  57. package/src/theme/components/ScrollToTop/index.js +0 -95
  58. package/src/theme/components/ScrollToTop/styles.module.css +0 -97
  59. package/src/theme/config/metaTags.js +0 -21
  60. /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 { PortoRoot } from "../core/constants.mjs";
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
- 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}`);
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/cliUtils.mjs";
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: packageJson.version,
18
- portoHome: packageJson.homepage,
19
- portoRepo: packageJson.repository.url,
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
+ }