@stfrigerio/sito-template 0.1.6 → 0.1.8
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/dist/components/molecules/SearchBar/SearchBar.d.ts +11 -2
- package/dist/components/molecules/SearchBar/SearchBar.d.ts.map +1 -1
- package/dist/components/molecules/SearchBar/index.d.ts +1 -1
- package/dist/components/molecules/SearchBar/index.d.ts.map +1 -1
- package/dist/components/molecules/Tabs/Tabs.d.ts +11 -5
- package/dist/components/molecules/Tabs/Tabs.d.ts.map +1 -1
- package/dist/components/molecules/ThemeSwitcher/ThemeSwitcher.d.ts +9 -2
- package/dist/components/molecules/ThemeSwitcher/ThemeSwitcher.d.ts.map +1 -1
- package/dist/components/molecules/index.d.ts +3 -2
- package/dist/components/molecules/index.d.ts.map +1 -1
- package/dist/components/organisms/charts/PieChart/PieChart.d.ts +2 -0
- package/dist/components/organisms/charts/PieChart/PieChart.d.ts.map +1 -1
- package/dist/components/organisms/charts/QuantifiableHabitsChart/QuantifiableHabitsChart.d.ts.map +1 -1
- package/dist/components/organisms/charts/SunburstChart/SunburstChart.d.ts +2 -0
- package/dist/components/organisms/charts/SunburstChart/SunburstChart.d.ts.map +1 -1
- package/dist/index.esm.js +177 -45
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +177 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1199,7 +1199,8 @@ const EditFAB = ({ canEdit, isEditMode, hasUnsavedChanges = false, isSaving = fa
|
|
|
1199
1199
|
|
|
1200
1200
|
var styles$a = {"searchContainer":"SearchBar-module_searchContainer__TdM1w","searchInputWrapper":"SearchBar-module_searchInputWrapper__kCZLU","searchIcon":"SearchBar-module_searchIcon__IIxEu","searchInput":"SearchBar-module_searchInput__V4gkE","clearButton":"SearchBar-module_clearButton__7fNIY","filterSelect":"SearchBar-module_filterSelect__xIVE4","resultsDropdown":"SearchBar-module_resultsDropdown__yh6NF","loadingState":"SearchBar-module_loadingState__4gidK","emptyState":"SearchBar-module_emptyState__RbI4s","spinner":"SearchBar-module_spinner__PMc6-","resultsGroups":"SearchBar-module_resultsGroups__U24DC","resultGroup":"SearchBar-module_resultGroup__SoTQH","groupHeader":"SearchBar-module_groupHeader__bFRHA","groupIcon":"SearchBar-module_groupIcon__9ENM-","groupTitle":"SearchBar-module_groupTitle__ZekZs","groupCount":"SearchBar-module_groupCount__PQIqw","groupResults":"SearchBar-module_groupResults__xTF52","resultItem":"SearchBar-module_resultItem__VaKKy","highlighted":"SearchBar-module_highlighted__Q-3sH","resultTitle":"SearchBar-module_resultTitle__i1uqL","resultSubtitle":"SearchBar-module_resultSubtitle__LQOJ1","resultMeta":"SearchBar-module_resultMeta__Kmkrn","resultContent":"SearchBar-module_resultContent__TzVzL","highlight":"SearchBar-module_highlight__Q3PSP"};
|
|
1201
1201
|
|
|
1202
|
-
|
|
1202
|
+
// Default filter options for backwards compatibility
|
|
1203
|
+
const defaultFilterOptions = [
|
|
1203
1204
|
{ value: 'all', label: 'All', icon: FiSearch },
|
|
1204
1205
|
{ value: 'projects', label: 'Projects', icon: FiFolder },
|
|
1205
1206
|
{ value: 'clients', label: 'Clients', icon: FiUsers },
|
|
@@ -1207,16 +1208,18 @@ const filterOptions = [
|
|
|
1207
1208
|
{ value: 'interactions', label: 'Interactions', icon: FiMessageSquare },
|
|
1208
1209
|
{ value: 'team', label: 'Team', icon: FiUserPlus },
|
|
1209
1210
|
];
|
|
1210
|
-
const
|
|
1211
|
+
const defaultEntityIcons = {
|
|
1211
1212
|
projects: FiFolder,
|
|
1212
1213
|
clients: FiUsers,
|
|
1213
1214
|
contacts: FiBook,
|
|
1214
1215
|
interactions: FiMessageSquare,
|
|
1215
1216
|
team: FiUserPlus,
|
|
1216
1217
|
};
|
|
1217
|
-
const SearchBar = ({ className, placeholder = "Search (Ctrl+Space)...", onSearch, onResultClick, onClear, debounceDelay = 300, minSearchLength = 2, showFilter = true, enableKeyboardShortcut = true }) => {
|
|
1218
|
+
const SearchBar = ({ className, placeholder = "Search (Ctrl+Space)...", onSearch, onResultClick, onClear, debounceDelay = 300, minSearchLength = 2, showFilter = true, enableKeyboardShortcut = true, filterOptions: customFilterOptions, entityIcons: customEntityIcons }) => {
|
|
1219
|
+
const filterOptions = customFilterOptions ?? defaultFilterOptions;
|
|
1220
|
+
const entityIcons = customEntityIcons ?? defaultEntityIcons;
|
|
1218
1221
|
const [query, setQuery] = React.useState('');
|
|
1219
|
-
const [filter, setFilter] = React.useState('all');
|
|
1222
|
+
const [filter, setFilter] = React.useState(filterOptions[0]?.value ?? 'all');
|
|
1220
1223
|
const [results, setResults] = React.useState([]);
|
|
1221
1224
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
1222
1225
|
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
|
|
@@ -1500,9 +1503,19 @@ const useTheme = () => {
|
|
|
1500
1503
|
|
|
1501
1504
|
var styles$7 = {"button":"ThemeSwitcher-module_button__VfRjU","iconWrapper":"ThemeSwitcher-module_iconWrapper__FpHo8","label":"ThemeSwitcher-module_label__2Hfkp","toggle":"ThemeSwitcher-module_toggle__ATXx4","toggleTrack":"ThemeSwitcher-module_toggleTrack__x28Rv","toggleThumb":"ThemeSwitcher-module_toggleThumb__V8QeN","dropdown":"ThemeSwitcher-module_dropdown__3qLdt","dropdownTrigger":"ThemeSwitcher-module_dropdownTrigger__UzYV5","dropdownMenu":"ThemeSwitcher-module_dropdownMenu__3L5hT","dropdownItem":"ThemeSwitcher-module_dropdownItem__inw-K","active":"ThemeSwitcher-module_active__OHP19","icon":"ThemeSwitcher-module_icon__iRZiJ","text":"ThemeSwitcher-module_text__OCOoA"};
|
|
1502
1505
|
|
|
1503
|
-
const ThemeSwitcher = ({ variant = 'button', showLabel = false, className = '', }) => {
|
|
1504
|
-
|
|
1505
|
-
const
|
|
1506
|
+
const ThemeSwitcher = ({ variant = 'button', showLabel = false, className = '', currentTheme, onThemeChange, themes: customThemes, }) => {
|
|
1507
|
+
// Try to use internal context if available, otherwise use props
|
|
1508
|
+
const contextTheme = (() => {
|
|
1509
|
+
try {
|
|
1510
|
+
return useTheme();
|
|
1511
|
+
}
|
|
1512
|
+
catch {
|
|
1513
|
+
return null;
|
|
1514
|
+
}
|
|
1515
|
+
})();
|
|
1516
|
+
const theme = currentTheme ?? contextTheme?.theme ?? 'light';
|
|
1517
|
+
const setTheme = onThemeChange ?? contextTheme?.setTheme ?? (() => { });
|
|
1518
|
+
const defaultThemes = [
|
|
1506
1519
|
{ value: 'light', label: 'Light', icon: jsxRuntime.jsx(FiSun, {}) },
|
|
1507
1520
|
{ value: 'dark', label: 'Dark', icon: jsxRuntime.jsx(FiMoon, {}) },
|
|
1508
1521
|
{ value: 'lossito', label: 'Lossito Light', icon: '✨' },
|
|
@@ -1510,21 +1523,22 @@ const ThemeSwitcher = ({ variant = 'button', showLabel = false, className = '',
|
|
|
1510
1523
|
{ value: 'dmood', label: 'Dmood Light', icon: '💙' },
|
|
1511
1524
|
{ value: 'dmood-dark', label: 'Dmood Dark', icon: '🌌' },
|
|
1512
1525
|
];
|
|
1526
|
+
const themes = customThemes ?? defaultThemes;
|
|
1513
1527
|
const currentThemeIndex = themes.findIndex(t => t.value === theme);
|
|
1514
|
-
const
|
|
1528
|
+
const currentThemeData = themes[currentThemeIndex] ?? themes[0];
|
|
1515
1529
|
if (variant === 'toggle') {
|
|
1516
1530
|
// Simple toggle between light and dark
|
|
1517
1531
|
const isDark = theme.includes('dark');
|
|
1518
1532
|
return (jsxRuntime.jsxs(framerMotion.motion.button, { className: `${styles$7.toggle} ${className}`, onClick: () => setTheme(isDark ? 'light' : 'dark'), whileTap: { scale: 0.95 }, "aria-label": "Toggle theme", children: [jsxRuntime.jsx(framerMotion.motion.div, { className: styles$7.toggleTrack, animate: { backgroundColor: isDark ? 'var(--color-primary)' : 'var(--color-border)' }, children: jsxRuntime.jsx(framerMotion.motion.div, { className: styles$7.toggleThumb, animate: { x: isDark ? 24 : 0 }, transition: { type: 'spring', stiffness: 500, damping: 30 }, children: isDark ? jsxRuntime.jsx(FiMoon, { size: 14 }) : jsxRuntime.jsx(FiSun, { size: 14 }) }) }), showLabel && jsxRuntime.jsx("span", { className: styles$7.label, children: isDark ? 'Dark' : 'Light' })] }));
|
|
1519
1533
|
}
|
|
1520
1534
|
if (variant === 'dropdown') {
|
|
1521
|
-
return (jsxRuntime.jsxs("div", { className: `${styles$7.dropdown} ${className}`, children: [jsxRuntime.jsxs(framerMotion.motion.button, { className: styles$7.dropdownTrigger, whileTap: { scale: 0.98 }, children: [
|
|
1535
|
+
return (jsxRuntime.jsxs("div", { className: `${styles$7.dropdown} ${className}`, children: [jsxRuntime.jsxs(framerMotion.motion.button, { className: styles$7.dropdownTrigger, whileTap: { scale: 0.98 }, children: [currentThemeData.icon, showLabel && jsxRuntime.jsx("span", { className: styles$7.label, children: currentThemeData.label })] }), jsxRuntime.jsx(framerMotion.motion.div, { className: styles$7.dropdownMenu, initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, children: themes.map((t) => (jsxRuntime.jsxs(framerMotion.motion.button, { className: `${styles$7.dropdownItem} ${theme === t.value ? styles$7.active : ''}`, onClick: () => setTheme(t.value), whileHover: { x: 4 }, whileTap: { scale: 0.98 }, children: [jsxRuntime.jsx("span", { className: styles$7.icon, children: t.icon }), jsxRuntime.jsx("span", { className: styles$7.text, children: t.label })] }, t.value))) })] }));
|
|
1522
1536
|
}
|
|
1523
1537
|
// Default button variant - cycles through themes
|
|
1524
1538
|
return (jsxRuntime.jsxs(framerMotion.motion.button, { className: `${styles$7.button} ${className}`, onClick: () => {
|
|
1525
1539
|
const nextIndex = (currentThemeIndex + 1) % themes.length;
|
|
1526
1540
|
setTheme(themes[nextIndex].value);
|
|
1527
|
-
}, whileTap: { scale: 0.95 }, whileHover: { scale: 1.05 }, "aria-label": `Current theme: ${
|
|
1541
|
+
}, whileTap: { scale: 0.95 }, whileHover: { scale: 1.05 }, "aria-label": `Current theme: ${currentThemeData.label}. Click to change.`, children: [jsxRuntime.jsx(framerMotion.motion.div, { initial: { rotate: -180, opacity: 0 }, animate: { rotate: 0, opacity: 1 }, exit: { rotate: 180, opacity: 0 }, transition: { duration: 0.3 }, className: styles$7.iconWrapper, children: currentThemeData.icon }, theme), showLabel && jsxRuntime.jsx("span", { className: styles$7.label, children: currentThemeData.label })] }));
|
|
1528
1542
|
};
|
|
1529
1543
|
|
|
1530
1544
|
// THIS FILE IS AUTO GENERATED
|
|
@@ -1534,15 +1548,16 @@ function SiJira (props) {
|
|
|
1534
1548
|
|
|
1535
1549
|
var styles$6 = {"tabs":"Tabs-module_tabs__Vlvn7","tab":"Tabs-module_tab__uQKim","tabIcon":"Tabs-module_tabIcon__AgN-O"};
|
|
1536
1550
|
|
|
1537
|
-
|
|
1551
|
+
// Default tabs for backwards compatibility
|
|
1552
|
+
const defaultTabs = [
|
|
1538
1553
|
{ id: 'details', icon: FiInfo, label: 'Dettagli' },
|
|
1539
1554
|
{ id: 'github', icon: FiGithub, label: 'GitHub' },
|
|
1540
1555
|
{ id: 'jira', icon: SiJira, label: 'Jira' },
|
|
1541
1556
|
{ id: 'functional', icon: FiInfo, label: 'Analisi funzionale' }
|
|
1542
1557
|
];
|
|
1543
|
-
const Tabs = ({ activeTab, onTabChange }) => {
|
|
1544
|
-
|
|
1545
|
-
|
|
1558
|
+
const Tabs = ({ activeTab, onTabChange, tabs: customTabs, className = '' }) => {
|
|
1559
|
+
const tabs = customTabs ?? defaultTabs;
|
|
1560
|
+
return (jsxRuntime.jsx("div", { className: `${styles$6.tabs} ${className}`, children: tabs.map((tab) => {
|
|
1546
1561
|
const isActive = activeTab === tab.id;
|
|
1547
1562
|
return (jsxRuntime.jsxs(framerMotion.motion.button, { className: styles$6.tab, "data-active": isActive, onClick: () => onTabChange(tab.id), style: { position: 'relative' }, children: [jsxRuntime.jsx(framerMotion.motion.div, { animate: {
|
|
1548
1563
|
rotate: isActive ? [0, -10, 10, -5, 5, 0] : 0,
|
|
@@ -1551,7 +1566,7 @@ const Tabs = ({ activeTab, onTabChange }) => {
|
|
|
1551
1566
|
duration: 0.5,
|
|
1552
1567
|
ease: 'easeInOut'
|
|
1553
1568
|
}
|
|
1554
|
-
}, children: jsxRuntime.jsx(
|
|
1569
|
+
}, children: tab.icon && (typeof tab.icon === 'function' ? (jsxRuntime.jsx("span", { className: styles$6.tabIcon, children: React.createElement(tab.icon) })) : (jsxRuntime.jsx("span", { className: styles$6.tabIcon, children: tab.icon }))) }), jsxRuntime.jsx("span", { children: tab.label })] }, tab.id));
|
|
1555
1570
|
}) }));
|
|
1556
1571
|
};
|
|
1557
1572
|
|
|
@@ -2235,11 +2250,22 @@ const BooleansHeatmap = ({ data, habitName, width = 800, height = 200, habitColo
|
|
|
2235
2250
|
var styles$1 = {"container":"SunburstChart-module_container__w1ZYc","title":"SunburstChart-module_title__T6Ak7","chart":"SunburstChart-module_chart__BFM6E","tooltip":"SunburstChart-module_tooltip__TuTAN"};
|
|
2236
2251
|
|
|
2237
2252
|
const COLOR_PALETTE = [
|
|
2238
|
-
'#
|
|
2239
|
-
'#
|
|
2240
|
-
'#
|
|
2253
|
+
'#6366f1', '#8b5cf6', '#06b6d4', '#10b981',
|
|
2254
|
+
'#f59e0b', '#ef4444', '#ec4899', '#84cc16',
|
|
2255
|
+
'#f97316', '#3b82f6', '#14b8a6', '#f59e0b'
|
|
2241
2256
|
];
|
|
2242
|
-
|
|
2257
|
+
// Calculate text color based on background luminance for optimal contrast
|
|
2258
|
+
const getTextColor$1 = (backgroundColor) => {
|
|
2259
|
+
const color = d3__namespace.color(backgroundColor);
|
|
2260
|
+
if (!color)
|
|
2261
|
+
return '#ffffff';
|
|
2262
|
+
const rgb = color.rgb();
|
|
2263
|
+
// Calculate relative luminance using WCAG formula
|
|
2264
|
+
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
|
|
2265
|
+
// Return white text for dark backgrounds, black for light backgrounds
|
|
2266
|
+
return luminance > 0.5 ? '#000000' : '#ffffff';
|
|
2267
|
+
};
|
|
2268
|
+
const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Chart', tagColors = {}, unit = 'items', centerLabel }) => {
|
|
2243
2269
|
const svgRef = React.useRef(null);
|
|
2244
2270
|
const colorMap = React.useRef(new Map()).current;
|
|
2245
2271
|
const colorIndex = React.useRef(0);
|
|
@@ -2282,7 +2308,8 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2282
2308
|
.startAngle(d => d.x0)
|
|
2283
2309
|
.endAngle(d => d.x1)
|
|
2284
2310
|
.innerRadius(d => Math.sqrt(d.y0))
|
|
2285
|
-
.outerRadius(d => Math.sqrt(d.y1))
|
|
2311
|
+
.outerRadius(d => Math.sqrt(d.y1))
|
|
2312
|
+
.cornerRadius(3);
|
|
2286
2313
|
const tooltip = d3__namespace.select('body').append('div')
|
|
2287
2314
|
.attr('class', styles$1.tooltip)
|
|
2288
2315
|
.style('opacity', 0)
|
|
@@ -2301,11 +2328,20 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2301
2328
|
.attr('stroke', 'var(--bg-primary)')
|
|
2302
2329
|
.attr('stroke-width', 2)
|
|
2303
2330
|
.style('cursor', 'pointer')
|
|
2331
|
+
.style('filter', 'drop-shadow(0 1px 3px rgba(0,0,0,0.12))')
|
|
2304
2332
|
.on('mouseover', function (event, d) {
|
|
2333
|
+
const hoverArc = d3__namespace.arc()
|
|
2334
|
+
.startAngle(d => d.x0)
|
|
2335
|
+
.endAngle(d => d.x1)
|
|
2336
|
+
.innerRadius(d => Math.sqrt(d.y0) - 2)
|
|
2337
|
+
.outerRadius(d => Math.sqrt(d.y1) + 4)
|
|
2338
|
+
.cornerRadius(3);
|
|
2305
2339
|
d3__namespace.select(this)
|
|
2306
2340
|
.transition()
|
|
2307
|
-
.duration(
|
|
2308
|
-
.
|
|
2341
|
+
.duration(150)
|
|
2342
|
+
.attr('d', d => hoverArc(d))
|
|
2343
|
+
.style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.2))')
|
|
2344
|
+
.style('opacity', 0.9);
|
|
2309
2345
|
tooltip.transition()
|
|
2310
2346
|
.duration(200)
|
|
2311
2347
|
.style('opacity', 1);
|
|
@@ -2319,10 +2355,12 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2319
2355
|
.style('left', (event.pageX + 10) + 'px')
|
|
2320
2356
|
.style('top', (event.pageY - 28) + 'px');
|
|
2321
2357
|
})
|
|
2322
|
-
.on('mouseout', function () {
|
|
2358
|
+
.on('mouseout', function (event, d) {
|
|
2323
2359
|
d3__namespace.select(this)
|
|
2324
2360
|
.transition()
|
|
2325
|
-
.duration(
|
|
2361
|
+
.duration(150)
|
|
2362
|
+
.attr('d', d => arc(d))
|
|
2363
|
+
.style('filter', 'drop-shadow(0 1px 3px rgba(0,0,0,0.12))')
|
|
2326
2364
|
.style('opacity', 1);
|
|
2327
2365
|
tooltip.transition()
|
|
2328
2366
|
.duration(500)
|
|
@@ -2332,9 +2370,32 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2332
2370
|
const angle = d.x1 - d.x0;
|
|
2333
2371
|
return angle > 0.15 && d.depth <= 2;
|
|
2334
2372
|
};
|
|
2335
|
-
|
|
2373
|
+
// Calculate average background color for center text contrast
|
|
2374
|
+
const allSegments = nodes.filter(d => d.depth === 1);
|
|
2375
|
+
const avgColor = allSegments.length > 0 ? d3__namespace.interpolateRgb.gamma(2.2)(...allSegments.map(d => getColor(d.data.name, 1)))(0.5) : '#ffffff';
|
|
2376
|
+
const centerTextColor = getTextColor$1(avgColor);
|
|
2377
|
+
// Add center text
|
|
2378
|
+
g.append('text')
|
|
2379
|
+
.attr('text-anchor', 'middle')
|
|
2380
|
+
.attr('alignment-baseline', 'middle')
|
|
2381
|
+
.attr('font-size', '18px')
|
|
2382
|
+
.attr('font-weight', 'bold')
|
|
2383
|
+
.attr('fill', centerTextColor)
|
|
2384
|
+
.style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 3px rgba(0,0,0,0.5)' : '0 1px 3px rgba(255,255,255,0.5)')
|
|
2385
|
+
.text(centerLabel || data.name || 'Total');
|
|
2386
|
+
g.append('text')
|
|
2387
|
+
.attr('text-anchor', 'middle')
|
|
2388
|
+
.attr('alignment-baseline', 'middle')
|
|
2389
|
+
.attr('y', 20)
|
|
2390
|
+
.attr('font-size', '14px')
|
|
2391
|
+
.attr('font-weight', '500')
|
|
2392
|
+
.attr('fill', centerTextColor)
|
|
2393
|
+
.style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 2px rgba(0,0,0,0.4)' : '0 1px 2px rgba(255,255,255,0.4)')
|
|
2394
|
+
.text(`${(root.value || 0).toLocaleString()} ${unit}`);
|
|
2395
|
+
g.selectAll('text.segment-label')
|
|
2336
2396
|
.data(nodes.filter(d => d.depth > 0 && d.value && d.value > 0 && shouldDisplayLabel(d)))
|
|
2337
2397
|
.enter().append('text')
|
|
2398
|
+
.attr('class', 'segment-label')
|
|
2338
2399
|
.attr('transform', d => {
|
|
2339
2400
|
const angle = (d.x0 + d.x1) / 2;
|
|
2340
2401
|
const radius = (Math.sqrt(d.y0) + Math.sqrt(d.y1)) / 2;
|
|
@@ -2344,11 +2405,32 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2344
2405
|
})
|
|
2345
2406
|
.attr('text-anchor', 'middle')
|
|
2346
2407
|
.attr('alignment-baseline', 'middle')
|
|
2347
|
-
.attr('font-size', '
|
|
2348
|
-
.attr('fill',
|
|
2349
|
-
|
|
2408
|
+
.attr('font-size', d => d.depth === 1 ? '13px' : '11px')
|
|
2409
|
+
.attr('fill', d => {
|
|
2410
|
+
let ancestor = d;
|
|
2411
|
+
while (ancestor.depth > 1 && ancestor.parent) {
|
|
2412
|
+
ancestor = ancestor.parent;
|
|
2413
|
+
}
|
|
2414
|
+
const segmentColor = getColor(ancestor.data.name, d.depth);
|
|
2415
|
+
return getTextColor$1(segmentColor);
|
|
2416
|
+
})
|
|
2417
|
+
.attr('font-weight', '600')
|
|
2350
2418
|
.style('pointer-events', 'none')
|
|
2351
|
-
.text
|
|
2419
|
+
.style('text-shadow', d => {
|
|
2420
|
+
let ancestor = d;
|
|
2421
|
+
while (ancestor.depth > 1 && ancestor.parent) {
|
|
2422
|
+
ancestor = ancestor.parent;
|
|
2423
|
+
}
|
|
2424
|
+
const segmentColor = getColor(ancestor.data.name, d.depth);
|
|
2425
|
+
const textColor = getTextColor$1(segmentColor);
|
|
2426
|
+
// Use contrasting shadow color
|
|
2427
|
+
const shadowColor = textColor === '#ffffff' ? 'rgba(0,0,0,0.5)' : 'rgba(255,255,255,0.5)';
|
|
2428
|
+
return `0 1px 2px ${shadowColor}`;
|
|
2429
|
+
})
|
|
2430
|
+
.text(d => {
|
|
2431
|
+
const maxLength = d.depth === 1 ? 12 : 8;
|
|
2432
|
+
return d.data.name.substring(0, maxLength);
|
|
2433
|
+
});
|
|
2352
2434
|
return () => {
|
|
2353
2435
|
tooltip.remove();
|
|
2354
2436
|
};
|
|
@@ -2359,12 +2441,23 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2359
2441
|
var styles = {"container":"PieChart-module_container__tXjbe","title":"PieChart-module_title__61o0R","chartContainer":"PieChart-module_chartContainer__uLmOz","chart":"PieChart-module_chart__3nqON","legend":"PieChart-module_legend__rAWgh","legendItem":"PieChart-module_legendItem__Nb031","legendColor":"PieChart-module_legendColor__fLuv9","legendLabel":"PieChart-module_legendLabel__xbjBr","legendValue":"PieChart-module_legendValue__h2WS2","tooltip":"PieChart-module_tooltip__140RU"};
|
|
2360
2442
|
|
|
2361
2443
|
const DEFAULT_COLORS = [
|
|
2362
|
-
'#
|
|
2363
|
-
'#
|
|
2364
|
-
'#
|
|
2365
|
-
'#
|
|
2444
|
+
'#6366f1', '#8b5cf6', '#06b6d4', '#10b981',
|
|
2445
|
+
'#f59e0b', '#ef4444', '#ec4899', '#84cc16',
|
|
2446
|
+
'#f97316', '#3b82f6', '#8b5cf6', '#14b8a6',
|
|
2447
|
+
'#f59e0b', '#ef4444', '#06b6d4', '#10b981'
|
|
2366
2448
|
];
|
|
2367
|
-
|
|
2449
|
+
// Calculate text color based on background luminance for optimal contrast
|
|
2450
|
+
const getTextColor = (backgroundColor) => {
|
|
2451
|
+
const color = d3__namespace.color(backgroundColor);
|
|
2452
|
+
if (!color)
|
|
2453
|
+
return '#ffffff';
|
|
2454
|
+
const rgb = color.rgb();
|
|
2455
|
+
// Calculate relative luminance using WCAG formula
|
|
2456
|
+
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
|
|
2457
|
+
// Return white text for dark backgrounds, black for light backgrounds
|
|
2458
|
+
return luminance > 0.5 ? '#000000' : '#ffffff';
|
|
2459
|
+
};
|
|
2460
|
+
const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', showLegend = true, unit = 'items', centerLabel }) => {
|
|
2368
2461
|
const svgRef = React.useRef(null);
|
|
2369
2462
|
const radius = Math.min(width, height) / 2 - 20;
|
|
2370
2463
|
React.useEffect(() => {
|
|
@@ -2378,8 +2471,9 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2378
2471
|
.value(d => d.value)
|
|
2379
2472
|
.sort(null);
|
|
2380
2473
|
const arc = d3__namespace.arc()
|
|
2381
|
-
.innerRadius(0)
|
|
2382
|
-
.outerRadius(radius)
|
|
2474
|
+
.innerRadius(radius * 0.4)
|
|
2475
|
+
.outerRadius(radius)
|
|
2476
|
+
.cornerRadius(4);
|
|
2383
2477
|
const labelArc = d3__namespace.arc()
|
|
2384
2478
|
.innerRadius(radius * 0.7)
|
|
2385
2479
|
.outerRadius(radius * 0.7);
|
|
@@ -2397,13 +2491,19 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2397
2491
|
.attr('d', d => arc(d))
|
|
2398
2492
|
.attr('fill', (d, i) => d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length])
|
|
2399
2493
|
.attr('stroke', 'var(--bg-primary)')
|
|
2400
|
-
.attr('stroke-width',
|
|
2494
|
+
.attr('stroke-width', 3)
|
|
2401
2495
|
.style('cursor', 'pointer')
|
|
2496
|
+
.style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.15))')
|
|
2402
2497
|
.on('mouseover', function (event, d) {
|
|
2498
|
+
const hoverArc = d3__namespace.arc()
|
|
2499
|
+
.innerRadius(radius * 0.4)
|
|
2500
|
+
.outerRadius(radius * 1.05)
|
|
2501
|
+
.cornerRadius(4);
|
|
2403
2502
|
d3__namespace.select(this)
|
|
2404
2503
|
.transition()
|
|
2405
2504
|
.duration(200)
|
|
2406
|
-
.
|
|
2505
|
+
.attr('d', d => hoverArc(d))
|
|
2506
|
+
.style('filter', 'drop-shadow(0 4px 12px rgba(0,0,0,0.25))');
|
|
2407
2507
|
tooltip.transition()
|
|
2408
2508
|
.duration(200)
|
|
2409
2509
|
.style('opacity', 1);
|
|
@@ -2416,27 +2516,59 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2416
2516
|
.style('left', (event.pageX + 10) + 'px')
|
|
2417
2517
|
.style('top', (event.pageY - 28) + 'px');
|
|
2418
2518
|
})
|
|
2419
|
-
.on('mouseout', function () {
|
|
2519
|
+
.on('mouseout', function (event, d) {
|
|
2420
2520
|
d3__namespace.select(this)
|
|
2421
2521
|
.transition()
|
|
2422
2522
|
.duration(200)
|
|
2423
|
-
.
|
|
2523
|
+
.attr('d', d => arc(d))
|
|
2524
|
+
.style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.15))');
|
|
2424
2525
|
tooltip.transition()
|
|
2425
2526
|
.duration(500)
|
|
2426
2527
|
.style('opacity', 0);
|
|
2427
2528
|
});
|
|
2428
|
-
|
|
2529
|
+
// Calculate average background color for center text contrast
|
|
2530
|
+
const avgColor = data.length > 0 ? d3__namespace.interpolateRgb.gamma(2.2)(...data.map((d, i) => d.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length]))(0.5) : '#ffffff';
|
|
2531
|
+
const centerTextColor = getTextColor(avgColor);
|
|
2532
|
+
// Add center text for donut
|
|
2533
|
+
g.append('text')
|
|
2534
|
+
.attr('text-anchor', 'middle')
|
|
2535
|
+
.attr('alignment-baseline', 'middle')
|
|
2536
|
+
.attr('font-size', '20px')
|
|
2537
|
+
.attr('font-weight', 'bold')
|
|
2538
|
+
.attr('fill', centerTextColor)
|
|
2539
|
+
.style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 3px rgba(0,0,0,0.5)' : '0 1px 3px rgba(255,255,255,0.5)')
|
|
2540
|
+
.text(centerLabel || 'Total');
|
|
2541
|
+
g.append('text')
|
|
2542
|
+
.attr('text-anchor', 'middle')
|
|
2543
|
+
.attr('alignment-baseline', 'middle')
|
|
2544
|
+
.attr('y', 22)
|
|
2545
|
+
.attr('font-size', '16px')
|
|
2546
|
+
.attr('font-weight', '600')
|
|
2547
|
+
.attr('fill', centerTextColor)
|
|
2548
|
+
.style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 2px rgba(0,0,0,0.4)' : '0 1px 2px rgba(255,255,255,0.4)')
|
|
2549
|
+
.text(`${total.toLocaleString()} ${unit}`);
|
|
2550
|
+
arcs.filter(d => (d.endAngle - d.startAngle) > 0.2)
|
|
2429
2551
|
.append('text')
|
|
2430
2552
|
.attr('transform', d => `translate(${labelArc.centroid(d)})`)
|
|
2431
2553
|
.attr('text-anchor', 'middle')
|
|
2432
2554
|
.attr('alignment-baseline', 'middle')
|
|
2433
|
-
.attr('font-size', '
|
|
2434
|
-
.attr('fill',
|
|
2435
|
-
.
|
|
2555
|
+
.attr('font-size', '13px')
|
|
2556
|
+
.attr('fill', (d, i) => {
|
|
2557
|
+
const segmentColor = d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length];
|
|
2558
|
+
return getTextColor(segmentColor);
|
|
2559
|
+
})
|
|
2560
|
+
.attr('font-weight', '600')
|
|
2436
2561
|
.style('pointer-events', 'none')
|
|
2562
|
+
.style('text-shadow', (d, i) => {
|
|
2563
|
+
const segmentColor = d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length];
|
|
2564
|
+
const textColor = getTextColor(segmentColor);
|
|
2565
|
+
// Use contrasting shadow color
|
|
2566
|
+
const shadowColor = textColor === '#ffffff' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.4)';
|
|
2567
|
+
return `0 1px 2px ${shadowColor}`;
|
|
2568
|
+
})
|
|
2437
2569
|
.text(d => {
|
|
2438
2570
|
const percentage = ((d.data.value / total) * 100);
|
|
2439
|
-
return percentage >
|
|
2571
|
+
return percentage > 8 ? `${percentage.toFixed(0)}%` : '';
|
|
2440
2572
|
});
|
|
2441
2573
|
return () => {
|
|
2442
2574
|
tooltip.remove();
|