portosaurus 1.14.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 (57) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +116 -0
  3. package/bin/portosaurus.js +337 -0
  4. package/internal/notes/index.md +10 -0
  5. package/internal/sidebars.js +20 -0
  6. package/internal/src/components/AboutSection/index.js +67 -0
  7. package/internal/src/components/AboutSection/styles.module.css +492 -0
  8. package/internal/src/components/ContactSection/index.js +94 -0
  9. package/internal/src/components/ContactSection/styles.module.css +327 -0
  10. package/internal/src/components/ExperienceSection/index.js +25 -0
  11. package/internal/src/components/ExperienceSection/styles.module.css +180 -0
  12. package/internal/src/components/HeroSection/index.js +61 -0
  13. package/internal/src/components/HeroSection/styles.module.css +471 -0
  14. package/internal/src/components/NoteIndex/index.js +127 -0
  15. package/internal/src/components/NoteIndex/styles.module.css +143 -0
  16. package/internal/src/components/ProjectsSection/index.js +529 -0
  17. package/internal/src/components/ProjectsSection/styles.module.css +830 -0
  18. package/internal/src/components/ScrollToTop/index.js +98 -0
  19. package/internal/src/components/ScrollToTop/styles.module.css +96 -0
  20. package/internal/src/components/SocialLinks/index.js +129 -0
  21. package/internal/src/components/SocialLinks/styles.module.css +55 -0
  22. package/internal/src/components/Tooltip/index.js +30 -0
  23. package/internal/src/components/Tooltip/styles.module.css +92 -0
  24. package/internal/src/config/iconMappings.js +329 -0
  25. package/internal/src/config/metaTags.js +240 -0
  26. package/internal/src/config/prism.js +179 -0
  27. package/internal/src/config/sidebar.js +20 -0
  28. package/internal/src/css/bootstrap.css +6 -0
  29. package/internal/src/css/catppuccin.css +632 -0
  30. package/internal/src/css/custom.css +186 -0
  31. package/internal/src/css/tasks.css +868 -0
  32. package/internal/src/pages/index.js +98 -0
  33. package/internal/src/pages/notes.js +88 -0
  34. package/internal/src/pages/tasks.js +310 -0
  35. package/internal/src/utils/HashNavigation.js +250 -0
  36. package/internal/src/utils/appVersion.js +27 -0
  37. package/internal/src/utils/compileConfig.js +82 -0
  38. package/internal/src/utils/cssUtils.js +99 -0
  39. package/internal/src/utils/filterEnabledItems.js +21 -0
  40. package/internal/src/utils/generateFavicon.js +256 -0
  41. package/internal/src/utils/generateRobotsTxt.js +97 -0
  42. package/internal/src/utils/iconExtractor.js +159 -0
  43. package/internal/src/utils/imageDownloader.js +88 -0
  44. package/internal/src/utils/imageProcessor.js +134 -0
  45. package/internal/src/utils/linkShortner.js +0 -0
  46. package/internal/src/utils/updateTitle.js +107 -0
  47. package/package.json +51 -0
  48. package/template/.github/workflows/deploy.yml +57 -0
  49. package/template/README.md +70 -0
  50. package/template/blog/authors.yml +5 -0
  51. package/template/blog/welcome.md +10 -0
  52. package/template/config.js +233 -0
  53. package/template/notes/getting-started.md +7 -0
  54. package/template/static/README.md +33 -0
  55. package/utils/createConfig.js +227 -0
  56. package/utils/logger.js +19 -0
  57. package/utils/packageManager.js +88 -0
@@ -0,0 +1,250 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ // AI Generated (partially)
4
+
5
+ /**
6
+ * <HashNavigation/> Component to handle hash-based navigation with visual effects
7
+ * Should be added at the bottom of the page
8
+ *
9
+ * @param {Object} props Component props
10
+ * @param {string} props.elementPrefix Prefix for element IDs (default: 'card-')
11
+ * @param {string} props.elementSelector Selector for all elements in the group (default: '.content-card')
12
+ * @param {string} props.containerSelector Selector for the container element (default: '.container')
13
+ * @param {number} props.effectDuration Duration of the visual effect in ms (default: 6000)
14
+ * @param {number} props.scrollDelay Delay before scrolling in ms (default: 300)
15
+ * @param {Object} props.scrollOptions Options for scrollIntoView (default: { behavior: 'smooth', block: 'center' })
16
+ * @param {boolean} props.enabled Whether the component is enabled (default: true)
17
+ * @param {Object} props.styles Custom styling options
18
+ * @param {string} props.styles.overlayColor Background color for the overlay (default: 'rgba(var(--ifm-color-emphasis-200-rgb), 0.5)')
19
+ * @param {string} props.styles.highlightShadow Shadow for highlighted element (default: '0 0 30px 10px var(--ifm-color-primary)')
20
+ * @param {string} props.styles.highlightScale Scale for highlighted element (default: '1.05')
21
+ * @param {string} props.styles.blurAmount Blur amount for non-highlighted elements (default: '4px')
22
+ * @param {string} props.styles.blurOpacity Opacity for blurred elements (default: '0.3')
23
+ */
24
+ export default function HashNavigation({
25
+ elementPrefix = 'card-',
26
+ elementSelector = '.content-card',
27
+ containerSelector = '.container',
28
+ effectDuration = 6000,
29
+ scrollDelay = 300,
30
+ scrollOptions = { behavior: 'smooth', block: 'center' },
31
+ enabled = true,
32
+ styles = {}
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
+
39
+ // Default styles
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'
46
+ } = styles;
47
+
48
+ // Reference to track if styles have been injected
49
+ const stylesInjected = useRef(false);
50
+
51
+ // Inject the component styles
52
+ useEffect(() => {
53
+
54
+ // Don't inject styles if already present
55
+ if (document.getElementById(styleId) || stylesInjected.current) {
56
+ return;
57
+ }
58
+
59
+ const styleElement = document.createElement('style');
60
+
61
+ styleElement.id = styleId;
62
+
63
+ styleElement.innerHTML = `
64
+
65
+ ${containerSelector}.${containerActiveClass} {
66
+ position: relative;
67
+ }
68
+
69
+ ${containerSelector}.${containerActiveClass}::after {
70
+ content: '';
71
+ position: fixed;
72
+ top: 0;
73
+ left: 0;
74
+ width: 100%;
75
+ height: 100%;
76
+ background: ${overlayColor};
77
+ z-index: 10;
78
+ pointer-events: none;
79
+ }
80
+
81
+ .${highlightClass} {
82
+ position: relative;
83
+ z-index: 20;
84
+ transform: scale(${highlightScale});
85
+ box-shadow: ${highlightShadow};
86
+ transition: all 0.3s ease;
87
+ }
88
+
89
+ .${blurClass} {
90
+ filter: blur(${blurAmount}) grayscale(70%) brightness(0.8);
91
+ opacity: ${blurOpacity};
92
+ transition: all 0.3s ease;
93
+ background-color: rgba(var(--ifm-color-emphasis-200-rgb), 0.15);
94
+ pointer-events: none;
95
+ }
96
+
97
+ /* Clickable overlay for dismissing effects */
98
+ .hash-nav-overlay {
99
+ position: fixed;
100
+ top: 0;
101
+ left: 0;
102
+ width: 100%;
103
+ height: 100%;
104
+ z-index: 15;
105
+ cursor: pointer;
106
+ }
107
+
108
+ /* Reduced motion support */
109
+ @media (prefers-reduced-motion: reduce) {
110
+ .${highlightClass},
111
+ .${blurClass} {
112
+ transition: none !important;
113
+ }
114
+
115
+ .${highlightClass} {
116
+ transform: none !important;
117
+ }
118
+
119
+ .${blurClass} {
120
+ filter: opacity(${blurOpacity});
121
+ background-color: rgba(var(--ifm-color-emphasis-200-rgb), 0.15);
122
+ }
123
+ }
124
+ `;
125
+
126
+ document.head.appendChild(styleElement);
127
+ stylesInjected.current = true;
128
+
129
+ // Clean up on unmount
130
+ return () => {
131
+ const existingStyle = document.getElementById(styleId);
132
+ if (existingStyle) {
133
+ document.head.removeChild(existingStyle);
134
+ }
135
+ stylesInjected.current = false;
136
+ };
137
+ }, [containerSelector, overlayColor, highlightShadow, highlightScale, blurAmount, blurOpacity]);
138
+
139
+
140
+ // Main hash navigation logic
141
+ useEffect(() => {
142
+ if (!enabled) return;
143
+
144
+ if (window.location.hash) {
145
+ const hashValue = window.location.hash.substring(1);
146
+ const targetElement = document.getElementById(`${elementPrefix}${hashValue}`);
147
+
148
+ if (targetElement) {
149
+
150
+ // Wait a moment for the page to fully render
151
+ setTimeout(() => {
152
+
153
+ // Scroll to the element
154
+ targetElement.scrollIntoView(scrollOptions);
155
+
156
+ // Get the container to add the overlay effect
157
+ const container = document.querySelector(containerSelector);
158
+ if (container) {
159
+ container.classList.add(containerActiveClass);
160
+ }
161
+
162
+ // Add visual effects
163
+ const allElements = document.querySelectorAll(elementSelector);
164
+
165
+ // Add highlight class to the target element
166
+ targetElement.classList.add(highlightClass);
167
+
168
+ // Add blur to all other elements
169
+ allElements.forEach(element => {
170
+ if (element !== targetElement) {
171
+ element.classList.add(blurClass);
172
+ }
173
+ });
174
+
175
+ // Create clickable overlay for dismissing effects
176
+ const overlay = document.createElement('div');
177
+ overlay.className = 'hash-nav-overlay';
178
+
179
+ document.body.appendChild(overlay);
180
+
181
+ let effectTimeoutId = null;
182
+
183
+ // remove effects
184
+ const removeEffects = () => {
185
+
186
+ if (effectTimeoutId) {
187
+ clearTimeout(effectTimeoutId);
188
+ effectTimeoutId = null;
189
+ }
190
+
191
+ // Remove effects
192
+ allElements.forEach(element => {
193
+ element.classList.remove(blurClass);
194
+ });
195
+
196
+ targetElement.classList.remove(highlightClass);
197
+
198
+ // Remove the container overlay
199
+ if (container) {
200
+ container.classList.remove(containerActiveClass);
201
+ }
202
+
203
+ // Remove clickable overlay
204
+ if (overlay && overlay.parentNode) {
205
+ overlay.parentNode.removeChild(overlay);
206
+ }
207
+
208
+ // Remove event listeners after effects are cleared
209
+ overlay.removeEventListener('click', removeEffects);
210
+ overlay.removeEventListener('touchstart', removeEffects);
211
+ document.removeEventListener('keydown', handleKeyDown);
212
+ };
213
+
214
+ // Add keyboard escape handler
215
+ const handleKeyDown = (e) => {
216
+ if (e.key === 'Escape') {
217
+ removeEffects();
218
+ }
219
+ };
220
+
221
+ // Add event listeners to dismiss effects
222
+ overlay.addEventListener('click', removeEffects);
223
+ overlay.addEventListener('touchstart', removeEffects);
224
+ document.addEventListener('keydown', handleKeyDown);
225
+
226
+ // Set timeout to automatically remove effects after duration
227
+ effectTimeoutId = setTimeout(removeEffects, effectDuration);
228
+
229
+ }, scrollDelay);
230
+ }
231
+ }
232
+
233
+ // Cleanup
234
+ return () => {
235
+ const container = document.querySelector(containerSelector);
236
+ const overlay = document.querySelector('.hash-nav-overlay');
237
+
238
+ if (container) {
239
+ container.classList.remove(containerActiveClass);
240
+ }
241
+
242
+ // Remove any overlay element that might exist
243
+ if (overlay && overlay.parentNode) {
244
+ overlay.parentNode.removeChild(overlay);
245
+ }
246
+ };
247
+ }, [enabled, elementPrefix, elementSelector, containerSelector, effectDuration, scrollDelay, scrollOptions]);
248
+
249
+ return null;
250
+ }
@@ -0,0 +1,27 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ let cachedVersion = null;
5
+
6
+ function appVersion() {
7
+
8
+ if (cachedVersion) {
9
+ return cachedVersion;
10
+ }
11
+
12
+ try {
13
+ const pkgPath = path.resolve(__dirname, '../../package.json');
14
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
15
+
16
+ cachedVersion = pkg.version || '0.0.0';
17
+ } catch (err) {
18
+
19
+ cachedVersion = '0.0.0';
20
+ console.warn('Could not read package.json version:', err.message);
21
+ }
22
+
23
+ console.info('\n[INFO] App version:', cachedVersion);
24
+ return cachedVersion;
25
+ }
26
+
27
+ module.exports = { appVersion };
@@ -0,0 +1,82 @@
1
+
2
+ // Import the config
3
+ const rawConfig = require('../../config.js');
4
+
5
+ function resolvePath(obj, path) {
6
+ const parts = path.split('.');
7
+ let current = obj;
8
+
9
+ for (const part of parts) {
10
+ if (current === null || current === undefined || typeof current !== 'object') {
11
+ return undefined;
12
+ }
13
+ current = current[part];
14
+ }
15
+
16
+ return current;
17
+ }
18
+
19
+ function parseStringValue(value, config) {
20
+
21
+ if (typeof value !== 'string') {
22
+ return value;
23
+ }
24
+
25
+ // Find all ${...} references
26
+ return value.replace(/\${([^}]+)}/g, (match, path) => {
27
+ const resolvedValue = resolvePath(config, path);
28
+
29
+ if (resolvedValue === undefined) {
30
+ console.warn(`Warning: Could not resolve reference "${path}" in config value "${value}"`);
31
+ return match;
32
+ }
33
+
34
+ if (typeof resolvedValue === 'string' && resolvedValue.includes('${')) {
35
+ return parseStringValue(resolvedValue, config);
36
+ }
37
+
38
+ return resolvedValue;
39
+ });
40
+ }
41
+
42
+
43
+ function parseConfigObject(obj, config) {
44
+
45
+ if (Array.isArray(obj)) {
46
+ return obj.map(item => parseConfigObject(item, config));
47
+ }
48
+
49
+ if (obj !== null && typeof obj === 'object') {
50
+ const result = {};
51
+ for (const [key, value] of Object.entries(obj)) {
52
+ result[key] = parseConfigObject(value, config);
53
+ }
54
+ return result;
55
+ }
56
+
57
+ if (typeof obj === 'string') {
58
+ return parseStringValue(obj, config);
59
+ }
60
+
61
+ return obj;
62
+ }
63
+
64
+
65
+ function parseConfig(config) {
66
+
67
+ const parsedConfig = JSON.parse(JSON.stringify(config));
68
+ return parseConfigObject(parsedConfig, config);
69
+ }
70
+
71
+ // Parse the raw config
72
+ const parsedExports = {};
73
+ for (const key in rawConfig) {
74
+ parsedExports[key] = parseConfig(rawConfig[key]);
75
+ }
76
+
77
+ module.exports = {
78
+ ...parsedExports,
79
+ parseConfig,
80
+ parseStringValue,
81
+ resolvePath,
82
+ }
@@ -0,0 +1,99 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ // AI generated
5
+
6
+ // Cache for CSS content and parsed variables
7
+ const cssCache = new Map();
8
+ const varCache = new Map();
9
+
10
+ // Debug flag - set to true to enable debug logs
11
+ const DEBUG = false;
12
+
13
+ function getCssVar(varName) {
14
+ // Return cached value if exists
15
+ if (varCache.has(varName)) {
16
+ DEBUG && console.log(`[CSS-DEBUG] Using cached value for ${varName}: ${varCache.get(varName)}`);
17
+ return varCache.get(varName);
18
+ }
19
+
20
+ DEBUG && console.log(`[CSS-DEBUG] Looking for CSS variable: ${varName}`);
21
+
22
+ // Try to find variable in CSS files
23
+ const cssFiles = [
24
+ path.resolve(__dirname, '../css/custom.css'),
25
+ path.resolve(__dirname, '../css/catppuccin.css')
26
+ ];
27
+
28
+ for (const cssPath of cssFiles) {
29
+ try {
30
+ DEBUG && console.log(`[CSS-DEBUG] Checking file: ${cssPath}`);
31
+
32
+ if (!fs.existsSync(cssPath)) {
33
+ DEBUG && console.log(`[CSS-DEBUG] File not found: ${cssPath}`);
34
+ continue;
35
+ }
36
+
37
+ let cssContent = cssCache.get(cssPath);
38
+ if (!cssContent) {
39
+ cssContent = fs.readFileSync(cssPath, 'utf8');
40
+ cssCache.set(cssPath, cssContent);
41
+ DEBUG && console.log(`[CSS-DEBUG] Loaded CSS file: ${cssPath}`);
42
+ }
43
+
44
+ // Find all occurrences of the variable
45
+ const regex = new RegExp(`${varName}:\\s*([^;]+);`, 'g');
46
+ let lastValue = null;
47
+ let match;
48
+ let matchCount = 0;
49
+
50
+ // Find all matches and keep the last one
51
+ while ((match = regex.exec(cssContent)) !== null) {
52
+ matchCount++;
53
+ lastValue = match[1].replace(/!important/g, '').trim();
54
+ DEBUG && console.log(`[CSS-DEBUG] Found match #${matchCount} for ${varName}: ${lastValue}`);
55
+ }
56
+
57
+ if (matchCount > 0) {
58
+ DEBUG && console.log(`[CSS-DEBUG] Using last of ${matchCount} matches for ${varName}: ${lastValue}`);
59
+ }
60
+
61
+ // Process nested variables
62
+ if (lastValue && lastValue.startsWith('var(')) {
63
+ const nestedMatch = lastValue.match(/var\((--[^)]+)\)/);
64
+ if (nestedMatch) {
65
+ const nestedVar = nestedMatch[1];
66
+ DEBUG && console.log(`[CSS-DEBUG] Found nested variable in ${varName}: ${nestedVar}`);
67
+
68
+ try {
69
+ const resolvedValue = getCssVar(nestedVar);
70
+ DEBUG && console.log(`[CSS-DEBUG] Resolved nested ${nestedVar} to: ${resolvedValue}`);
71
+ varCache.set(varName, resolvedValue);
72
+ return resolvedValue;
73
+ } catch (err) {
74
+ DEBUG && console.log(`[CSS-DEBUG] Could not resolve nested variable: ${err.message}`);
75
+ throw new Error(`Failed to resolve nested variable ${nestedVar} in ${varName}: ${err.message}`);
76
+ }
77
+ }
78
+ }
79
+
80
+ if (lastValue) {
81
+ DEBUG && console.log(`[CSS-DEBUG] Caching and returning value for ${varName}: ${lastValue}`);
82
+ varCache.set(varName, lastValue);
83
+ return lastValue;
84
+ }
85
+ } catch (err) {
86
+ DEBUG && console.log(`[CSS-DEBUG] Error processing ${cssPath}: ${err.message}`);
87
+ if (err.message.includes('Failed to resolve nested variable')) {
88
+ throw err;
89
+ }
90
+ }
91
+ }
92
+
93
+ // Variable not found - throw error
94
+ const errorMsg = `CSS variable ${varName} not found in any CSS files`;
95
+ DEBUG && console.error(`[CSS-DEBUG] ${errorMsg}`);
96
+ throw new Error(errorMsg);
97
+ }
98
+
99
+ module.exports = { getCssVar };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Filters an array of items that can be either:
3
+ * 1. Regular items (included as-is)
4
+ * 2. Conditional items with enable/value properties (included only if enabled)
5
+ *
6
+ **/
7
+ export const useEnabled = (items) => {
8
+ if (!Array.isArray(items)) {
9
+ console.warn('useEnabled: Expected an array, received:', typeof items);
10
+ return [];
11
+ }
12
+
13
+ return items.flatMap(item => {
14
+ // If item has enable property, it's a conditional item
15
+ if (item && typeof item === 'object' && 'enable' in item && 'value' in item) {
16
+ return item.enable === true ? [item.value] : [];
17
+ }
18
+ // Otherwise it's a regular item that's always included
19
+ return [item];
20
+ });
21
+ };