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
@@ -8,23 +8,22 @@
8
8
  This Page is completely Vibe coded. No code except small tweaks is written by me.
9
9
  */
10
10
 
11
-
12
- import { useState } from 'react';
13
- import Layout from '@theme/Layout';
14
- import Head from '@docusaurus/Head';
11
+ import { useState } from "react";
12
+ import Layout from "@theme/Layout";
13
+ import Head from "@docusaurus/Head";
15
14
  import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
16
- import '../css/tasks.css';
17
- import {
18
- FaClipboardList,
19
- FaSyncAlt,
20
- FaClock,
15
+ import "../css/tasks.css";
16
+ import {
17
+ FaClipboardList,
18
+ FaSyncAlt,
19
+ FaClock,
21
20
  FaCheckCircle,
22
21
  FaFire,
23
22
  FaThermometerHalf,
24
23
  FaSnowflake,
25
24
  FaTasks,
26
- FaExclamationTriangle
27
- } from 'react-icons/fa';
25
+ FaExclamationTriangle,
26
+ } from "react-icons/fa";
28
27
 
29
28
  function TaskList({ filterStatus, taskList }) {
30
29
  if (!taskList || !Array.isArray(taskList)) {
@@ -35,9 +34,9 @@ function TaskList({ filterStatus, taskList }) {
35
34
  </div>
36
35
  );
37
36
  }
38
-
39
- const filteredTasks = taskList.filter(task =>
40
- filterStatus ? task.status === filterStatus : true
37
+
38
+ const filteredTasks = taskList.filter((task) =>
39
+ filterStatus ? task.status === filterStatus : true,
41
40
  );
42
41
 
43
42
  if (filteredTasks.length === 0) {
@@ -53,14 +52,14 @@ function TaskList({ filterStatus, taskList }) {
53
52
  const sortedTasks = [...filteredTasks].sort((a, b) => {
54
53
  const statusOrder = { active: 1, pending: 2, completed: 3 };
55
54
  const statusDiff = statusOrder[a.status] - statusOrder[b.status];
56
-
55
+
57
56
  if (statusDiff !== 0) return statusDiff;
58
-
57
+
59
58
  // Priority order: high, medium, low
60
59
  const priorityOrder = { high: 1, medium: 2, low: 3 };
61
60
  return priorityOrder[a.priority] - priorityOrder[b.priority];
62
61
  });
63
-
62
+
64
63
  return (
65
64
  <div className="task-list-container">
66
65
  <div className="task-list-table">
@@ -72,15 +71,27 @@ function TaskList({ filterStatus, taskList }) {
72
71
 
73
72
  <div className="task-rows">
74
73
  {sortedTasks.map((task, index) => (
75
- <div
76
- key={index}
77
- className={`task-row ${task.status === 'completed' ? 'task-row-completed' : ''} ${index % 2 === 1 ? 'task-row-striped' : ''}`}
74
+ <div
75
+ key={index}
76
+ className={`task-row ${task.status === "completed" ? "task-row-completed" : ""} ${index % 2 === 1 ? "task-row-striped" : ""}`}
78
77
  >
79
78
  <div className="task-cell task-cell-status">
80
79
  <span className={`badge badge-status-${task.status}`}>
81
- {task.status === 'completed' && <><FaCheckCircle className="badge-icon" /> Done</>}
82
- {task.status === 'active' && <><FaSyncAlt className="badge-icon spin" /> In Progress</>}
83
- {task.status === 'pending' && <><FaClock className="badge-icon" /> Planned</>}
80
+ {task.status === "completed" && (
81
+ <>
82
+ <FaCheckCircle className="badge-icon" /> Done
83
+ </>
84
+ )}
85
+ {task.status === "active" && (
86
+ <>
87
+ <FaSyncAlt className="badge-icon spin" /> In Progress
88
+ </>
89
+ )}
90
+ {task.status === "pending" && (
91
+ <>
92
+ <FaClock className="badge-icon" /> Planned
93
+ </>
94
+ )}
84
95
  </span>
85
96
  </div>
86
97
 
@@ -93,9 +104,21 @@ function TaskList({ filterStatus, taskList }) {
93
104
 
94
105
  <div className="task-cell task-cell-priority">
95
106
  <span className={`badge badge-priority-${task.priority}`}>
96
- {task.priority === 'high' && <><FaFire className="badge-icon" /> High</>}
97
- {task.priority === 'medium' && <><FaThermometerHalf className="badge-icon" /> Medium</>}
98
- {task.priority === 'low' && <><FaSnowflake className="badge-icon" /> Low</>}
107
+ {task.priority === "high" && (
108
+ <>
109
+ <FaFire className="badge-icon" /> High
110
+ </>
111
+ )}
112
+ {task.priority === "medium" && (
113
+ <>
114
+ <FaThermometerHalf className="badge-icon" /> Medium
115
+ </>
116
+ )}
117
+ {task.priority === "low" && (
118
+ <>
119
+ <FaSnowflake className="badge-icon" /> Low
120
+ </>
121
+ )}
99
122
  </span>
100
123
  </div>
101
124
  </div>
@@ -106,16 +129,17 @@ function TaskList({ filterStatus, taskList }) {
106
129
  );
107
130
  }
108
131
 
109
-
110
132
  function TaskStats({ taskList }) {
111
133
  if (!taskList || !Array.isArray(taskList)) {
112
134
  return null;
113
135
  }
114
-
136
+
115
137
  const total = taskList.length;
116
- const completed = taskList.filter(task => task.status === 'completed').length;
117
- const active = taskList.filter(task => task.status === 'active').length;
118
- const pending = taskList.filter(task => task.status === 'pending').length;
138
+ const completed = taskList.filter(
139
+ (task) => task.status === "completed",
140
+ ).length;
141
+ const active = taskList.filter((task) => task.status === "active").length;
142
+ const pending = taskList.filter((task) => task.status === "pending").length;
119
143
  const percentComplete = total > 0 ? Math.round((completed / total) * 100) : 0;
120
144
 
121
145
  return (
@@ -140,7 +164,10 @@ function TaskStats({ taskList }) {
140
164
  <div className="stat-label">Progress</div>
141
165
  <div className="stat-value">{percentComplete}%</div>
142
166
  <div className="progress-bar-container">
143
- <div className="progress-bar" style={{width: `${percentComplete}%`}}></div>
167
+ <div
168
+ className="progress-bar"
169
+ style={{ width: `${percentComplete}%` }}
170
+ ></div>
144
171
  </div>
145
172
  </div>
146
173
  </div>
@@ -148,55 +175,82 @@ function TaskStats({ taskList }) {
148
175
  }
149
176
 
150
177
  function TaskTabs({ taskList }) {
151
- const [activeTab, setActiveTab] = useState('all');
152
-
178
+ const [activeTab, setActiveTab] = useState("all");
179
+
153
180
  if (!taskList || !Array.isArray(taskList)) {
154
181
  return null;
155
182
  }
156
-
183
+
157
184
  const tabData = [
158
- { id: 'all', label: 'All Tasks', icon: <FaClipboardList />, count: taskList.length },
159
- { id: 'active', label: 'In Progress', icon: <FaSyncAlt className="spin" />, count: taskList.filter(t => t.status === 'active').length },
160
- { id: 'pending', label: 'Planned', icon: <FaClock />, count: taskList.filter(t => t.status === 'pending').length },
161
- { id: 'completed', label: 'Completed', icon: <FaCheckCircle />, count: taskList.filter(t => t.status === 'completed').length },
185
+ {
186
+ id: "all",
187
+ label: "All Tasks",
188
+ icon: <FaClipboardList />,
189
+ count: taskList.length,
190
+ },
191
+ {
192
+ id: "active",
193
+ label: "In Progress",
194
+ icon: <FaSyncAlt className="spin" />,
195
+ count: taskList.filter((t) => t.status === "active").length,
196
+ },
197
+ {
198
+ id: "pending",
199
+ label: "Planned",
200
+ icon: <FaClock />,
201
+ count: taskList.filter((t) => t.status === "pending").length,
202
+ },
203
+ {
204
+ id: "completed",
205
+ label: "Completed",
206
+ icon: <FaCheckCircle />,
207
+ count: taskList.filter((t) => t.status === "completed").length,
208
+ },
162
209
  ];
163
-
210
+
164
211
  return (
165
212
  <div className="task-tabs-container">
166
213
  <div className="task-tabs" role="tablist" aria-label="Task categories">
167
- {tabData.map(tab => (
168
- <button
214
+ {tabData.map((tab) => (
215
+ <button
169
216
  key={tab.id}
170
- className={`task-tab ${activeTab === tab.id ? 'task-tab-active' : ''}`}
217
+ className={`task-tab ${activeTab === tab.id ? "task-tab-active" : ""}`}
171
218
  onClick={() => setActiveTab(tab.id)}
172
219
  role="tab"
173
220
  aria-selected={activeTab === tab.id}
174
221
  aria-controls={`tab-content-${tab.id}`}
175
222
  id={`tab-${tab.id}`}
176
223
  >
177
- <span className="task-tab-icon" aria-hidden="true">{tab.icon}</span>
224
+ <span className="task-tab-icon" aria-hidden="true">
225
+ {tab.icon}
226
+ </span>
178
227
  <span className="task-tab-label">{tab.label}</span>
179
228
  <span className="task-tab-count">{tab.count}</span>
180
229
  </button>
181
230
  ))}
182
231
  </div>
183
-
184
- <div
185
- className="task-tab-content"
186
- role="tabpanel"
232
+
233
+ <div
234
+ className="task-tab-content"
235
+ role="tabpanel"
187
236
  id={`tab-content-${activeTab}`}
188
237
  aria-labelledby={`tab-${activeTab}`}
189
238
  >
190
- {activeTab === 'all' && <TaskList taskList={taskList} />}
191
- {activeTab === 'active' && <TaskList taskList={taskList} filterStatus="active" />}
192
- {activeTab === 'pending' && <TaskList taskList={taskList} filterStatus="pending" />}
193
- {activeTab === 'completed' && <TaskList taskList={taskList} filterStatus="completed" />}
239
+ {activeTab === "all" && <TaskList taskList={taskList} />}
240
+ {activeTab === "active" && (
241
+ <TaskList taskList={taskList} filterStatus="active" />
242
+ )}
243
+ {activeTab === "pending" && (
244
+ <TaskList taskList={taskList} filterStatus="pending" />
245
+ )}
246
+ {activeTab === "completed" && (
247
+ <TaskList taskList={taskList} filterStatus="completed" />
248
+ )}
194
249
  </div>
195
250
  </div>
196
251
  );
197
252
  }
198
253
 
199
-
200
254
  export default function TasksPage() {
201
255
  const { siteConfig } = useDocusaurusContext();
202
256
  const { customFields } = siteConfig || {};
@@ -204,12 +258,16 @@ export default function TasksPage() {
204
258
  const tasksPage = customFields?.tasksPage;
205
259
  const title = tasksPage.title;
206
260
  const description = tasksPage.description;
207
- const taskList = tasksPage.enable && tasksPage.taskList ? tasksPage.taskList : [];
261
+ const taskList =
262
+ tasksPage.enable && tasksPage.taskList ? tasksPage.taskList : [];
208
263
 
209
264
  // If tasks are disabled, show a notice box instead
210
265
  if (!tasksPage || !tasksPage.enable) {
211
266
  return (
212
- <Layout title="Tasks are Disabled" description="Tasks are currently disabled">
267
+ <Layout
268
+ title="Tasks are Disabled"
269
+ description="Tasks are currently disabled"
270
+ >
213
271
  <div className="tasks-container">
214
272
  <div className="tasks-content">
215
273
  <div className="tasks-disabled-notice">
@@ -218,7 +276,8 @@ export default function TasksPage() {
218
276
  </div>
219
277
  <h2 className="disabled-title">Tasks are currently disabled</h2>
220
278
  <p className="disabled-help">
221
- To enable tasks, set <code>tasks_page.enable</code> to <code>true</code>
279
+ To enable tasks, set <code>tasks_page.enable</code> to{" "}
280
+ <code>true</code>
222
281
  </p>
223
282
  </div>
224
283
  </div>
@@ -1,11 +1,11 @@
1
- import { useEffect, useRef } from 'react';
1
+ import { useEffect, useRef } from "react";
2
2
 
3
3
  // AI Generated (partially)
4
4
 
5
5
  /**
6
6
  * <HashNavigation/> Component to handle hash-based navigation with visual effects
7
7
  * Should be added at the bottom of the page
8
- *
8
+ *
9
9
  * @param {Object} props Component props
10
10
  * @param {string} props.elementPrefix Prefix for element IDs (default: 'card-')
11
11
  * @param {string} props.elementSelector Selector for all elements in the group (default: '.content-card')
@@ -21,42 +21,41 @@ import { useEffect, useRef } from 'react';
21
21
  * @param {string} props.styles.blurAmount Blur amount for non-highlighted elements (default: '4px')
22
22
  * @param {string} props.styles.blurOpacity Opacity for blurred elements (default: '0.3')
23
23
  */
24
- export default function HashNavigation({
25
- elementPrefix = 'card-',
26
- elementSelector = '.content-card',
27
- containerSelector = '.container',
24
+ export default function HashNavigation({
25
+ elementPrefix = "card-",
26
+ elementSelector = ".content-card",
27
+ containerSelector = ".container",
28
28
  effectDuration = 6000,
29
29
  scrollDelay = 300,
30
- scrollOptions = { behavior: 'smooth', block: 'center' },
30
+ scrollOptions = { behavior: "smooth", block: "center" },
31
31
  enabled = true,
32
- styles = {}
32
+ styles = {},
33
33
  }) {
34
- const styleId = 'hash-navigation-styles';
35
- const highlightClass = 'hash-nav-highlight';
36
- const blurClass = 'hash-nav-blur';
37
- const containerActiveClass = 'hash-nav-active';
38
-
34
+ const styleId = "hash-navigation-styles";
35
+ const highlightClass = "hash-nav-highlight";
36
+ const blurClass = "hash-nav-blur";
37
+ const containerActiveClass = "hash-nav-active";
38
+
39
39
  // Default styles
40
40
  const {
41
- overlayColor = 'rgba(var(--ifm-color-emphasis-200-rgb), 0.5)',
42
- highlightShadow = '0 0 30px 10px var(--ifm-color-primary)',
43
- highlightScale = '1.05',
44
- blurAmount = '4px',
45
- blurOpacity = '0.3'
41
+ overlayColor = "rgba(var(--ifm-color-emphasis-200-rgb), 0.5)",
42
+ highlightShadow = "0 0 30px 10px var(--ifm-color-primary)",
43
+ highlightScale = "1.05",
44
+ blurAmount = "4px",
45
+ blurOpacity = "0.3",
46
46
  } = styles;
47
-
47
+
48
48
  // Reference to track if styles have been injected
49
49
  const stylesInjected = useRef(false);
50
-
50
+
51
51
  // Inject the component styles
52
52
  useEffect(() => {
53
-
54
53
  // Don't inject styles if already present
55
54
  if (document.getElementById(styleId) || stylesInjected.current) {
56
55
  return;
57
56
  }
58
-
59
- const styleElement = document.createElement('style');
57
+
58
+ const styleElement = document.createElement("style");
60
59
 
61
60
  styleElement.id = styleId;
62
61
 
@@ -122,10 +121,10 @@ export default function HashNavigation({
122
121
  }
123
122
  }
124
123
  `;
125
-
124
+
126
125
  document.head.appendChild(styleElement);
127
126
  stylesInjected.current = true;
128
-
127
+
129
128
  // Clean up on unmount
130
129
  return () => {
131
130
  const existingStyle = document.getElementById(styleId);
@@ -134,8 +133,14 @@ export default function HashNavigation({
134
133
  }
135
134
  stylesInjected.current = false;
136
135
  };
137
- }, [containerSelector, overlayColor, highlightShadow, highlightScale, blurAmount, blurOpacity]);
138
-
136
+ }, [
137
+ containerSelector,
138
+ overlayColor,
139
+ highlightShadow,
140
+ highlightScale,
141
+ blurAmount,
142
+ blurOpacity,
143
+ ]);
139
144
 
140
145
  // Main hash navigation logic
141
146
  useEffect(() => {
@@ -143,16 +148,16 @@ export default function HashNavigation({
143
148
 
144
149
  if (window.location.hash) {
145
150
  const hashValue = window.location.hash.substring(1);
146
- const targetElement = document.getElementById(`${elementPrefix}${hashValue}`);
151
+ const targetElement = document.getElementById(
152
+ `${elementPrefix}${hashValue}`,
153
+ );
147
154
 
148
155
  if (targetElement) {
149
-
150
156
  // Wait a moment for the page to fully render
151
157
  setTimeout(() => {
152
-
153
158
  // Scroll to the element
154
159
  targetElement.scrollIntoView(scrollOptions);
155
-
160
+
156
161
  // Get the container to add the overlay effect
157
162
  const container = document.querySelector(containerSelector);
158
163
  if (container) {
@@ -166,15 +171,15 @@ export default function HashNavigation({
166
171
  targetElement.classList.add(highlightClass);
167
172
 
168
173
  // Add blur to all other elements
169
- allElements.forEach(element => {
174
+ allElements.forEach((element) => {
170
175
  if (element !== targetElement) {
171
176
  element.classList.add(blurClass);
172
177
  }
173
178
  });
174
179
 
175
180
  // Create clickable overlay for dismissing effects
176
- const overlay = document.createElement('div');
177
- overlay.className = 'hash-nav-overlay';
181
+ const overlay = document.createElement("div");
182
+ overlay.className = "hash-nav-overlay";
178
183
 
179
184
  document.body.appendChild(overlay);
180
185
 
@@ -182,50 +187,48 @@ export default function HashNavigation({
182
187
 
183
188
  // remove effects
184
189
  const removeEffects = () => {
185
-
186
190
  if (effectTimeoutId) {
187
191
  clearTimeout(effectTimeoutId);
188
192
  effectTimeoutId = null;
189
193
  }
190
194
 
191
195
  // Remove effects
192
- allElements.forEach(element => {
196
+ allElements.forEach((element) => {
193
197
  element.classList.remove(blurClass);
194
198
  });
195
199
 
196
200
  targetElement.classList.remove(highlightClass);
197
-
201
+
198
202
  // Remove the container overlay
199
203
  if (container) {
200
204
  container.classList.remove(containerActiveClass);
201
205
  }
202
-
206
+
203
207
  // Remove clickable overlay
204
208
  if (overlay && overlay.parentNode) {
205
209
  overlay.parentNode.removeChild(overlay);
206
210
  }
207
211
 
208
212
  // Remove event listeners after effects are cleared
209
- overlay.removeEventListener('click', removeEffects);
210
- overlay.removeEventListener('touchstart', removeEffects);
211
- document.removeEventListener('keydown', handleKeyDown);
213
+ overlay.removeEventListener("click", removeEffects);
214
+ overlay.removeEventListener("touchstart", removeEffects);
215
+ document.removeEventListener("keydown", handleKeyDown);
212
216
  };
213
-
217
+
214
218
  // Add keyboard escape handler
215
219
  const handleKeyDown = (e) => {
216
- if (e.key === 'Escape') {
220
+ if (e.key === "Escape") {
217
221
  removeEffects();
218
222
  }
219
223
  };
220
224
 
221
225
  // Add event listeners to dismiss effects
222
- overlay.addEventListener('click', removeEffects);
223
- overlay.addEventListener('touchstart', removeEffects);
224
- document.addEventListener('keydown', handleKeyDown);
226
+ overlay.addEventListener("click", removeEffects);
227
+ overlay.addEventListener("touchstart", removeEffects);
228
+ document.addEventListener("keydown", handleKeyDown);
225
229
 
226
230
  // Set timeout to automatically remove effects after duration
227
231
  effectTimeoutId = setTimeout(removeEffects, effectDuration);
228
-
229
232
  }, scrollDelay);
230
233
  }
231
234
  }
@@ -233,7 +236,7 @@ export default function HashNavigation({
233
236
  // Cleanup
234
237
  return () => {
235
238
  const container = document.querySelector(containerSelector);
236
- const overlay = document.querySelector('.hash-nav-overlay');
239
+ const overlay = document.querySelector(".hash-nav-overlay");
237
240
 
238
241
  if (container) {
239
242
  container.classList.remove(containerActiveClass);
@@ -244,7 +247,15 @@ export default function HashNavigation({
244
247
  overlay.parentNode.removeChild(overlay);
245
248
  }
246
249
  };
247
- }, [enabled, elementPrefix, elementSelector, containerSelector, effectDuration, scrollDelay, scrollOptions]);
250
+ }, [
251
+ enabled,
252
+ elementPrefix,
253
+ elementSelector,
254
+ containerSelector,
255
+ effectDuration,
256
+ scrollDelay,
257
+ scrollOptions,
258
+ ]);
248
259
 
249
260
  return null;
250
261
  }
@@ -1,6 +1,6 @@
1
- import { useEffect, useState } from 'react';
2
- import { useLocation } from '@docusaurus/router';
3
- import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
1
+ import { useEffect, useState } from "react";
2
+ import { useLocation } from "@docusaurus/router";
3
+ import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
4
4
 
5
5
  // AI Generated
6
6
 
@@ -13,11 +13,10 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
13
13
  * @returns {null} This component doesn't render anything visible
14
14
  */
15
15
 
16
-
17
- export default function UpdateTitle({
18
- sections = {},
16
+ export default function UpdateTitle({
17
+ sections = {},
19
18
  defaultTitle = null,
20
- enabled = true
19
+ enabled = true,
21
20
  }) {
22
21
  const location = useLocation();
23
22
  const { siteConfig } = useDocusaurusContext();
@@ -27,44 +26,41 @@ export default function UpdateTitle({
27
26
  const effectiveDefaultTitle = defaultTitle || siteConfig.title;
28
27
 
29
28
  useEffect(() => {
30
-
31
29
  // Only run if enabled
32
30
  if (!enabled) return;
33
31
 
34
32
  // Use provided sections or default to empty object
35
- const sectionTitles = Object.keys(sections).length > 0
36
- ? sections
37
- : {};
33
+ const sectionTitles = Object.keys(sections).length > 0 ? sections : {};
38
34
 
39
35
  const updateTitle = () => {
40
36
  // Get all sections we want to track
41
37
  const sectionsToTrack = Object.keys(sectionTitles)
42
- .map(id => document.getElementById(id))
38
+ .map((id) => document.getElementById(id))
43
39
  .filter(Boolean);
44
-
40
+
45
41
  if (sectionsToTrack.length === 0) {
46
42
  // No sections found, use default title
47
43
  setCurrentTitle(effectiveDefaultTitle);
48
44
  return;
49
45
  }
50
-
46
+
51
47
  // Calculate which section is most visible
52
48
  const viewportHeight = window.innerHeight;
53
49
  let maxVisibleSection = null;
54
50
  let maxVisibleArea = 0;
55
-
56
- sectionsToTrack.forEach(section => {
51
+
52
+ sectionsToTrack.forEach((section) => {
57
53
  const rect = section.getBoundingClientRect();
58
54
  const visibleTop = Math.max(0, rect.top);
59
55
  const visibleBottom = Math.min(viewportHeight, rect.bottom);
60
56
  const visibleArea = Math.max(0, visibleBottom - visibleTop);
61
-
57
+
62
58
  if (visibleArea > maxVisibleArea) {
63
59
  maxVisibleArea = visibleArea;
64
60
  maxVisibleSection = section.id;
65
61
  }
66
62
  });
67
-
63
+
68
64
  // Update title state based on visible section
69
65
  if (maxVisibleSection && sectionTitles[maxVisibleSection]) {
70
66
  setCurrentTitle(sectionTitles[maxVisibleSection]);
@@ -72,7 +68,7 @@ export default function UpdateTitle({
72
68
  setCurrentTitle(effectiveDefaultTitle);
73
69
  }
74
70
  };
75
-
71
+
76
72
  // Add scroll event listener with throttling
77
73
  let isScrolling = false;
78
74
  const handleScroll = () => {
@@ -84,15 +80,15 @@ export default function UpdateTitle({
84
80
  isScrolling = true;
85
81
  }
86
82
  };
87
-
88
- window.addEventListener('scroll', handleScroll);
89
-
83
+
84
+ window.addEventListener("scroll", handleScroll);
85
+
90
86
  // Initial call
91
87
  updateTitle();
92
-
88
+
93
89
  // Clean up
94
90
  return () => {
95
- window.removeEventListener('scroll', handleScroll);
91
+ window.removeEventListener("scroll", handleScroll);
96
92
  };
97
93
  }, [location.pathname, sections, effectiveDefaultTitle, enabled]);
98
94
 
@@ -104,4 +100,4 @@ export default function UpdateTitle({
104
100
 
105
101
  // Component doesn't render anything visible
106
102
  return null;
107
- }
103
+ }
@@ -15,10 +15,12 @@ export function getCssVar(name) {
15
15
  const cssContent = fs.readFileSync(cssPath, "utf8");
16
16
 
17
17
  if (name === "--ifm-color-primary") {
18
- const match = cssContent.match(/--ifm-color-primary:\s*(#[a-fA-F0-9]{3,6})/);
18
+ const match = cssContent.match(
19
+ /--ifm-color-primary:\s*(#[a-fA-F0-9]{3,6})/,
20
+ );
19
21
  return match ? match[1] : "#2e8555";
20
22
  }
21
-
23
+
22
24
  if (name === "--ifm-background-color") {
23
25
  return "#ffffff";
24
26
  }
@@ -27,4 +29,4 @@ export function getCssVar(name) {
27
29
  } catch {
28
30
  return "#2e8555"; // Safe default
29
31
  }
30
- }
32
+ }