@stfrigerio/sito-template 0.1.7 → 0.1.9
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/atoms/ArrayInput/ArrayInput.d.ts +5 -0
- package/dist/components/atoms/ArrayInput/ArrayInput.d.ts.map +1 -1
- package/dist/components/atoms/Toggle/Toggle.d.ts +4 -0
- package/dist/components/atoms/Toggle/Toggle.d.ts.map +1 -1
- package/dist/components/atoms/Toggle/Toggle.stories.d.ts +1 -0
- package/dist/components/atoms/Toggle/Toggle.stories.d.ts.map +1 -1
- 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 +182 -46
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +182 -46
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -219,7 +219,7 @@ function TextInput({ label, value, onChange, type = "text", onFocus, onBlur, pla
|
|
|
219
219
|
return (jsxRuntime.jsxs("div", { className: getContainerClassName(), children: [jsxRuntime.jsxs("label", { htmlFor: inputId, children: [label, required && jsxRuntime.jsx("span", { className: styles$l.required, children: "*" })] }), jsxRuntime.jsxs("div", { style: { position: 'relative' }, children: [icon && jsxRuntime.jsx("div", { className: styles$l.inputIcon, children: icon }), jsxRuntime.jsx("input", { id: inputId, type: type, value: value, onChange: (e) => onChange(e.target.value), onFocus: onFocus, onBlur: onBlur, placeholder: placeholder, className: error ? styles$l.inputError : '', "aria-invalid": !!error, "aria-describedby": error ? `${inputId}-error` : undefined, disabled: disabled || loading, maxLength: maxLength, autoComplete: autoComplete }), actionButton && (jsxRuntime.jsx("button", { type: "button", className: styles$l.actionButton, onClick: actionButton.onClick, disabled: disabled || loading, children: actionButton.label }))] }), error && (jsxRuntime.jsx("span", { id: `${inputId}-error`, className: styles$l.errorMessage, children: error }))] }));
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
var styles$k = {"arrayInput":"ArrayInput-module_arrayInput__FNrd2","arrayInputLabel":"ArrayInput-module_arrayInputLabel__7Rpkj","arrayInputItem":"ArrayInput-module_arrayInputItem__eSH-6","inputWrapper":"ArrayInput-module_inputWrapper__i-MB-","input":"ArrayInput-module_input__792ru","complexItem":"ArrayInput-module_complexItem__iX3v6","fieldsWrapper":"ArrayInput-module_fieldsWrapper__fzqvn"};
|
|
222
|
+
var styles$k = {"arrayInput":"ArrayInput-module_arrayInput__FNrd2","arrayInputLabel":"ArrayInput-module_arrayInputLabel__7Rpkj","arrayInputItem":"ArrayInput-module_arrayInputItem__eSH-6","inputWrapper":"ArrayInput-module_inputWrapper__i-MB-","input":"ArrayInput-module_input__792ru","complexItem":"ArrayInput-module_complexItem__iX3v6","fieldsWrapper":"ArrayInput-module_fieldsWrapper__fzqvn","removeButton":"ArrayInput-module_removeButton__khhdR","addButton":"ArrayInput-module_addButton__10o-9"};
|
|
223
223
|
|
|
224
224
|
/**
|
|
225
225
|
* ArrayInput component - Versatile dynamic list manager
|
|
@@ -259,7 +259,7 @@ function ArrayInput(props) {
|
|
|
259
259
|
return jsxRuntime.jsx(SimpleArrayInput, { ...props });
|
|
260
260
|
}
|
|
261
261
|
// Simple string array implementation
|
|
262
|
-
function SimpleArrayInput({ label, values, onChange, placeholder }) {
|
|
262
|
+
function SimpleArrayInput({ label, values, onChange, placeholder, itemStyle, inputStyle }) {
|
|
263
263
|
const handleChange = (index, value) => {
|
|
264
264
|
const newValues = [...values];
|
|
265
265
|
newValues[index] = value;
|
|
@@ -272,10 +272,14 @@ function SimpleArrayInput({ label, values, onChange, placeholder }) {
|
|
|
272
272
|
const newValues = values.filter((_, i) => i !== index);
|
|
273
273
|
onChange(newValues);
|
|
274
274
|
};
|
|
275
|
-
return (jsxRuntime.jsxs("div", { className: styles$k.arrayInput, children: [jsxRuntime.jsx("h3", { className: styles$k.arrayInputLabel, children: label }),
|
|
275
|
+
return (jsxRuntime.jsxs("div", { className: styles$k.arrayInput, children: [jsxRuntime.jsx("h3", { className: styles$k.arrayInputLabel, children: label }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx(framerMotion.AnimatePresence, { children: values.map((value, index) => (jsxRuntime.jsxs(framerMotion.motion.div, { className: styles$k.arrayInputItem, style: itemStyle, initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0 }, transition: {
|
|
276
|
+
duration: 0.3,
|
|
277
|
+
ease: "easeInOut",
|
|
278
|
+
layout: { duration: 0.2 }
|
|
279
|
+
}, children: [jsxRuntime.jsx("div", { className: styles$k.inputWrapper, children: jsxRuntime.jsx("input", { type: "text", value: value, onChange: (e) => handleChange(index, e.target.value), placeholder: placeholder, className: styles$k.input, style: inputStyle }) }), jsxRuntime.jsx(Button, { variant: "ghost", size: "small", onClick: () => handleRemove(index), "aria-label": "Remove item", className: styles$k.removeButton, children: jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) })] }, `item-${index}`))) }) }), jsxRuntime.jsxs(Button, { variant: "primary", size: "small", onClick: handleAdd, className: styles$k.addButton, children: ["Add ", label] })] }));
|
|
276
280
|
}
|
|
277
281
|
// Complex object array implementation
|
|
278
|
-
function ComplexArrayInput({ label, values, onChange, fields, getKey }) {
|
|
282
|
+
function ComplexArrayInput({ label, values, onChange, fields, getKey, itemStyle, inputStyle }) {
|
|
279
283
|
const handleChange = (index, field, value) => {
|
|
280
284
|
const newValues = [...values];
|
|
281
285
|
newValues[index] = { ...newValues[index], [field]: value };
|
|
@@ -297,7 +301,11 @@ function ComplexArrayInput({ label, values, onChange, fields, getKey }) {
|
|
|
297
301
|
// Generate key from all field values
|
|
298
302
|
return fields.map(f => item[f.name] || '').join('-') + `-${index}`;
|
|
299
303
|
};
|
|
300
|
-
return (jsxRuntime.jsxs("div", { className: styles$k.arrayInput, children: [jsxRuntime.jsx("h3", { className: styles$k.arrayInputLabel, children: label }), values.map((value, index) => (jsxRuntime.jsxs(
|
|
304
|
+
return (jsxRuntime.jsxs("div", { className: styles$k.arrayInput, children: [jsxRuntime.jsx("h3", { className: styles$k.arrayInputLabel, children: label }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx(framerMotion.AnimatePresence, { children: values.map((value, index) => (jsxRuntime.jsxs(framerMotion.motion.div, { className: `${styles$k.arrayInputItem} ${fields.length > 1 ? styles$k.complexItem : ''}`, style: itemStyle, initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0 }, transition: {
|
|
305
|
+
duration: 0.3,
|
|
306
|
+
ease: "easeInOut",
|
|
307
|
+
layout: { duration: 0.2 }
|
|
308
|
+
}, children: [jsxRuntime.jsx("div", { className: styles$k.fieldsWrapper, children: fields.map((field) => (jsxRuntime.jsx("div", { style: inputStyle, children: jsxRuntime.jsx(TextInput, { value: value[field.name] || '', onChange: (newValue) => handleChange(index, field.name, newValue), label: field.label, type: field.type, placeholder: field.placeholder }) }, field.name))) }), jsxRuntime.jsx(Button, { variant: "ghost", size: "small", onClick: () => handleRemove(index), "aria-label": "Remove item", className: styles$k.removeButton, children: jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) })] }, generateKey(value, index)))) }) }), jsxRuntime.jsxs(Button, { variant: "primary", size: "small", onClick: handleAdd, className: styles$k.addButton, children: ["Add ", label] })] }));
|
|
301
309
|
}
|
|
302
310
|
|
|
303
311
|
var styles$j = {"checkboxLabel":"Checkbox-module_checkboxLabel__4tBVg","checkbox":"Checkbox-module_checkbox__BbJul","checkboxText":"Checkbox-module_checkboxText__oJsc9"};
|
|
@@ -846,8 +854,15 @@ var styles$e = {"toggleContainer":"Toggle-module_toggleContainer__QxqQb","toggle
|
|
|
846
854
|
* @returns {JSX.Element} The rendered Toggle component
|
|
847
855
|
*/
|
|
848
856
|
function Toggle(props) {
|
|
849
|
-
const { isOn, onToggle, leftLabel, rightLabel, leftIcon, rightIcon } = props;
|
|
850
|
-
|
|
857
|
+
const { isOn, onToggle, leftLabel, rightLabel, leftIcon, rightIcon, className, style } = props;
|
|
858
|
+
// Ensure content stays centered by merging styles
|
|
859
|
+
const buttonStyle = {
|
|
860
|
+
display: 'flex',
|
|
861
|
+
alignItems: 'center',
|
|
862
|
+
justifyContent: 'center',
|
|
863
|
+
...style
|
|
864
|
+
};
|
|
865
|
+
return (jsxRuntime.jsxs("div", { className: `${styles$e.toggleContainer} ${className || ''}`, children: [jsxRuntime.jsxs("button", { className: `${styles$e.toggleButton} ${!isOn ? styles$e.active : ''}`, onClick: () => onToggle(false), style: buttonStyle, children: [leftIcon, leftLabel] }), jsxRuntime.jsxs("button", { className: `${styles$e.toggleButton} ${isOn ? styles$e.active : ''}`, onClick: () => onToggle(true), style: buttonStyle, children: [rightIcon, rightLabel] })] }));
|
|
851
866
|
}
|
|
852
867
|
|
|
853
868
|
var styles$d = {"container":"NumberStepper-module_container__WSGlU","header":"NumberStepper-module_header__qXI1Y","icon":"NumberStepper-module_icon__vHgsw","label":"NumberStepper-module_label__AYr3g","stepper":"NumberStepper-module_stepper__oQhTp","disabled":"NumberStepper-module_disabled__kGB-g","button":"NumberStepper-module_button__YcjRt","buttonIcon":"NumberStepper-module_buttonIcon__odXec","valueContainer":"NumberStepper-module_valueContainer__87w2D","valueWrapper":"NumberStepper-module_valueWrapper__TH65N","value":"NumberStepper-module_value__BxJeD","limits":"NumberStepper-module_limits__-UrRE","limit":"NumberStepper-module_limit__7nbIP","small":"NumberStepper-module_small__P-k96","large":"NumberStepper-module_large__Lz6lk","outlined":"NumberStepper-module_outlined__CIXv7","filled":"NumberStepper-module_filled__IxOg-","pulse":"NumberStepper-module_pulse__51oUo"};
|
|
@@ -1199,7 +1214,8 @@ const EditFAB = ({ canEdit, isEditMode, hasUnsavedChanges = false, isSaving = fa
|
|
|
1199
1214
|
|
|
1200
1215
|
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
1216
|
|
|
1202
|
-
|
|
1217
|
+
// Default filter options for backwards compatibility
|
|
1218
|
+
const defaultFilterOptions = [
|
|
1203
1219
|
{ value: 'all', label: 'All', icon: FiSearch },
|
|
1204
1220
|
{ value: 'projects', label: 'Projects', icon: FiFolder },
|
|
1205
1221
|
{ value: 'clients', label: 'Clients', icon: FiUsers },
|
|
@@ -1207,16 +1223,18 @@ const filterOptions = [
|
|
|
1207
1223
|
{ value: 'interactions', label: 'Interactions', icon: FiMessageSquare },
|
|
1208
1224
|
{ value: 'team', label: 'Team', icon: FiUserPlus },
|
|
1209
1225
|
];
|
|
1210
|
-
const
|
|
1226
|
+
const defaultEntityIcons = {
|
|
1211
1227
|
projects: FiFolder,
|
|
1212
1228
|
clients: FiUsers,
|
|
1213
1229
|
contacts: FiBook,
|
|
1214
1230
|
interactions: FiMessageSquare,
|
|
1215
1231
|
team: FiUserPlus,
|
|
1216
1232
|
};
|
|
1217
|
-
const SearchBar = ({ className, placeholder = "Search (Ctrl+Space)...", onSearch, onResultClick, onClear, debounceDelay = 300, minSearchLength = 2, showFilter = true, enableKeyboardShortcut = true }) => {
|
|
1233
|
+
const SearchBar = ({ className, placeholder = "Search (Ctrl+Space)...", onSearch, onResultClick, onClear, debounceDelay = 300, minSearchLength = 2, showFilter = true, enableKeyboardShortcut = true, filterOptions: customFilterOptions, entityIcons: customEntityIcons }) => {
|
|
1234
|
+
const filterOptions = customFilterOptions ?? defaultFilterOptions;
|
|
1235
|
+
const entityIcons = customEntityIcons ?? defaultEntityIcons;
|
|
1218
1236
|
const [query, setQuery] = React.useState('');
|
|
1219
|
-
const [filter, setFilter] = React.useState('all');
|
|
1237
|
+
const [filter, setFilter] = React.useState(filterOptions[0]?.value ?? 'all');
|
|
1220
1238
|
const [results, setResults] = React.useState([]);
|
|
1221
1239
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
1222
1240
|
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
|
|
@@ -1545,15 +1563,16 @@ function SiJira (props) {
|
|
|
1545
1563
|
|
|
1546
1564
|
var styles$6 = {"tabs":"Tabs-module_tabs__Vlvn7","tab":"Tabs-module_tab__uQKim","tabIcon":"Tabs-module_tabIcon__AgN-O"};
|
|
1547
1565
|
|
|
1548
|
-
|
|
1566
|
+
// Default tabs for backwards compatibility
|
|
1567
|
+
const defaultTabs = [
|
|
1549
1568
|
{ id: 'details', icon: FiInfo, label: 'Dettagli' },
|
|
1550
1569
|
{ id: 'github', icon: FiGithub, label: 'GitHub' },
|
|
1551
1570
|
{ id: 'jira', icon: SiJira, label: 'Jira' },
|
|
1552
1571
|
{ id: 'functional', icon: FiInfo, label: 'Analisi funzionale' }
|
|
1553
1572
|
];
|
|
1554
|
-
const Tabs = ({ activeTab, onTabChange }) => {
|
|
1555
|
-
|
|
1556
|
-
|
|
1573
|
+
const Tabs = ({ activeTab, onTabChange, tabs: customTabs, className = '' }) => {
|
|
1574
|
+
const tabs = customTabs ?? defaultTabs;
|
|
1575
|
+
return (jsxRuntime.jsx("div", { className: `${styles$6.tabs} ${className}`, children: tabs.map((tab) => {
|
|
1557
1576
|
const isActive = activeTab === tab.id;
|
|
1558
1577
|
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
1578
|
rotate: isActive ? [0, -10, 10, -5, 5, 0] : 0,
|
|
@@ -1562,7 +1581,7 @@ const Tabs = ({ activeTab, onTabChange }) => {
|
|
|
1562
1581
|
duration: 0.5,
|
|
1563
1582
|
ease: 'easeInOut'
|
|
1564
1583
|
}
|
|
1565
|
-
}, children: jsxRuntime.jsx(
|
|
1584
|
+
}, 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
1585
|
}) }));
|
|
1567
1586
|
};
|
|
1568
1587
|
|
|
@@ -2246,11 +2265,22 @@ const BooleansHeatmap = ({ data, habitName, width = 800, height = 200, habitColo
|
|
|
2246
2265
|
var styles$1 = {"container":"SunburstChart-module_container__w1ZYc","title":"SunburstChart-module_title__T6Ak7","chart":"SunburstChart-module_chart__BFM6E","tooltip":"SunburstChart-module_tooltip__TuTAN"};
|
|
2247
2266
|
|
|
2248
2267
|
const COLOR_PALETTE = [
|
|
2249
|
-
'#
|
|
2250
|
-
'#
|
|
2251
|
-
'#
|
|
2268
|
+
'#6366f1', '#8b5cf6', '#06b6d4', '#10b981',
|
|
2269
|
+
'#f59e0b', '#ef4444', '#ec4899', '#84cc16',
|
|
2270
|
+
'#f97316', '#3b82f6', '#14b8a6', '#f59e0b'
|
|
2252
2271
|
];
|
|
2253
|
-
|
|
2272
|
+
// Calculate text color based on background luminance for optimal contrast
|
|
2273
|
+
const getTextColor$1 = (backgroundColor) => {
|
|
2274
|
+
const color = d3__namespace.color(backgroundColor);
|
|
2275
|
+
if (!color)
|
|
2276
|
+
return '#ffffff';
|
|
2277
|
+
const rgb = color.rgb();
|
|
2278
|
+
// Calculate relative luminance using WCAG formula
|
|
2279
|
+
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
|
|
2280
|
+
// Return white text for dark backgrounds, black for light backgrounds
|
|
2281
|
+
return luminance > 0.5 ? '#000000' : '#ffffff';
|
|
2282
|
+
};
|
|
2283
|
+
const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Chart', tagColors = {}, unit = 'items', centerLabel }) => {
|
|
2254
2284
|
const svgRef = React.useRef(null);
|
|
2255
2285
|
const colorMap = React.useRef(new Map()).current;
|
|
2256
2286
|
const colorIndex = React.useRef(0);
|
|
@@ -2293,7 +2323,8 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2293
2323
|
.startAngle(d => d.x0)
|
|
2294
2324
|
.endAngle(d => d.x1)
|
|
2295
2325
|
.innerRadius(d => Math.sqrt(d.y0))
|
|
2296
|
-
.outerRadius(d => Math.sqrt(d.y1))
|
|
2326
|
+
.outerRadius(d => Math.sqrt(d.y1))
|
|
2327
|
+
.cornerRadius(3);
|
|
2297
2328
|
const tooltip = d3__namespace.select('body').append('div')
|
|
2298
2329
|
.attr('class', styles$1.tooltip)
|
|
2299
2330
|
.style('opacity', 0)
|
|
@@ -2312,11 +2343,20 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2312
2343
|
.attr('stroke', 'var(--bg-primary)')
|
|
2313
2344
|
.attr('stroke-width', 2)
|
|
2314
2345
|
.style('cursor', 'pointer')
|
|
2346
|
+
.style('filter', 'drop-shadow(0 1px 3px rgba(0,0,0,0.12))')
|
|
2315
2347
|
.on('mouseover', function (event, d) {
|
|
2348
|
+
const hoverArc = d3__namespace.arc()
|
|
2349
|
+
.startAngle(d => d.x0)
|
|
2350
|
+
.endAngle(d => d.x1)
|
|
2351
|
+
.innerRadius(d => Math.sqrt(d.y0) - 2)
|
|
2352
|
+
.outerRadius(d => Math.sqrt(d.y1) + 4)
|
|
2353
|
+
.cornerRadius(3);
|
|
2316
2354
|
d3__namespace.select(this)
|
|
2317
2355
|
.transition()
|
|
2318
|
-
.duration(
|
|
2319
|
-
.
|
|
2356
|
+
.duration(150)
|
|
2357
|
+
.attr('d', d => hoverArc(d))
|
|
2358
|
+
.style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.2))')
|
|
2359
|
+
.style('opacity', 0.9);
|
|
2320
2360
|
tooltip.transition()
|
|
2321
2361
|
.duration(200)
|
|
2322
2362
|
.style('opacity', 1);
|
|
@@ -2330,10 +2370,12 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2330
2370
|
.style('left', (event.pageX + 10) + 'px')
|
|
2331
2371
|
.style('top', (event.pageY - 28) + 'px');
|
|
2332
2372
|
})
|
|
2333
|
-
.on('mouseout', function () {
|
|
2373
|
+
.on('mouseout', function (event, d) {
|
|
2334
2374
|
d3__namespace.select(this)
|
|
2335
2375
|
.transition()
|
|
2336
|
-
.duration(
|
|
2376
|
+
.duration(150)
|
|
2377
|
+
.attr('d', d => arc(d))
|
|
2378
|
+
.style('filter', 'drop-shadow(0 1px 3px rgba(0,0,0,0.12))')
|
|
2337
2379
|
.style('opacity', 1);
|
|
2338
2380
|
tooltip.transition()
|
|
2339
2381
|
.duration(500)
|
|
@@ -2343,9 +2385,32 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2343
2385
|
const angle = d.x1 - d.x0;
|
|
2344
2386
|
return angle > 0.15 && d.depth <= 2;
|
|
2345
2387
|
};
|
|
2346
|
-
|
|
2388
|
+
// Calculate average background color for center text contrast
|
|
2389
|
+
const allSegments = nodes.filter(d => d.depth === 1);
|
|
2390
|
+
const avgColor = allSegments.length > 0 ? d3__namespace.interpolateRgb.gamma(2.2)(...allSegments.map(d => getColor(d.data.name, 1)))(0.5) : '#ffffff';
|
|
2391
|
+
const centerTextColor = getTextColor$1(avgColor);
|
|
2392
|
+
// Add center text
|
|
2393
|
+
g.append('text')
|
|
2394
|
+
.attr('text-anchor', 'middle')
|
|
2395
|
+
.attr('alignment-baseline', 'middle')
|
|
2396
|
+
.attr('font-size', '18px')
|
|
2397
|
+
.attr('font-weight', 'bold')
|
|
2398
|
+
.attr('fill', centerTextColor)
|
|
2399
|
+
.style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 3px rgba(0,0,0,0.5)' : '0 1px 3px rgba(255,255,255,0.5)')
|
|
2400
|
+
.text(centerLabel || data.name || 'Total');
|
|
2401
|
+
g.append('text')
|
|
2402
|
+
.attr('text-anchor', 'middle')
|
|
2403
|
+
.attr('alignment-baseline', 'middle')
|
|
2404
|
+
.attr('y', 20)
|
|
2405
|
+
.attr('font-size', '14px')
|
|
2406
|
+
.attr('font-weight', '500')
|
|
2407
|
+
.attr('fill', centerTextColor)
|
|
2408
|
+
.style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 2px rgba(0,0,0,0.4)' : '0 1px 2px rgba(255,255,255,0.4)')
|
|
2409
|
+
.text(`${(root.value || 0).toLocaleString()} ${unit}`);
|
|
2410
|
+
g.selectAll('text.segment-label')
|
|
2347
2411
|
.data(nodes.filter(d => d.depth > 0 && d.value && d.value > 0 && shouldDisplayLabel(d)))
|
|
2348
2412
|
.enter().append('text')
|
|
2413
|
+
.attr('class', 'segment-label')
|
|
2349
2414
|
.attr('transform', d => {
|
|
2350
2415
|
const angle = (d.x0 + d.x1) / 2;
|
|
2351
2416
|
const radius = (Math.sqrt(d.y0) + Math.sqrt(d.y1)) / 2;
|
|
@@ -2355,11 +2420,32 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2355
2420
|
})
|
|
2356
2421
|
.attr('text-anchor', 'middle')
|
|
2357
2422
|
.attr('alignment-baseline', 'middle')
|
|
2358
|
-
.attr('font-size', '
|
|
2359
|
-
.attr('fill',
|
|
2360
|
-
|
|
2423
|
+
.attr('font-size', d => d.depth === 1 ? '13px' : '11px')
|
|
2424
|
+
.attr('fill', d => {
|
|
2425
|
+
let ancestor = d;
|
|
2426
|
+
while (ancestor.depth > 1 && ancestor.parent) {
|
|
2427
|
+
ancestor = ancestor.parent;
|
|
2428
|
+
}
|
|
2429
|
+
const segmentColor = getColor(ancestor.data.name, d.depth);
|
|
2430
|
+
return getTextColor$1(segmentColor);
|
|
2431
|
+
})
|
|
2432
|
+
.attr('font-weight', '600')
|
|
2361
2433
|
.style('pointer-events', 'none')
|
|
2362
|
-
.text
|
|
2434
|
+
.style('text-shadow', d => {
|
|
2435
|
+
let ancestor = d;
|
|
2436
|
+
while (ancestor.depth > 1 && ancestor.parent) {
|
|
2437
|
+
ancestor = ancestor.parent;
|
|
2438
|
+
}
|
|
2439
|
+
const segmentColor = getColor(ancestor.data.name, d.depth);
|
|
2440
|
+
const textColor = getTextColor$1(segmentColor);
|
|
2441
|
+
// Use contrasting shadow color
|
|
2442
|
+
const shadowColor = textColor === '#ffffff' ? 'rgba(0,0,0,0.5)' : 'rgba(255,255,255,0.5)';
|
|
2443
|
+
return `0 1px 2px ${shadowColor}`;
|
|
2444
|
+
})
|
|
2445
|
+
.text(d => {
|
|
2446
|
+
const maxLength = d.depth === 1 ? 12 : 8;
|
|
2447
|
+
return d.data.name.substring(0, maxLength);
|
|
2448
|
+
});
|
|
2363
2449
|
return () => {
|
|
2364
2450
|
tooltip.remove();
|
|
2365
2451
|
};
|
|
@@ -2370,12 +2456,23 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
|
|
|
2370
2456
|
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
2457
|
|
|
2372
2458
|
const DEFAULT_COLORS = [
|
|
2373
|
-
'#
|
|
2374
|
-
'#
|
|
2375
|
-
'#
|
|
2376
|
-
'#
|
|
2459
|
+
'#6366f1', '#8b5cf6', '#06b6d4', '#10b981',
|
|
2460
|
+
'#f59e0b', '#ef4444', '#ec4899', '#84cc16',
|
|
2461
|
+
'#f97316', '#3b82f6', '#8b5cf6', '#14b8a6',
|
|
2462
|
+
'#f59e0b', '#ef4444', '#06b6d4', '#10b981'
|
|
2377
2463
|
];
|
|
2378
|
-
|
|
2464
|
+
// Calculate text color based on background luminance for optimal contrast
|
|
2465
|
+
const getTextColor = (backgroundColor) => {
|
|
2466
|
+
const color = d3__namespace.color(backgroundColor);
|
|
2467
|
+
if (!color)
|
|
2468
|
+
return '#ffffff';
|
|
2469
|
+
const rgb = color.rgb();
|
|
2470
|
+
// Calculate relative luminance using WCAG formula
|
|
2471
|
+
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
|
|
2472
|
+
// Return white text for dark backgrounds, black for light backgrounds
|
|
2473
|
+
return luminance > 0.5 ? '#000000' : '#ffffff';
|
|
2474
|
+
};
|
|
2475
|
+
const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', showLegend = true, unit = 'items', centerLabel }) => {
|
|
2379
2476
|
const svgRef = React.useRef(null);
|
|
2380
2477
|
const radius = Math.min(width, height) / 2 - 20;
|
|
2381
2478
|
React.useEffect(() => {
|
|
@@ -2389,8 +2486,9 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2389
2486
|
.value(d => d.value)
|
|
2390
2487
|
.sort(null);
|
|
2391
2488
|
const arc = d3__namespace.arc()
|
|
2392
|
-
.innerRadius(0)
|
|
2393
|
-
.outerRadius(radius)
|
|
2489
|
+
.innerRadius(radius * 0.4)
|
|
2490
|
+
.outerRadius(radius)
|
|
2491
|
+
.cornerRadius(4);
|
|
2394
2492
|
const labelArc = d3__namespace.arc()
|
|
2395
2493
|
.innerRadius(radius * 0.7)
|
|
2396
2494
|
.outerRadius(radius * 0.7);
|
|
@@ -2408,13 +2506,19 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2408
2506
|
.attr('d', d => arc(d))
|
|
2409
2507
|
.attr('fill', (d, i) => d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length])
|
|
2410
2508
|
.attr('stroke', 'var(--bg-primary)')
|
|
2411
|
-
.attr('stroke-width',
|
|
2509
|
+
.attr('stroke-width', 3)
|
|
2412
2510
|
.style('cursor', 'pointer')
|
|
2511
|
+
.style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.15))')
|
|
2413
2512
|
.on('mouseover', function (event, d) {
|
|
2513
|
+
const hoverArc = d3__namespace.arc()
|
|
2514
|
+
.innerRadius(radius * 0.4)
|
|
2515
|
+
.outerRadius(radius * 1.05)
|
|
2516
|
+
.cornerRadius(4);
|
|
2414
2517
|
d3__namespace.select(this)
|
|
2415
2518
|
.transition()
|
|
2416
2519
|
.duration(200)
|
|
2417
|
-
.
|
|
2520
|
+
.attr('d', d => hoverArc(d))
|
|
2521
|
+
.style('filter', 'drop-shadow(0 4px 12px rgba(0,0,0,0.25))');
|
|
2418
2522
|
tooltip.transition()
|
|
2419
2523
|
.duration(200)
|
|
2420
2524
|
.style('opacity', 1);
|
|
@@ -2427,27 +2531,59 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
|
|
|
2427
2531
|
.style('left', (event.pageX + 10) + 'px')
|
|
2428
2532
|
.style('top', (event.pageY - 28) + 'px');
|
|
2429
2533
|
})
|
|
2430
|
-
.on('mouseout', function () {
|
|
2534
|
+
.on('mouseout', function (event, d) {
|
|
2431
2535
|
d3__namespace.select(this)
|
|
2432
2536
|
.transition()
|
|
2433
2537
|
.duration(200)
|
|
2434
|
-
.
|
|
2538
|
+
.attr('d', d => arc(d))
|
|
2539
|
+
.style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.15))');
|
|
2435
2540
|
tooltip.transition()
|
|
2436
2541
|
.duration(500)
|
|
2437
2542
|
.style('opacity', 0);
|
|
2438
2543
|
});
|
|
2439
|
-
|
|
2544
|
+
// Calculate average background color for center text contrast
|
|
2545
|
+
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';
|
|
2546
|
+
const centerTextColor = getTextColor(avgColor);
|
|
2547
|
+
// Add center text for donut
|
|
2548
|
+
g.append('text')
|
|
2549
|
+
.attr('text-anchor', 'middle')
|
|
2550
|
+
.attr('alignment-baseline', 'middle')
|
|
2551
|
+
.attr('font-size', '20px')
|
|
2552
|
+
.attr('font-weight', 'bold')
|
|
2553
|
+
.attr('fill', centerTextColor)
|
|
2554
|
+
.style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 3px rgba(0,0,0,0.5)' : '0 1px 3px rgba(255,255,255,0.5)')
|
|
2555
|
+
.text(centerLabel || 'Total');
|
|
2556
|
+
g.append('text')
|
|
2557
|
+
.attr('text-anchor', 'middle')
|
|
2558
|
+
.attr('alignment-baseline', 'middle')
|
|
2559
|
+
.attr('y', 22)
|
|
2560
|
+
.attr('font-size', '16px')
|
|
2561
|
+
.attr('font-weight', '600')
|
|
2562
|
+
.attr('fill', centerTextColor)
|
|
2563
|
+
.style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 2px rgba(0,0,0,0.4)' : '0 1px 2px rgba(255,255,255,0.4)')
|
|
2564
|
+
.text(`${total.toLocaleString()} ${unit}`);
|
|
2565
|
+
arcs.filter(d => (d.endAngle - d.startAngle) > 0.2)
|
|
2440
2566
|
.append('text')
|
|
2441
2567
|
.attr('transform', d => `translate(${labelArc.centroid(d)})`)
|
|
2442
2568
|
.attr('text-anchor', 'middle')
|
|
2443
2569
|
.attr('alignment-baseline', 'middle')
|
|
2444
|
-
.attr('font-size', '
|
|
2445
|
-
.attr('fill',
|
|
2446
|
-
.
|
|
2570
|
+
.attr('font-size', '13px')
|
|
2571
|
+
.attr('fill', (d, i) => {
|
|
2572
|
+
const segmentColor = d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length];
|
|
2573
|
+
return getTextColor(segmentColor);
|
|
2574
|
+
})
|
|
2575
|
+
.attr('font-weight', '600')
|
|
2447
2576
|
.style('pointer-events', 'none')
|
|
2577
|
+
.style('text-shadow', (d, i) => {
|
|
2578
|
+
const segmentColor = d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length];
|
|
2579
|
+
const textColor = getTextColor(segmentColor);
|
|
2580
|
+
// Use contrasting shadow color
|
|
2581
|
+
const shadowColor = textColor === '#ffffff' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.4)';
|
|
2582
|
+
return `0 1px 2px ${shadowColor}`;
|
|
2583
|
+
})
|
|
2448
2584
|
.text(d => {
|
|
2449
2585
|
const percentage = ((d.data.value / total) * 100);
|
|
2450
|
-
return percentage >
|
|
2586
|
+
return percentage > 8 ? `${percentage.toFixed(0)}%` : '';
|
|
2451
2587
|
});
|
|
2452
2588
|
return () => {
|
|
2453
2589
|
tooltip.remove();
|