@aiaiai-pt/design-system 0.28.0 → 0.29.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.
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
-->
|
|
31
31
|
<script module>
|
|
32
32
|
/**
|
|
33
|
-
* @typedef {{ id: string, label: string, description?: string, active: boolean }} PrefItem
|
|
33
|
+
* @typedef {{ id: string, label: string, description?: string, active: boolean, group?: string }} PrefItem
|
|
34
34
|
*/
|
|
35
35
|
</script>
|
|
36
36
|
|
|
@@ -54,30 +54,56 @@
|
|
|
54
54
|
class: className = "",
|
|
55
55
|
...rest
|
|
56
56
|
} = $props();
|
|
57
|
+
|
|
58
|
+
// Group rows by their optional `group` (order preserved). Items with no
|
|
59
|
+
// `group` fall in the leading unnamed group, which renders WITHOUT a header —
|
|
60
|
+
// so a flat `items` list (no group set) renders exactly as before
|
|
61
|
+
// (backward-compatible). A named group renders an <h3> section header above
|
|
62
|
+
// its bordered list (e.g. "Edição" / "Categoria" / "Freguesia").
|
|
63
|
+
const groups = $derived.by(() => {
|
|
64
|
+
/** @type {string[]} */
|
|
65
|
+
const order = [];
|
|
66
|
+
/** @type {Map<string, PrefItem[]>} */
|
|
67
|
+
const byGroup = new Map();
|
|
68
|
+
for (const item of items) {
|
|
69
|
+
const g = item.group ?? "";
|
|
70
|
+
if (!byGroup.has(g)) {
|
|
71
|
+
byGroup.set(g, []);
|
|
72
|
+
order.push(g);
|
|
73
|
+
}
|
|
74
|
+
byGroup.get(g)?.push(item);
|
|
75
|
+
}
|
|
76
|
+
return order.map((g) => ({ group: g, items: byGroup.get(g) ?? [] }));
|
|
77
|
+
});
|
|
57
78
|
</script>
|
|
58
79
|
|
|
59
80
|
<section class="notification-prefs {className}" aria-label={label} {...rest}>
|
|
60
81
|
{#if items.length > 0}
|
|
61
|
-
|
|
62
|
-
{#
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
{#each groups as grp (grp.group)}
|
|
83
|
+
{#if grp.group}
|
|
84
|
+
<h3 class="notification-prefs-group">{grp.group}</h3>
|
|
85
|
+
{/if}
|
|
86
|
+
<List variant="bordered">
|
|
87
|
+
{#each grp.items as item (item.id)}
|
|
88
|
+
<ListItem>
|
|
89
|
+
{#snippet leading()}
|
|
90
|
+
<span class="notification-prefs-label">{item.label}</span>
|
|
91
|
+
{#if item.description}
|
|
92
|
+
<span class="notification-prefs-desc">{item.description}</span>
|
|
93
|
+
{/if}
|
|
94
|
+
{/snippet}
|
|
95
|
+
{#snippet trailing()}
|
|
96
|
+
<Toggle
|
|
97
|
+
checked={item.active}
|
|
98
|
+
disabled={busyId === item.id}
|
|
99
|
+
aria-label={item.label}
|
|
100
|
+
onchange={(next) => onToggle?.(item.id, next)}
|
|
101
|
+
/>
|
|
102
|
+
{/snippet}
|
|
103
|
+
</ListItem>
|
|
104
|
+
{/each}
|
|
105
|
+
</List>
|
|
106
|
+
{/each}
|
|
81
107
|
{:else}
|
|
82
108
|
<p class="notification-prefs-empty">{emptyText}</p>
|
|
83
109
|
{/if}
|
|
@@ -90,6 +116,18 @@
|
|
|
90
116
|
gap: var(--space-md);
|
|
91
117
|
}
|
|
92
118
|
|
|
119
|
+
.notification-prefs-group {
|
|
120
|
+
font-family: var(--type-heading-font, var(--type-body-font));
|
|
121
|
+
font-size: var(--type-body-size);
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
color: var(--color-text);
|
|
124
|
+
margin: var(--space-sm) 0 calc(-1 * var(--space-xs)) 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.notification-prefs-group:first-child {
|
|
128
|
+
margin-top: 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
93
131
|
.notification-prefs-label {
|
|
94
132
|
font-family: var(--type-body-font);
|
|
95
133
|
font-size: var(--type-body-size);
|