@stfrigerio/sito-template 0.1.7 → 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/index.d.ts +2 -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 +160 -39
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +160 -39
- 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);
|
|
@@ -1545,15 +1548,16 @@ function SiJira (props) {
|
|
|
1545
1548
|
|
|
1546
1549
|
var styles$6 = {"tabs":"Tabs-module_tabs__Vlvn7","tab":"Tabs-module_tab__uQKim","tabIcon":"Tabs-module_tabIcon__AgN-O"};
|
|
1547
1550
|
|
|
1548
|
-
|
|
1551
|
+
// Default tabs for backwards compatibility
|
|
1552
|
+
const defaultTabs = [
|
|
1549
1553
|
{ id: 'details', icon: FiInfo, label: 'Dettagli' },
|
|
1550
1554
|
{ id: 'github', icon: FiGithub, label: 'GitHub' },
|
|
1551
1555
|
{ id: 'jira', icon: SiJira, label: 'Jira' },
|
|
1552
1556
|
{ id: 'functional', icon: FiInfo, label: 'Analisi funzionale' }
|
|
1553
1557
|
];
|
|
1554
|
-
const Tabs = ({ activeTab, onTabChange }) => {
|
|
1555
|
-
|
|
1556
|
-
|
|
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) => {
|
|
1557
1561
|
const isActive = activeTab === tab.id;
|
|
1558
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: {
|
|
1559
1563
|
rotate: isActive ? [0, -10, 10, -5, 5, 0] : 0,
|
|
@@ -1562,7 +1566,7 @@ const Tabs = ({ activeTab, onTabChange }) => {
|
|
|
1562
1566
|
duration: 0.5,
|
|
1563
1567
|
ease: 'easeInOut'
|
|
1564
1568
|
}
|
|
1565
|
-
}, 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));
|
|
1566
1570
|
}) }));
|
|
1567
1571
|
};
|
|
1568
1572
|
|
|
@@ -2246,11 +2250,22 @@ const BooleansHeatmap = ({ data, habitName, width = 800, height = 200, habitColo
|
|
|
2246
2250
|
var styles$1 = {"container":"SunburstChart-module_container__w1ZYc","title":"SunburstChart-module_title__T6Ak7","chart":"SunburstChart-module_chart__BFM6E","tooltip":"SunburstChart-module_tooltip__TuTAN"};
|
|
2247
2251
|
|
|
2248
2252
|
const COLOR_PALETTE = [
|
|
2249
|
-
'#
|
|
2250
|
-
'#
|
|
2251
|
-
'#
|
|
2253
|
+
'#6366f1', '#8b5cf6', '#06b6d4', '#10b981',
|
|
2254
|
+
'#f59e0b', '#ef4444', '#ec4899', '#84cc16',
|
|
2255
|
+
'#f97316', '#3b82f6', '#14b8a6', '#f59e0b'
|
|
2252
2256
|
];
|
|
2253
|
-
|
|
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 }) => {
|
|
2254
2269
|
const svgRef = React.useRef(null);
|
|
2255
2270
|
const colorMap = React.useRef(new Map()).current;
|
|
2256
2271
|
const colorIndex = React.useRef(0);
|
|
@@ -2293,7 +2308,8 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2293
2308
|
.startAngle(d => d.x0)
|
|
2294
2309
|
.endAngle(d => d.x1)
|
|
2295
2310
|
.innerRadius(d => Math.sqrt(d.y0))
|
|
2296
|
-
.outerRadius(d => Math.sqrt(d.y1))
|
|
2311
|
+
.outerRadius(d => Math.sqrt(d.y1))
|
|
2312
|
+
.cornerRadius(3);
|
|
2297
2313
|
const tooltip = d3__namespace.select('body').append('div')
|
|
2298
2314
|
.attr('class', styles$1.tooltip)
|
|
2299
2315
|
.style('opacity', 0)
|
|
@@ -2312,11 +2328,20 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2312
2328
|
.attr('stroke', 'var(--bg-primary)')
|
|
2313
2329
|
.attr('stroke-width', 2)
|
|
2314
2330
|
.style('cursor', 'pointer')
|
|
2331
|
+
.style('filter', 'drop-shadow(0 1px 3px rgba(0,0,0,0.12))')
|
|
2315
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);
|
|
2316
2339
|
d3__namespace.select(this)
|
|
2317
2340
|
.transition()
|
|
2318
|
-
.duration(
|
|
2319
|
-
.
|
|
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);
|
|
2320
2345
|
tooltip.transition()
|
|
2321
2346
|
.duration(200)
|
|
2322
2347
|
.style('opacity', 1);
|
|
@@ -2330,10 +2355,12 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2330
2355
|
.style('left', (event.pageX + 10) + 'px')
|
|
2331
2356
|
.style('top', (event.pageY - 28) + 'px');
|
|
2332
2357
|
})
|
|
2333
|
-
.on('mouseout', function () {
|
|
2358
|
+
.on('mouseout', function (event, d) {
|
|
2334
2359
|
d3__namespace.select(this)
|
|
2335
2360
|
.transition()
|
|
2336
|
-
.duration(
|
|
2361
|
+
.duration(150)
|
|
2362
|
+
.attr('d', d => arc(d))
|
|
2363
|
+
.style('filter', 'drop-shadow(0 1px 3px rgba(0,0,0,0.12))')
|
|
2337
2364
|
.style('opacity', 1);
|
|
2338
2365
|
tooltip.transition()
|
|
2339
2366
|
.duration(500)
|
|
@@ -2343,9 +2370,32 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2343
2370
|
const angle = d.x1 - d.x0;
|
|
2344
2371
|
return angle > 0.15 && d.depth <= 2;
|
|
2345
2372
|
};
|
|
2346
|
-
|
|
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')
|
|
2347
2396
|
.data(nodes.filter(d => d.depth > 0 && d.value && d.value > 0 && shouldDisplayLabel(d)))
|
|
2348
2397
|
.enter().append('text')
|
|
2398
|
+
.attr('class', 'segment-label')
|
|
2349
2399
|
.attr('transform', d => {
|
|
2350
2400
|
const angle = (d.x0 + d.x1) / 2;
|
|
2351
2401
|
const radius = (Math.sqrt(d.y0) + Math.sqrt(d.y1)) / 2;
|
|
@@ -2355,11 +2405,32 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2355
2405
|
})
|
|
2356
2406
|
.attr('text-anchor', 'middle')
|
|
2357
2407
|
.attr('alignment-baseline', 'middle')
|
|
2358
|
-
.attr('font-size', '
|
|
2359
|
-
.attr('fill',
|
|
2360
|
-
|
|
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')
|
|
2361
2418
|
.style('pointer-events', 'none')
|
|
2362
|
-
.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
|
+
});
|
|
2363
2434
|
return () => {
|
|
2364
2435
|
tooltip.remove();
|
|
2365
2436
|
};
|
|
@@ -2370,12 +2441,23 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2370
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"};
|
|
2371
2442
|
|
|
2372
2443
|
const DEFAULT_COLORS = [
|
|
2373
|
-
'#
|
|
2374
|
-
'#
|
|
2375
|
-
'#
|
|
2376
|
-
'#
|
|
2444
|
+
'#6366f1', '#8b5cf6', '#06b6d4', '#10b981',
|
|
2445
|
+
'#f59e0b', '#ef4444', '#ec4899', '#84cc16',
|
|
2446
|
+
'#f97316', '#3b82f6', '#8b5cf6', '#14b8a6',
|
|
2447
|
+
'#f59e0b', '#ef4444', '#06b6d4', '#10b981'
|
|
2377
2448
|
];
|
|
2378
|
-
|
|
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 }) => {
|
|
2379
2461
|
const svgRef = React.useRef(null);
|
|
2380
2462
|
const radius = Math.min(width, height) / 2 - 20;
|
|
2381
2463
|
React.useEffect(() => {
|
|
@@ -2389,8 +2471,9 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2389
2471
|
.value(d => d.value)
|
|
2390
2472
|
.sort(null);
|
|
2391
2473
|
const arc = d3__namespace.arc()
|
|
2392
|
-
.innerRadius(0)
|
|
2393
|
-
.outerRadius(radius)
|
|
2474
|
+
.innerRadius(radius * 0.4)
|
|
2475
|
+
.outerRadius(radius)
|
|
2476
|
+
.cornerRadius(4);
|
|
2394
2477
|
const labelArc = d3__namespace.arc()
|
|
2395
2478
|
.innerRadius(radius * 0.7)
|
|
2396
2479
|
.outerRadius(radius * 0.7);
|
|
@@ -2408,13 +2491,19 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2408
2491
|
.attr('d', d => arc(d))
|
|
2409
2492
|
.attr('fill', (d, i) => d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length])
|
|
2410
2493
|
.attr('stroke', 'var(--bg-primary)')
|
|
2411
|
-
.attr('stroke-width',
|
|
2494
|
+
.attr('stroke-width', 3)
|
|
2412
2495
|
.style('cursor', 'pointer')
|
|
2496
|
+
.style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.15))')
|
|
2413
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);
|
|
2414
2502
|
d3__namespace.select(this)
|
|
2415
2503
|
.transition()
|
|
2416
2504
|
.duration(200)
|
|
2417
|
-
.
|
|
2505
|
+
.attr('d', d => hoverArc(d))
|
|
2506
|
+
.style('filter', 'drop-shadow(0 4px 12px rgba(0,0,0,0.25))');
|
|
2418
2507
|
tooltip.transition()
|
|
2419
2508
|
.duration(200)
|
|
2420
2509
|
.style('opacity', 1);
|
|
@@ -2427,27 +2516,59 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2427
2516
|
.style('left', (event.pageX + 10) + 'px')
|
|
2428
2517
|
.style('top', (event.pageY - 28) + 'px');
|
|
2429
2518
|
})
|
|
2430
|
-
.on('mouseout', function () {
|
|
2519
|
+
.on('mouseout', function (event, d) {
|
|
2431
2520
|
d3__namespace.select(this)
|
|
2432
2521
|
.transition()
|
|
2433
2522
|
.duration(200)
|
|
2434
|
-
.
|
|
2523
|
+
.attr('d', d => arc(d))
|
|
2524
|
+
.style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.15))');
|
|
2435
2525
|
tooltip.transition()
|
|
2436
2526
|
.duration(500)
|
|
2437
2527
|
.style('opacity', 0);
|
|
2438
2528
|
});
|
|
2439
|
-
|
|
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)
|
|
2440
2551
|
.append('text')
|
|
2441
2552
|
.attr('transform', d => `translate(${labelArc.centroid(d)})`)
|
|
2442
2553
|
.attr('text-anchor', 'middle')
|
|
2443
2554
|
.attr('alignment-baseline', 'middle')
|
|
2444
|
-
.attr('font-size', '
|
|
2445
|
-
.attr('fill',
|
|
2446
|
-
.
|
|
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')
|
|
2447
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
|
+
})
|
|
2448
2569
|
.text(d => {
|
|
2449
2570
|
const percentage = ((d.data.value / total) * 100);
|
|
2450
|
-
return percentage >
|
|
2571
|
+
return percentage > 8 ? `${percentage.toFixed(0)}%` : '';
|
|
2451
2572
|
});
|
|
2452
2573
|
return () => {
|
|
2453
2574
|
tooltip.remove();
|