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.
- package/LICENSE +674 -0
- package/README.md +116 -0
- package/bin/portosaurus.js +337 -0
- package/internal/notes/index.md +10 -0
- package/internal/sidebars.js +20 -0
- package/internal/src/components/AboutSection/index.js +67 -0
- package/internal/src/components/AboutSection/styles.module.css +492 -0
- package/internal/src/components/ContactSection/index.js +94 -0
- package/internal/src/components/ContactSection/styles.module.css +327 -0
- package/internal/src/components/ExperienceSection/index.js +25 -0
- package/internal/src/components/ExperienceSection/styles.module.css +180 -0
- package/internal/src/components/HeroSection/index.js +61 -0
- package/internal/src/components/HeroSection/styles.module.css +471 -0
- package/internal/src/components/NoteIndex/index.js +127 -0
- package/internal/src/components/NoteIndex/styles.module.css +143 -0
- package/internal/src/components/ProjectsSection/index.js +529 -0
- package/internal/src/components/ProjectsSection/styles.module.css +830 -0
- package/internal/src/components/ScrollToTop/index.js +98 -0
- package/internal/src/components/ScrollToTop/styles.module.css +96 -0
- package/internal/src/components/SocialLinks/index.js +129 -0
- package/internal/src/components/SocialLinks/styles.module.css +55 -0
- package/internal/src/components/Tooltip/index.js +30 -0
- package/internal/src/components/Tooltip/styles.module.css +92 -0
- package/internal/src/config/iconMappings.js +329 -0
- package/internal/src/config/metaTags.js +240 -0
- package/internal/src/config/prism.js +179 -0
- package/internal/src/config/sidebar.js +20 -0
- package/internal/src/css/bootstrap.css +6 -0
- package/internal/src/css/catppuccin.css +632 -0
- package/internal/src/css/custom.css +186 -0
- package/internal/src/css/tasks.css +868 -0
- package/internal/src/pages/index.js +98 -0
- package/internal/src/pages/notes.js +88 -0
- package/internal/src/pages/tasks.js +310 -0
- package/internal/src/utils/HashNavigation.js +250 -0
- package/internal/src/utils/appVersion.js +27 -0
- package/internal/src/utils/compileConfig.js +82 -0
- package/internal/src/utils/cssUtils.js +99 -0
- package/internal/src/utils/filterEnabledItems.js +21 -0
- package/internal/src/utils/generateFavicon.js +256 -0
- package/internal/src/utils/generateRobotsTxt.js +97 -0
- package/internal/src/utils/iconExtractor.js +159 -0
- package/internal/src/utils/imageDownloader.js +88 -0
- package/internal/src/utils/imageProcessor.js +134 -0
- package/internal/src/utils/linkShortner.js +0 -0
- package/internal/src/utils/updateTitle.js +107 -0
- package/package.json +51 -0
- package/template/.github/workflows/deploy.yml +57 -0
- package/template/README.md +70 -0
- package/template/blog/authors.yml +5 -0
- package/template/blog/welcome.md +10 -0
- package/template/config.js +233 -0
- package/template/notes/getting-started.md +7 -0
- package/template/static/README.md +33 -0
- package/utils/createConfig.js +227 -0
- package/utils/logger.js +19 -0
- 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
|
+
};
|