@gnome-ui/react 1.40.1 → 1.41.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/README.md +42 -0
- package/dist/components/AvatarRotator/AvatarRotator.cjs +2 -0
- package/dist/components/AvatarRotator/AvatarRotator.cjs.map +1 -0
- package/dist/components/AvatarRotator/AvatarRotator.d.ts +36 -0
- package/dist/components/AvatarRotator/AvatarRotator.js +84 -0
- package/dist/components/AvatarRotator/AvatarRotator.js.map +1 -0
- package/dist/components/AvatarRotator/AvatarRotator.module.css.cjs +2 -0
- package/dist/components/AvatarRotator/AvatarRotator.module.css.cjs.map +1 -0
- package/dist/components/AvatarRotator/AvatarRotator.module.css.js +13 -0
- package/dist/components/AvatarRotator/AvatarRotator.module.css.js.map +1 -0
- package/dist/components/AvatarRotator/index.d.ts +2 -0
- package/dist/components/AvatarRotator.cjs +1 -0
- package/dist/components/AvatarRotator.d.ts +2 -0
- package/dist/components/AvatarRotator.js +2 -0
- package/dist/components/Chip/Chip.cjs +1 -1
- package/dist/components/Chip/Chip.cjs.map +1 -1
- package/dist/components/Chip/Chip.js +19 -19
- package/dist/components/ContributionGraph/ContributionGraph.cjs +1 -1
- package/dist/components/ContributionGraph/ContributionGraph.cjs.map +1 -1
- package/dist/components/ContributionGraph/ContributionGraph.js +108 -117
- package/dist/components/ContributionGraph/ContributionGraph.js.map +1 -1
- package/dist/components/CountDownTimer/CountDownTimer.cjs +1 -1
- package/dist/components/CountDownTimer/CountDownTimer.cjs.map +1 -1
- package/dist/components/CountDownTimer/CountDownTimer.js +37 -28
- package/dist/components/CountDownTimer/CountDownTimer.js.map +1 -1
- package/dist/components/Dropdown/Dropdown.cjs +1 -1
- package/dist/components/Dropdown/Dropdown.cjs.map +1 -1
- package/dist/components/Dropdown/Dropdown.js +45 -46
- package/dist/components/Dropdown/Dropdown.js.map +1 -1
- package/dist/components/GnomeProvider/GnomeContext.cjs +2 -0
- package/dist/components/GnomeProvider/GnomeContext.cjs.map +1 -0
- package/dist/components/GnomeProvider/GnomeContext.d.ts +16 -0
- package/dist/components/GnomeProvider/GnomeContext.js +40 -0
- package/dist/components/GnomeProvider/GnomeContext.js.map +1 -0
- package/dist/components/GnomeProvider/GnomeProvider.cjs +2 -0
- package/dist/components/GnomeProvider/GnomeProvider.cjs.map +1 -0
- package/dist/components/GnomeProvider/GnomeProvider.d.ts +24 -0
- package/dist/components/GnomeProvider/GnomeProvider.js +25 -0
- package/dist/components/GnomeProvider/GnomeProvider.js.map +1 -0
- package/dist/components/PasswordEntryRow/PasswordEntryRow.cjs +1 -1
- package/dist/components/PasswordEntryRow/PasswordEntryRow.cjs.map +1 -1
- package/dist/components/PasswordEntryRow/PasswordEntryRow.js +11 -12
- package/dist/components/PasswordEntryRow/PasswordEntryRow.js.map +1 -1
- package/dist/components/SearchBar/SearchBar.cjs +1 -1
- package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
- package/dist/components/SearchBar/SearchBar.js +38 -39
- package/dist/components/SearchBar/SearchBar.js.map +1 -1
- package/dist/components/Sidebar/SidebarSection.cjs +1 -1
- package/dist/components/Sidebar/SidebarSection.cjs.map +1 -1
- package/dist/components/Sidebar/SidebarSection.js +41 -42
- package/dist/components/Sidebar/SidebarSection.js.map +1 -1
- package/dist/components/Toast/Toast.cjs +1 -1
- package/dist/components/Toast/Toast.cjs.map +1 -1
- package/dist/components/Toast/Toast.js +18 -18
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks.cjs +1 -1
- package/dist/hooks.js +3 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +90 -87
- package/dist/style.css +1 -1
- package/package.json +16 -1
- package/dist/icons/dist/icons/Check.cjs +0 -2
- package/dist/icons/dist/icons/Check.cjs.map +0 -1
- package/dist/icons/dist/icons/Check.js +0 -12
- package/dist/icons/dist/icons/Check.js.map +0 -1
- package/dist/icons/dist/icons/Close.cjs +0 -2
- package/dist/icons/dist/icons/Close.cjs.map +0 -1
- package/dist/icons/dist/icons/Close.js +0 -12
- package/dist/icons/dist/icons/Close.js.map +0 -1
- package/dist/icons/dist/icons/PanDown.cjs +0 -2
- package/dist/icons/dist/icons/PanDown.cjs.map +0 -1
- package/dist/icons/dist/icons/PanDown.js +0 -12
- package/dist/icons/dist/icons/PanDown.js.map +0 -1
- package/dist/icons/dist/icons/PanUp.cjs +0 -2
- package/dist/icons/dist/icons/PanUp.cjs.map +0 -1
- package/dist/icons/dist/icons/PanUp.js +0 -12
- package/dist/icons/dist/icons/PanUp.js.map +0 -1
- package/dist/icons/dist/icons/Search.cjs +0 -2
- package/dist/icons/dist/icons/Search.cjs.map +0 -1
- package/dist/icons/dist/icons/Search.js +0 -12
- package/dist/icons/dist/icons/Search.js.map +0 -1
- package/dist/icons/dist/icons/ViewConceal.cjs +0 -2
- package/dist/icons/dist/icons/ViewConceal.cjs.map +0 -1
- package/dist/icons/dist/icons/ViewConceal.js +0 -12
- package/dist/icons/dist/icons/ViewConceal.js.map +0 -1
- package/dist/icons/dist/icons/ViewReveal.cjs +0 -2
- package/dist/icons/dist/icons/ViewReveal.cjs.map +0 -1
- package/dist/icons/dist/icons/ViewReveal.js +0 -12
- package/dist/icons/dist/icons/ViewReveal.js.map +0 -1
|
@@ -1,239 +1,230 @@
|
|
|
1
1
|
import e from "./ContributionGraph.module.css.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { useDateTimeFormatter as t } from "../GnomeProvider/GnomeContext.js";
|
|
3
|
+
import { useMemo as n, useRef as r, useState as i } from "react";
|
|
4
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
4
5
|
//#region src/components/ContributionGraph/ContributionGraph.tsx
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"Sep",
|
|
15
|
-
"Oct",
|
|
16
|
-
"Nov",
|
|
17
|
-
"Dec"
|
|
18
|
-
], s = [
|
|
19
|
-
"Sun",
|
|
20
|
-
"Mon",
|
|
21
|
-
"Tue",
|
|
22
|
-
"Wed",
|
|
23
|
-
"Thu",
|
|
24
|
-
"Fri",
|
|
25
|
-
"Sat"
|
|
26
|
-
], c = 28, l = 20, u = [
|
|
6
|
+
var s = new Date(2e3, 0, 2);
|
|
7
|
+
function c(e, t) {
|
|
8
|
+
return t.format(new Date(2e3, e));
|
|
9
|
+
}
|
|
10
|
+
function l(e, t) {
|
|
11
|
+
let n = new Date(s);
|
|
12
|
+
return n.setDate(s.getDate() + e), t.format(n);
|
|
13
|
+
}
|
|
14
|
+
var u = 28, d = 20, f = [
|
|
27
15
|
"var(--gnome-card-shade-color, rgba(0,0,0,0.07))",
|
|
28
16
|
"var(--gnome-green-1, #8ff0a4)",
|
|
29
17
|
"var(--gnome-green-2, #57e389)",
|
|
30
18
|
"var(--gnome-green-4, #2ec27e)",
|
|
31
19
|
"var(--gnome-green-5, #26a269)"
|
|
32
20
|
];
|
|
33
|
-
function
|
|
21
|
+
function p(e) {
|
|
34
22
|
return `${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}`;
|
|
35
23
|
}
|
|
36
|
-
function
|
|
24
|
+
function m(e) {
|
|
37
25
|
let [t, n, r] = e.split("-").map(Number);
|
|
38
26
|
return new Date(t, n - 1, r);
|
|
39
27
|
}
|
|
40
|
-
function
|
|
41
|
-
return
|
|
28
|
+
function h(e, t) {
|
|
29
|
+
return t.format(m(e));
|
|
30
|
+
}
|
|
31
|
+
function g({ data: s, maxLevel: m = 4, colorScale: g, cellSize: _ = 12, cellGap: v = 3, weekStartDay: y = 1, showMonthLabels: b = !0, showDayLabels: x = !0, showLegend: S = !0, weeks: C = 52, ariaLabel: w = "Contribution graph", onDayClick: T, tooltipContent: E, className: D }) {
|
|
32
|
+
let O = t({ month: "short" }), k = t({ weekday: "short" }), A = t({
|
|
42
33
|
weekday: "long",
|
|
43
34
|
year: "numeric",
|
|
44
35
|
month: "long",
|
|
45
36
|
day: "numeric"
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
function m({ data: f, maxLevel: m = 4, colorScale: h, cellSize: g = 12, cellGap: _ = 3, weekStartDay: v = 1, showMonthLabels: y = !0, showDayLabels: b = !0, showLegend: x = !0, weeks: S = 52, ariaLabel: C = "Contribution graph", onDayClick: w, tooltipContent: T, className: E }) {
|
|
49
|
-
let D = g + _, O = n(null), k = n(null), A = h ?? u, [j, M] = r({
|
|
37
|
+
}), j = _ + v, M = r(null), N = r(null), P = g ?? f, [F, I] = i({
|
|
50
38
|
col: 0,
|
|
51
39
|
row: 0
|
|
52
|
-
}), [
|
|
40
|
+
}), [L, R] = i(null), z = n(() => {
|
|
53
41
|
let e = /* @__PURE__ */ new Map();
|
|
54
|
-
for (let t of
|
|
42
|
+
for (let t of s) e.set(t.date, t.count);
|
|
55
43
|
return e;
|
|
56
|
-
}, [
|
|
44
|
+
}, [s]), B = n(() => Math.max(1, ...s.map((e) => e.count)), [s]), { grid: V, monthLabels: H } = n(() => {
|
|
57
45
|
let e = /* @__PURE__ */ new Date();
|
|
58
46
|
e.setHours(0, 0, 0, 0);
|
|
59
|
-
let t = (e.getDay() -
|
|
47
|
+
let t = (e.getDay() - y + 7) % 7, n = new Date(e);
|
|
60
48
|
n.setDate(e.getDate() - t);
|
|
61
49
|
let r = new Date(n);
|
|
62
|
-
r.setDate(n.getDate() - (
|
|
63
|
-
let i = [], a = [],
|
|
64
|
-
for (let t = 0; t <
|
|
50
|
+
r.setDate(n.getDate() - (C - 1) * 7);
|
|
51
|
+
let i = [], a = [], o = -1;
|
|
52
|
+
for (let t = 0; t < C; t++) {
|
|
65
53
|
let n = new Date(r);
|
|
66
|
-
n.setDate(r.getDate() + t * 7), n.getMonth() !==
|
|
54
|
+
n.setDate(r.getDate() + t * 7), n.getMonth() !== o && (a.push({
|
|
67
55
|
col: t,
|
|
68
|
-
month:
|
|
69
|
-
}),
|
|
70
|
-
let
|
|
56
|
+
month: c(n.getMonth(), O)
|
|
57
|
+
}), o = n.getMonth());
|
|
58
|
+
let s = [];
|
|
71
59
|
for (let n = 0; n < 7; n++) {
|
|
72
60
|
let i = new Date(r);
|
|
73
61
|
i.setDate(r.getDate() + t * 7 + n);
|
|
74
|
-
let a = i > e, o =
|
|
75
|
-
|
|
62
|
+
let a = i > e, o = p(i), c = a ? 0 : z.get(o) ?? 0, l = c === 0 ? 0 : Math.min(m, Math.ceil(c / B * m));
|
|
63
|
+
s.push({
|
|
76
64
|
iso: o,
|
|
77
|
-
count:
|
|
65
|
+
count: c,
|
|
78
66
|
level: l,
|
|
79
67
|
future: a
|
|
80
68
|
});
|
|
81
69
|
}
|
|
82
|
-
i.push(
|
|
70
|
+
i.push(s);
|
|
83
71
|
}
|
|
84
72
|
return {
|
|
85
73
|
grid: i,
|
|
86
74
|
monthLabels: a
|
|
87
75
|
};
|
|
88
76
|
}, [
|
|
89
|
-
|
|
90
|
-
|
|
77
|
+
z,
|
|
78
|
+
B,
|
|
91
79
|
m,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
C,
|
|
81
|
+
y,
|
|
82
|
+
O
|
|
83
|
+
]), U = n(() => [
|
|
95
84
|
1,
|
|
96
85
|
3,
|
|
97
86
|
5
|
|
98
87
|
].map((e) => ({
|
|
99
|
-
row: (e -
|
|
100
|
-
label:
|
|
101
|
-
})), [
|
|
102
|
-
function
|
|
103
|
-
let n = Math.max(0, Math.min(
|
|
104
|
-
|
|
88
|
+
row: (e - y + 7) % 7,
|
|
89
|
+
label: l(e, k)
|
|
90
|
+
})), [y, k]), W = x ? u : 0, G = b ? d : 0, K = W + C * j - v, q = G + 7 * j - v, J = Math.min(4, Math.floor(_ / 3));
|
|
91
|
+
function Y(e, t) {
|
|
92
|
+
let n = Math.max(0, Math.min(C - 1, e)), r = Math.max(0, Math.min(6, t));
|
|
93
|
+
I({
|
|
105
94
|
col: n,
|
|
106
95
|
row: r
|
|
107
|
-
}),
|
|
96
|
+
}), M.current?.querySelector(`[data-col="${n}"][data-row="${r}"]`)?.focus();
|
|
108
97
|
}
|
|
109
|
-
function
|
|
98
|
+
function X(e, t, n) {
|
|
110
99
|
let r = {
|
|
111
100
|
ArrowRight: [t + 1, n],
|
|
112
101
|
ArrowLeft: [t - 1, n],
|
|
113
102
|
ArrowDown: [t, n + 1],
|
|
114
103
|
ArrowUp: [t, n - 1]
|
|
115
104
|
};
|
|
116
|
-
if (r[e.key]) e.preventDefault(),
|
|
105
|
+
if (r[e.key]) e.preventDefault(), Y(...r[e.key]);
|
|
117
106
|
else if (e.key === "Enter" || e.key === " ") {
|
|
118
107
|
e.preventDefault();
|
|
119
|
-
let r =
|
|
120
|
-
r && !r.future &&
|
|
108
|
+
let r = V[t]?.[n];
|
|
109
|
+
r && !r.future && T?.({
|
|
121
110
|
date: r.iso,
|
|
122
111
|
count: r.count
|
|
123
112
|
});
|
|
124
113
|
}
|
|
125
114
|
}
|
|
126
|
-
function
|
|
127
|
-
let n =
|
|
115
|
+
function Z(e, t) {
|
|
116
|
+
let n = N.current;
|
|
128
117
|
if (!n) return;
|
|
129
118
|
let r = n.getBoundingClientRect(), i = e.currentTarget.getBoundingClientRect();
|
|
130
|
-
|
|
131
|
-
x: i.left - r.left +
|
|
119
|
+
R({
|
|
120
|
+
x: i.left - r.left + _ / 2,
|
|
132
121
|
y: i.top - r.top,
|
|
133
122
|
text: t
|
|
134
123
|
});
|
|
135
124
|
}
|
|
136
|
-
function
|
|
137
|
-
return e.future ?
|
|
125
|
+
function Q(e) {
|
|
126
|
+
return e.future ? P[0] : P[Math.min(e.level, P.length - 1)] ?? P[P.length - 1];
|
|
138
127
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
128
|
+
function $(e) {
|
|
129
|
+
if (e.future) return h(e.iso, A);
|
|
130
|
+
let t = h(e.iso, A);
|
|
131
|
+
return E?.({
|
|
141
132
|
date: e.iso,
|
|
142
133
|
count: e.count
|
|
143
|
-
}) ?? `${e.count} contribution${e.count === 1 ? "" : "s"} on ${
|
|
134
|
+
}) ?? `${e.count} contribution${e.count === 1 ? "" : "s"} on ${t}`;
|
|
144
135
|
}
|
|
145
|
-
return /* @__PURE__ */
|
|
146
|
-
ref:
|
|
147
|
-
className: [e.wrapper,
|
|
136
|
+
return /* @__PURE__ */ o("div", {
|
|
137
|
+
ref: N,
|
|
138
|
+
className: [e.wrapper, D].filter(Boolean).join(" "),
|
|
148
139
|
children: [
|
|
149
|
-
/* @__PURE__ */
|
|
150
|
-
ref:
|
|
151
|
-
width:
|
|
152
|
-
height:
|
|
140
|
+
/* @__PURE__ */ o("svg", {
|
|
141
|
+
ref: M,
|
|
142
|
+
width: K,
|
|
143
|
+
height: q,
|
|
153
144
|
className: e.svg,
|
|
154
|
-
"aria-label":
|
|
145
|
+
"aria-label": w,
|
|
155
146
|
role: "img",
|
|
156
147
|
children: [
|
|
157
|
-
|
|
158
|
-
x:
|
|
148
|
+
b && H.map(({ col: t, month: n }) => /* @__PURE__ */ a("text", {
|
|
149
|
+
x: W + t * j,
|
|
159
150
|
y: 12,
|
|
160
151
|
className: e.label,
|
|
161
152
|
children: n
|
|
162
153
|
}, `m-${t}`)),
|
|
163
|
-
|
|
154
|
+
x && U.map(({ row: t, label: n }) => /* @__PURE__ */ a("text", {
|
|
164
155
|
x: 0,
|
|
165
|
-
y:
|
|
156
|
+
y: G + t * j + _ - 1,
|
|
166
157
|
className: e.label,
|
|
167
158
|
children: n
|
|
168
159
|
}, `d-${t}`)),
|
|
169
|
-
/* @__PURE__ */
|
|
160
|
+
/* @__PURE__ */ a("g", {
|
|
170
161
|
role: "grid",
|
|
171
|
-
"aria-label":
|
|
172
|
-
children:
|
|
162
|
+
"aria-label": w,
|
|
163
|
+
children: V.map((t, n) => /* @__PURE__ */ a("g", {
|
|
173
164
|
role: "row",
|
|
174
165
|
children: t.map((t, r) => {
|
|
175
|
-
let
|
|
176
|
-
return /* @__PURE__ */
|
|
166
|
+
let i = $(t), o = F.col === n && F.row === r;
|
|
167
|
+
return /* @__PURE__ */ a("rect", {
|
|
177
168
|
"data-col": n,
|
|
178
169
|
"data-row": r,
|
|
179
|
-
x:
|
|
180
|
-
y:
|
|
181
|
-
width:
|
|
182
|
-
height:
|
|
183
|
-
rx:
|
|
184
|
-
fill:
|
|
170
|
+
x: W + n * j,
|
|
171
|
+
y: G + r * j,
|
|
172
|
+
width: _,
|
|
173
|
+
height: _,
|
|
174
|
+
rx: J,
|
|
175
|
+
fill: Q(t),
|
|
185
176
|
opacity: t.future ? .35 : 1,
|
|
186
177
|
className: e.cell,
|
|
187
178
|
role: "gridcell",
|
|
188
|
-
"aria-label":
|
|
179
|
+
"aria-label": i,
|
|
189
180
|
"aria-disabled": t.future || void 0,
|
|
190
181
|
tabIndex: o ? 0 : -1,
|
|
191
|
-
onClick: () => !t.future &&
|
|
182
|
+
onClick: () => !t.future && T?.({
|
|
192
183
|
date: t.iso,
|
|
193
184
|
count: t.count
|
|
194
185
|
}),
|
|
195
|
-
onKeyDown: (e) =>
|
|
196
|
-
onFocus: () =>
|
|
186
|
+
onKeyDown: (e) => X(e, n, r),
|
|
187
|
+
onFocus: () => I({
|
|
197
188
|
col: n,
|
|
198
189
|
row: r
|
|
199
190
|
}),
|
|
200
|
-
onMouseEnter: (e) =>
|
|
201
|
-
onMouseLeave: () =>
|
|
191
|
+
onMouseEnter: (e) => Z(e, i),
|
|
192
|
+
onMouseLeave: () => R(null)
|
|
202
193
|
}, `${n}-${r}`);
|
|
203
194
|
})
|
|
204
195
|
}, n))
|
|
205
196
|
})
|
|
206
197
|
]
|
|
207
198
|
}),
|
|
208
|
-
|
|
199
|
+
L && /* @__PURE__ */ a("div", {
|
|
209
200
|
className: e.tooltip,
|
|
210
201
|
style: {
|
|
211
|
-
left:
|
|
212
|
-
top:
|
|
202
|
+
left: L.x,
|
|
203
|
+
top: L.y
|
|
213
204
|
},
|
|
214
205
|
role: "tooltip",
|
|
215
|
-
children:
|
|
206
|
+
children: L.text
|
|
216
207
|
}),
|
|
217
|
-
|
|
208
|
+
S && /* @__PURE__ */ o("div", {
|
|
218
209
|
className: e.legend,
|
|
219
210
|
children: [
|
|
220
|
-
/* @__PURE__ */
|
|
211
|
+
/* @__PURE__ */ a("span", {
|
|
221
212
|
className: e.legendLabel,
|
|
222
213
|
children: "Less"
|
|
223
214
|
}),
|
|
224
|
-
Array.from({ length: m + 1 }, (t, n) => /* @__PURE__ */
|
|
225
|
-
width:
|
|
226
|
-
height:
|
|
215
|
+
Array.from({ length: m + 1 }, (t, n) => /* @__PURE__ */ a("svg", {
|
|
216
|
+
width: _,
|
|
217
|
+
height: _,
|
|
227
218
|
"aria-hidden": "true",
|
|
228
219
|
className: e.legendCell,
|
|
229
|
-
children: /* @__PURE__ */
|
|
230
|
-
width:
|
|
231
|
-
height:
|
|
232
|
-
rx:
|
|
233
|
-
fill:
|
|
220
|
+
children: /* @__PURE__ */ a("rect", {
|
|
221
|
+
width: _,
|
|
222
|
+
height: _,
|
|
223
|
+
rx: J,
|
|
224
|
+
fill: P[Math.min(n, P.length - 1)]
|
|
234
225
|
})
|
|
235
226
|
}, n)),
|
|
236
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ a("span", {
|
|
237
228
|
className: e.legendLabel,
|
|
238
229
|
children: "More"
|
|
239
230
|
})
|
|
@@ -243,6 +234,6 @@ function m({ data: f, maxLevel: m = 4, colorScale: h, cellSize: g = 12, cellGap:
|
|
|
243
234
|
});
|
|
244
235
|
}
|
|
245
236
|
//#endregion
|
|
246
|
-
export {
|
|
237
|
+
export { g as ContributionGraph };
|
|
247
238
|
|
|
248
239
|
//# sourceMappingURL=ContributionGraph.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContributionGraph.js","names":[],"sources":["../../../src/components/ContributionGraph/ContributionGraph.tsx"],"sourcesContent":["import { useMemo, useRef, useState } from \"react\";\nimport type { KeyboardEvent } from \"react\";\nimport styles from \"./ContributionGraph.module.css\";\n\nexport interface ContributionDay {\n /** ISO 8601 date — \"YYYY-MM-DD\". */\n date: string;\n /** Non-negative activity count. */\n count: number;\n}\n\nexport interface ContributionGraphProps {\n /** Activity data. Days absent from the array are treated as count = 0. */\n data: ContributionDay[];\n /**\n * Number of intensity levels (excluding 0).\n * @default 4\n */\n maxLevel?: number;\n /**\n * Colour scale — length must be maxLevel + 1 (index 0 = empty).\n * Defaults to the Adwaita green palette.\n */\n colorScale?: string[];\n /** Cell side length in pixels. @default 12 */\n cellSize?: number;\n /** Gap between cells in pixels. @default 3 */\n cellGap?: number;\n /** 0 = Sunday · 1 = Monday (GNOME locale default). @default 1 */\n weekStartDay?: 0 | 1;\n /** @default true */\n showMonthLabels?: boolean;\n /** @default true */\n showDayLabels?: boolean;\n /** @default true */\n showLegend?: boolean;\n /** Number of week columns to display. @default 52 */\n weeks?: number;\n /** @default \"Contribution graph\" */\n ariaLabel?: string;\n onDayClick?: (day: ContributionDay) => void;\n /** Returns a plain-text tooltip string for a day. */\n tooltipContent?: (day: ContributionDay) => string;\n className?: string;\n}\n\nconst SHORT_MONTHS = [\n \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n];\n// 0=Sun … 6=Sat\nconst SHORT_DAYS = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\nconst DAY_LABEL_WIDTH = 28;\nconst MONTH_LABEL_HEIGHT = 20;\n\nconst DEFAULT_COLORS = [\n \"var(--gnome-card-shade-color, rgba(0,0,0,0.07))\",\n \"var(--gnome-green-1, #8ff0a4)\",\n \"var(--gnome-green-2, #57e389)\",\n \"var(--gnome-green-4, #2ec27e)\",\n \"var(--gnome-green-5, #26a269)\",\n];\n\nfunction dateToIso(date: Date): string {\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, \"0\");\n const d = String(date.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${d}`;\n}\n\nfunction isoToLocal(iso: string): Date {\n const [y, m, d] = iso.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\n\nfunction fullDateLabel(iso: string): string {\n return isoToLocal(iso).toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n}\n\ninterface GridCell {\n iso: string;\n count: number;\n level: number;\n future: boolean;\n}\n\nexport function ContributionGraph({\n data,\n maxLevel = 4,\n colorScale,\n cellSize = 12,\n cellGap = 3,\n weekStartDay = 1,\n showMonthLabels = true,\n showDayLabels = true,\n showLegend = true,\n weeks = 52,\n ariaLabel = \"Contribution graph\",\n onDayClick,\n tooltipContent,\n className,\n}: ContributionGraphProps) {\n const stride = cellSize + cellGap;\n const svgRef = useRef<SVGSVGElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const colors = colorScale ?? DEFAULT_COLORS;\n\n const [focusedCell, setFocusedCell] = useState({ col: 0, row: 0 });\n const [tooltip, setTooltip] = useState<{\n x: number;\n y: number;\n text: string;\n } | null>(null);\n\n const countMap = useMemo(() => {\n const map = new Map<string, number>();\n for (const d of data) map.set(d.date, d.count);\n return map;\n }, [data]);\n\n const maxCount = useMemo(\n () => Math.max(1, ...data.map((d) => d.count)),\n [data],\n );\n\n const { grid, monthLabels } = useMemo(() => {\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n\n // Align to start of current week\n const daysFromWeekStart = (today.getDay() - weekStartDay + 7) % 7;\n const lastWeekStart = new Date(today);\n lastWeekStart.setDate(today.getDate() - daysFromWeekStart);\n\n const firstDay = new Date(lastWeekStart);\n firstDay.setDate(lastWeekStart.getDate() - (weeks - 1) * 7);\n\n const gridResult: GridCell[][] = [];\n const labels: { col: number; month: string }[] = [];\n let lastMonth = -1;\n\n for (let col = 0; col < weeks; col++) {\n const colStart = new Date(firstDay);\n colStart.setDate(firstDay.getDate() + col * 7);\n\n // Month label when the column starts a new month\n if (colStart.getMonth() !== lastMonth) {\n labels.push({ col, month: SHORT_MONTHS[colStart.getMonth()] });\n lastMonth = colStart.getMonth();\n }\n\n const column: GridCell[] = [];\n for (let row = 0; row < 7; row++) {\n const date = new Date(firstDay);\n date.setDate(firstDay.getDate() + col * 7 + row);\n const future = date > today;\n const iso = dateToIso(date);\n const count = future ? 0 : (countMap.get(iso) ?? 0);\n const level =\n count === 0\n ? 0\n : Math.min(maxLevel, Math.ceil((count / maxCount) * maxLevel));\n column.push({ iso, count, level, future });\n }\n gridResult.push(column);\n }\n\n return { grid: gridResult, monthLabels: labels };\n }, [countMap, maxCount, maxLevel, weeks, weekStartDay]);\n\n // Always label Mon(1), Wed(3), Fri(5) — rows shift with weekStartDay\n const labelRows = useMemo(\n () =>\n [1, 3, 5].map((dayIndex) => ({\n row: (dayIndex - weekStartDay + 7) % 7,\n label: SHORT_DAYS[dayIndex],\n })),\n [weekStartDay],\n );\n\n const dayLabelW = showDayLabels ? DAY_LABEL_WIDTH : 0;\n const monthLabelH = showMonthLabels ? MONTH_LABEL_HEIGHT : 0;\n const svgWidth = dayLabelW + weeks * stride - cellGap;\n const svgHeight = monthLabelH + 7 * stride - cellGap;\n const cellRx = Math.min(4, Math.floor(cellSize / 3));\n\n function focusCell(col: number, row: number) {\n const c = Math.max(0, Math.min(weeks - 1, col));\n const r = Math.max(0, Math.min(6, row));\n setFocusedCell({ col: c, row: r });\n svgRef.current\n ?.querySelector<SVGRectElement>(`[data-col=\"${c}\"][data-row=\"${r}\"]`)\n ?.focus();\n }\n\n function handleCellKey(e: KeyboardEvent, col: number, row: number) {\n const moves: Record<string, [number, number]> = {\n ArrowRight: [col + 1, row],\n ArrowLeft: [col - 1, row],\n ArrowDown: [col, row + 1],\n ArrowUp: [col, row - 1],\n };\n if (moves[e.key]) {\n e.preventDefault();\n focusCell(...moves[e.key]);\n } else if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n const cell = grid[col]?.[row];\n if (cell && !cell.future) onDayClick?.({ date: cell.iso, count: cell.count });\n }\n }\n\n function handleMouseEnter(\n e: React.MouseEvent<SVGRectElement>,\n text: string,\n ) {\n const wrapper = wrapperRef.current;\n if (!wrapper) return;\n const wRect = wrapper.getBoundingClientRect();\n const rRect = (e.currentTarget as Element).getBoundingClientRect();\n setTooltip({\n x: rRect.left - wRect.left + cellSize / 2,\n y: rRect.top - wRect.top,\n text,\n });\n }\n\n function cellColor(cell: GridCell): string {\n if (cell.future) return colors[0];\n return colors[Math.min(cell.level, colors.length - 1)] ?? colors[colors.length - 1];\n }\n\n function cellTooltip(cell: GridCell): string {\n if (cell.future) return fullDateLabel(cell.iso);\n return (\n tooltipContent?.({ date: cell.iso, count: cell.count }) ??\n `${cell.count} contribution${cell.count !== 1 ? \"s\" : \"\"} on ${fullDateLabel(cell.iso)}`\n );\n }\n\n return (\n <div\n ref={wrapperRef}\n className={[styles.wrapper, className].filter(Boolean).join(\" \")}\n >\n <svg\n ref={svgRef}\n width={svgWidth}\n height={svgHeight}\n className={styles.svg}\n aria-label={ariaLabel}\n role=\"img\"\n >\n {/* Month labels */}\n {showMonthLabels &&\n monthLabels.map(({ col, month }) => (\n <text\n key={`m-${col}`}\n x={dayLabelW + col * stride}\n y={12}\n className={styles.label}\n >\n {month}\n </text>\n ))}\n\n {/* Day-of-week labels: Mon, Wed, Fri */}\n {showDayLabels &&\n labelRows.map(({ row, label }) => (\n <text\n key={`d-${row}`}\n x={0}\n y={monthLabelH + row * stride + cellSize - 1}\n className={styles.label}\n >\n {label}\n </text>\n ))}\n\n {/* Activity grid */}\n <g role=\"grid\" aria-label={ariaLabel}>\n {grid.map((column, col) => (\n <g key={col} role=\"row\">\n {column.map((cell, row) => {\n const tipText = cellTooltip(cell);\n const isFocused =\n focusedCell.col === col && focusedCell.row === row;\n\n return (\n <rect\n key={`${col}-${row}`}\n data-col={col}\n data-row={row}\n x={dayLabelW + col * stride}\n y={monthLabelH + row * stride}\n width={cellSize}\n height={cellSize}\n rx={cellRx}\n fill={cellColor(cell)}\n opacity={cell.future ? 0.35 : 1}\n className={styles.cell}\n role=\"gridcell\"\n aria-label={tipText}\n aria-disabled={cell.future || undefined}\n tabIndex={isFocused ? 0 : -1}\n onClick={() => !cell.future && onDayClick?.({ date: cell.iso, count: cell.count })}\n onKeyDown={(e) => handleCellKey(e, col, row)}\n onFocus={() => setFocusedCell({ col, row })}\n onMouseEnter={(e) => handleMouseEnter(e, tipText)}\n onMouseLeave={() => setTooltip(null)}\n />\n );\n })}\n </g>\n ))}\n </g>\n </svg>\n\n {tooltip && (\n <div\n className={styles.tooltip}\n style={{ left: tooltip.x, top: tooltip.y }}\n role=\"tooltip\"\n >\n {tooltip.text}\n </div>\n )}\n\n {showLegend && (\n <div className={styles.legend}>\n <span className={styles.legendLabel}>Less</span>\n {Array.from({ length: maxLevel + 1 }, (_, i) => (\n <svg\n key={i}\n width={cellSize}\n height={cellSize}\n aria-hidden=\"true\"\n className={styles.legendCell}\n >\n <rect\n width={cellSize}\n height={cellSize}\n rx={cellRx}\n fill={colors[Math.min(i, colors.length - 1)]}\n />\n </svg>\n ))}\n <span className={styles.legendLabel}>More</span>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ContributionGraph.js","names":[],"sources":["../../../src/components/ContributionGraph/ContributionGraph.tsx"],"sourcesContent":["import { useMemo, useRef, useState } from \"react\";\nimport type { KeyboardEvent } from \"react\";\nimport styles from \"./ContributionGraph.module.css\";\nimport { useDateTimeFormatter } from \"../GnomeProvider/GnomeContext\";\n\nexport interface ContributionDay {\n /** ISO 8601 date — \"YYYY-MM-DD\". */\n date: string;\n /** Non-negative activity count. */\n count: number;\n}\n\nexport interface ContributionGraphProps {\n /** Activity data. Days absent from the array are treated as count = 0. */\n data: ContributionDay[];\n /**\n * Number of intensity levels (excluding 0).\n * @default 4\n */\n maxLevel?: number;\n /**\n * Colour scale — length must be maxLevel + 1 (index 0 = empty).\n * Defaults to the Adwaita green palette.\n */\n colorScale?: string[];\n /** Cell side length in pixels. @default 12 */\n cellSize?: number;\n /** Gap between cells in pixels. @default 3 */\n cellGap?: number;\n /** 0 = Sunday · 1 = Monday (GNOME locale default). @default 1 */\n weekStartDay?: 0 | 1;\n /** @default true */\n showMonthLabels?: boolean;\n /** @default true */\n showDayLabels?: boolean;\n /** @default true */\n showLegend?: boolean;\n /** Number of week columns to display. @default 52 */\n weeks?: number;\n /** @default \"Contribution graph\" */\n ariaLabel?: string;\n onDayClick?: (day: ContributionDay) => void;\n /** Returns a plain-text tooltip string for a day. */\n tooltipContent?: (day: ContributionDay) => string;\n className?: string;\n}\n\n// Reference Sunday: 2000-01-02 is a Sunday (day index 0)\nconst REF_SUNDAY = new Date(2000, 0, 2);\n\nfunction getShortMonth(\n monthIndex: number,\n formatter: Intl.DateTimeFormat,\n): string {\n return formatter.format(new Date(2000, monthIndex));\n}\n\nfunction getShortDay(\n dayIndex: number,\n formatter: Intl.DateTimeFormat,\n): string {\n const date = new Date(REF_SUNDAY);\n date.setDate(REF_SUNDAY.getDate() + dayIndex);\n return formatter.format(date);\n}\n\nconst DAY_LABEL_WIDTH = 28;\nconst MONTH_LABEL_HEIGHT = 20;\n\nconst DEFAULT_COLORS = [\n \"var(--gnome-card-shade-color, rgba(0,0,0,0.07))\",\n \"var(--gnome-green-1, #8ff0a4)\",\n \"var(--gnome-green-2, #57e389)\",\n \"var(--gnome-green-4, #2ec27e)\",\n \"var(--gnome-green-5, #26a269)\",\n];\n\nfunction dateToIso(date: Date): string {\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, \"0\");\n const d = String(date.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${d}`;\n}\n\nfunction isoToLocal(iso: string): Date {\n const [y, m, d] = iso.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\n\nfunction fullDateLabel(iso: string, formatter: Intl.DateTimeFormat): string {\n return formatter.format(isoToLocal(iso));\n}\n\ninterface GridCell {\n iso: string;\n count: number;\n level: number;\n future: boolean;\n}\n\nexport function ContributionGraph({\n data,\n maxLevel = 4,\n colorScale,\n cellSize = 12,\n cellGap = 3,\n weekStartDay = 1,\n showMonthLabels = true,\n showDayLabels = true,\n showLegend = true,\n weeks = 52,\n ariaLabel = \"Contribution graph\",\n onDayClick,\n tooltipContent,\n className,\n}: ContributionGraphProps) {\n const monthFormatter = useDateTimeFormatter({ month: \"short\" });\n const weekdayFormatter = useDateTimeFormatter({ weekday: \"short\" });\n const fullDateFormatter = useDateTimeFormatter({\n weekday: \"long\",\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n const stride = cellSize + cellGap;\n const svgRef = useRef<SVGSVGElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const colors = colorScale ?? DEFAULT_COLORS;\n\n const [focusedCell, setFocusedCell] = useState({ col: 0, row: 0 });\n const [tooltip, setTooltip] = useState<{\n x: number;\n y: number;\n text: string;\n } | null>(null);\n\n const countMap = useMemo(() => {\n const map = new Map<string, number>();\n for (const d of data) map.set(d.date, d.count);\n return map;\n }, [data]);\n\n const maxCount = useMemo(\n () => Math.max(1, ...data.map((d) => d.count)),\n [data],\n );\n\n const { grid, monthLabels } = useMemo(() => {\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n\n // Align to start of current week\n const daysFromWeekStart = (today.getDay() - weekStartDay + 7) % 7;\n const lastWeekStart = new Date(today);\n lastWeekStart.setDate(today.getDate() - daysFromWeekStart);\n\n const firstDay = new Date(lastWeekStart);\n firstDay.setDate(lastWeekStart.getDate() - (weeks - 1) * 7);\n\n const gridResult: GridCell[][] = [];\n const labels: { col: number; month: string }[] = [];\n let lastMonth = -1;\n\n for (let col = 0; col < weeks; col++) {\n const colStart = new Date(firstDay);\n colStart.setDate(firstDay.getDate() + col * 7);\n\n // Month label when the column starts a new month\n if (colStart.getMonth() !== lastMonth) {\n labels.push({\n col,\n month: getShortMonth(colStart.getMonth(), monthFormatter),\n });\n lastMonth = colStart.getMonth();\n }\n\n const column: GridCell[] = [];\n for (let row = 0; row < 7; row++) {\n const date = new Date(firstDay);\n date.setDate(firstDay.getDate() + col * 7 + row);\n const future = date > today;\n const iso = dateToIso(date);\n const count = future ? 0 : (countMap.get(iso) ?? 0);\n const level =\n count === 0\n ? 0\n : Math.min(maxLevel, Math.ceil((count / maxCount) * maxLevel));\n column.push({ iso, count, level, future });\n }\n gridResult.push(column);\n }\n\n return { grid: gridResult, monthLabels: labels };\n }, [countMap, maxCount, maxLevel, weeks, weekStartDay, monthFormatter]);\n\n // Always label Mon(1), Wed(3), Fri(5) — rows shift with weekStartDay\n const labelRows = useMemo(\n () =>\n [1, 3, 5].map((dayIndex) => ({\n row: (dayIndex - weekStartDay + 7) % 7,\n label: getShortDay(dayIndex, weekdayFormatter),\n })),\n [weekStartDay, weekdayFormatter],\n );\n\n const dayLabelW = showDayLabels ? DAY_LABEL_WIDTH : 0;\n const monthLabelH = showMonthLabels ? MONTH_LABEL_HEIGHT : 0;\n const svgWidth = dayLabelW + weeks * stride - cellGap;\n const svgHeight = monthLabelH + 7 * stride - cellGap;\n const cellRx = Math.min(4, Math.floor(cellSize / 3));\n\n function focusCell(col: number, row: number) {\n const c = Math.max(0, Math.min(weeks - 1, col));\n const r = Math.max(0, Math.min(6, row));\n setFocusedCell({ col: c, row: r });\n svgRef.current\n ?.querySelector<SVGRectElement>(`[data-col=\"${c}\"][data-row=\"${r}\"]`)\n ?.focus();\n }\n\n function handleCellKey(e: KeyboardEvent, col: number, row: number) {\n const moves: Record<string, [number, number]> = {\n ArrowRight: [col + 1, row],\n ArrowLeft: [col - 1, row],\n ArrowDown: [col, row + 1],\n ArrowUp: [col, row - 1],\n };\n if (moves[e.key]) {\n e.preventDefault();\n focusCell(...moves[e.key]);\n } else if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n const cell = grid[col]?.[row];\n if (cell && !cell.future) onDayClick?.({ date: cell.iso, count: cell.count });\n }\n }\n\n function handleMouseEnter(\n e: React.MouseEvent<SVGRectElement>,\n text: string,\n ) {\n const wrapper = wrapperRef.current;\n if (!wrapper) return;\n const wRect = wrapper.getBoundingClientRect();\n const rRect = (e.currentTarget as Element).getBoundingClientRect();\n setTooltip({\n x: rRect.left - wRect.left + cellSize / 2,\n y: rRect.top - wRect.top,\n text,\n });\n }\n\n function cellColor(cell: GridCell): string {\n if (cell.future) return colors[0];\n return colors[Math.min(cell.level, colors.length - 1)] ?? colors[colors.length - 1];\n }\n\n function cellTooltip(cell: GridCell): string {\n if (cell.future) return fullDateLabel(cell.iso, fullDateFormatter);\n const formattedDate = fullDateLabel(cell.iso, fullDateFormatter);\n return (\n tooltipContent?.({ date: cell.iso, count: cell.count }) ??\n `${cell.count} contribution${cell.count !== 1 ? \"s\" : \"\"} on ${formattedDate}`\n );\n }\n\n return (\n <div\n ref={wrapperRef}\n className={[styles.wrapper, className].filter(Boolean).join(\" \")}\n >\n <svg\n ref={svgRef}\n width={svgWidth}\n height={svgHeight}\n className={styles.svg}\n aria-label={ariaLabel}\n role=\"img\"\n >\n {/* Month labels */}\n {showMonthLabels &&\n monthLabels.map(({ col, month }) => (\n <text\n key={`m-${col}`}\n x={dayLabelW + col * stride}\n y={12}\n className={styles.label}\n >\n {month}\n </text>\n ))}\n\n {/* Day-of-week labels: Mon, Wed, Fri */}\n {showDayLabels &&\n labelRows.map(({ row, label }) => (\n <text\n key={`d-${row}`}\n x={0}\n y={monthLabelH + row * stride + cellSize - 1}\n className={styles.label}\n >\n {label}\n </text>\n ))}\n\n {/* Activity grid */}\n <g role=\"grid\" aria-label={ariaLabel}>\n {grid.map((column, col) => (\n <g key={col} role=\"row\">\n {column.map((cell, row) => {\n const tipText = cellTooltip(cell);\n const isFocused =\n focusedCell.col === col && focusedCell.row === row;\n\n return (\n <rect\n key={`${col}-${row}`}\n data-col={col}\n data-row={row}\n x={dayLabelW + col * stride}\n y={monthLabelH + row * stride}\n width={cellSize}\n height={cellSize}\n rx={cellRx}\n fill={cellColor(cell)}\n opacity={cell.future ? 0.35 : 1}\n className={styles.cell}\n role=\"gridcell\"\n aria-label={tipText}\n aria-disabled={cell.future || undefined}\n tabIndex={isFocused ? 0 : -1}\n onClick={() => !cell.future && onDayClick?.({ date: cell.iso, count: cell.count })}\n onKeyDown={(e) => handleCellKey(e, col, row)}\n onFocus={() => setFocusedCell({ col, row })}\n onMouseEnter={(e) => handleMouseEnter(e, tipText)}\n onMouseLeave={() => setTooltip(null)}\n />\n );\n })}\n </g>\n ))}\n </g>\n </svg>\n\n {tooltip && (\n <div\n className={styles.tooltip}\n style={{ left: tooltip.x, top: tooltip.y }}\n role=\"tooltip\"\n >\n {tooltip.text}\n </div>\n )}\n\n {showLegend && (\n <div className={styles.legend}>\n <span className={styles.legendLabel}>Less</span>\n {Array.from({ length: maxLevel + 1 }, (_, i) => (\n <svg\n key={i}\n width={cellSize}\n height={cellSize}\n aria-hidden=\"true\"\n className={styles.legendCell}\n >\n <rect\n width={cellSize}\n height={cellSize}\n rx={cellRx}\n fill={colors[Math.min(i, colors.length - 1)]}\n />\n </svg>\n ))}\n <span className={styles.legendLabel}>More</span>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`./CountDownTimer.module.css.cjs`);let
|
|
1
|
+
const e=require(`../GnomeProvider/GnomeContext.cjs`),t=require(`./CountDownTimer.module.css.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`);function i({start:i,end:a,format:o=`time`,variant:s=`accent`,action:c,className:l,...u}){let d=e.useDateTimeFormatter(),[f,p]=(0,n.useState)(null),[m,h]=(0,n.useState)(!1);if((0,n.useEffect)(()=>{let e=()=>{let e=new Date,t=new Date(a).getTime()-e.getTime();return t<=0?{days:0,hours:0,minutes:0,seconds:0,isFinished:!0}:{days:Math.floor(t/(1e3*60*60*24)),hours:Math.floor(t/(1e3*60*60)%24),minutes:Math.floor(t/1e3/60%60),seconds:Math.floor(t/1e3%60),isFinished:!1}};p(e());let t=setInterval(()=>{let t=e();p(t),t.isFinished&&!m&&(c?.(),h(!0))},1e3);return()=>clearInterval(t)},[a,c,m]),!f)return null;let g=()=>{if(o===`date`){let e=new Date(a);return d.format(e)}let{days:e,hours:t,minutes:n,seconds:r,isFinished:i}=f;if(i)return`00:00:00`;if(o===`datetime`){let e=new Date(a);return`${d.format(e)} ${`${String(t).padStart(2,`0`)}:${String(n).padStart(2,`0`)}:${String(r).padStart(2,`0`)}`}`}return e>0?`${e}d ${String(t).padStart(2,`0`)}h ${String(n).padStart(2,`0`)}m`:`${String(t).padStart(2,`0`)}:${String(n).padStart(2,`0`)}:${String(r).padStart(2,`0`)}`},_=f.isFinished?`destructive`:s;return(0,r.jsx)(`div`,{className:[t.default.countdownTimer,t.default[_],f.isFinished?t.default.finished:null,l].filter(Boolean).join(` `),...u,children:(0,r.jsx)(`span`,{className:t.default.value,children:g()})})}exports.CountDownTimer=i;
|
|
2
2
|
//# sourceMappingURL=CountDownTimer.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountDownTimer.cjs","names":[],"sources":["../../../src/components/CountDownTimer/CountDownTimer.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport styles from \"./CountDownTimer.module.css\";\n\nexport type CountDownVariant = \"accent\" | \"destructive\" | \"success\" | \"warning\";\n\nexport interface CountDownTimerProps extends HTMLAttributes<HTMLDivElement> {\n /** Start date for the countdown */\n start: Date;\n /** End date for the countdown */\n end: Date;\n /** Format to display: \"date\", \"time\", or \"datetime\" */\n format?: \"date\" | \"time\" | \"datetime\";\n /** Visual style variant. Defaults to `\"accent\"`. */\n variant?: CountDownVariant;\n /** Callback action to execute when countdown reaches zero */\n action?: () => void;\n}\n\ninterface TimeRemaining {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n isFinished: boolean;\n}\n\n/**\n * CountDown timer component that displays remaining time and executes an action when time runs out.\n *\n * @see https://developer.gnome.org/hig/patterns/\n */\nexport function CountDownTimer({\n start,\n end,\n format = \"time\",\n variant = \"accent\",\n action,\n className,\n ...props\n}: CountDownTimerProps) {\n const [timeRemaining, setTimeRemaining] = useState<TimeRemaining | null>(null);\n const [hasExecutedAction, setHasExecutedAction] = useState(false);\n\n useEffect(() => {\n const calculateTimeRemaining = (): TimeRemaining => {\n const now = new Date();\n const endTime = new Date(end).getTime();\n const nowTime = now.getTime();\n const difference = endTime - nowTime;\n\n if (difference <= 0) {\n return {\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n isFinished: true,\n };\n }\n\n const days = Math.floor(difference / (1000 * 60 * 60 * 24));\n const hours = Math.floor((difference / (1000 * 60 * 60)) % 24);\n const minutes = Math.floor((difference / 1000 / 60) % 60);\n const seconds = Math.floor((difference / 1000) % 60);\n\n return {\n days,\n hours,\n minutes,\n seconds,\n isFinished: false,\n };\n };\n\n // Initial calculation\n setTimeRemaining(calculateTimeRemaining());\n\n // Update every second\n const interval = setInterval(() => {\n const remaining = calculateTimeRemaining();\n setTimeRemaining(remaining);\n\n // Execute action when countdown finishes\n if (remaining.isFinished && !hasExecutedAction) {\n action?.();\n setHasExecutedAction(true);\n }\n }, 1000);\n\n return () => clearInterval(interval);\n }, [end, action, hasExecutedAction]);\n\n if (!timeRemaining) {\n return null;\n }\n\n const formatTime = (): string => {\n if (format === \"date\") {\n const endDate = new Date(end);\n return
|
|
1
|
+
{"version":3,"file":"CountDownTimer.cjs","names":[],"sources":["../../../src/components/CountDownTimer/CountDownTimer.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport styles from \"./CountDownTimer.module.css\";\nimport { useDateTimeFormatter } from \"../GnomeProvider/GnomeContext\";\n\nexport type CountDownVariant = \"accent\" | \"destructive\" | \"success\" | \"warning\";\n\nexport interface CountDownTimerProps extends HTMLAttributes<HTMLDivElement> {\n /** Start date for the countdown */\n start: Date;\n /** End date for the countdown */\n end: Date;\n /** Format to display: \"date\", \"time\", or \"datetime\" */\n format?: \"date\" | \"time\" | \"datetime\";\n /** Visual style variant. Defaults to `\"accent\"`. */\n variant?: CountDownVariant;\n /** Callback action to execute when countdown reaches zero */\n action?: () => void;\n}\n\ninterface TimeRemaining {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n isFinished: boolean;\n}\n\n/**\n * CountDown timer component that displays remaining time and executes an action when time runs out.\n *\n * @see https://developer.gnome.org/hig/patterns/\n */\nexport function CountDownTimer({\n start,\n end,\n format = \"time\",\n variant = \"accent\",\n action,\n className,\n ...props\n}: CountDownTimerProps) {\n const dateFormatter = useDateTimeFormatter();\n const [timeRemaining, setTimeRemaining] = useState<TimeRemaining | null>(null);\n const [hasExecutedAction, setHasExecutedAction] = useState(false);\n\n useEffect(() => {\n const calculateTimeRemaining = (): TimeRemaining => {\n const now = new Date();\n const endTime = new Date(end).getTime();\n const nowTime = now.getTime();\n const difference = endTime - nowTime;\n\n if (difference <= 0) {\n return {\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n isFinished: true,\n };\n }\n\n const days = Math.floor(difference / (1000 * 60 * 60 * 24));\n const hours = Math.floor((difference / (1000 * 60 * 60)) % 24);\n const minutes = Math.floor((difference / 1000 / 60) % 60);\n const seconds = Math.floor((difference / 1000) % 60);\n\n return {\n days,\n hours,\n minutes,\n seconds,\n isFinished: false,\n };\n };\n\n // Initial calculation\n setTimeRemaining(calculateTimeRemaining());\n\n // Update every second\n const interval = setInterval(() => {\n const remaining = calculateTimeRemaining();\n setTimeRemaining(remaining);\n\n // Execute action when countdown finishes\n if (remaining.isFinished && !hasExecutedAction) {\n action?.();\n setHasExecutedAction(true);\n }\n }, 1000);\n\n return () => clearInterval(interval);\n }, [end, action, hasExecutedAction]);\n\n if (!timeRemaining) {\n return null;\n }\n\n const formatTime = (): string => {\n if (format === \"date\") {\n const endDate = new Date(end);\n return dateFormatter.format(endDate);\n }\n\n const { days, hours, minutes, seconds, isFinished } = timeRemaining;\n\n if (isFinished) {\n return \"00:00:00\";\n }\n\n if (format === \"datetime\") {\n const endDate = new Date(end);\n const dateString = dateFormatter.format(endDate);\n const timeString = `${String(hours).padStart(2, \"0\")}:${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`;\n return `${dateString} ${timeString}`;\n }\n\n if (days > 0) {\n return `${days}d ${String(hours).padStart(2, \"0\")}h ${String(minutes).padStart(2, \"0\")}m`;\n }\n\n return `${String(hours).padStart(2, \"0\")}:${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`;\n };\n\n const displayVariant = timeRemaining.isFinished ? \"destructive\" : variant;\n\n return (\n <div\n className={[\n styles.countdownTimer,\n styles[displayVariant],\n timeRemaining.isFinished ? styles.finished : null,\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n {...props}\n >\n <span className={styles.value}>{formatTime()}</span>\n </div>\n );\n}\n"],"mappings":"wJAiCA,SAAgB,EAAe,CAC3B,QACA,MACA,SAAS,OACT,UAAU,SACV,SACA,YACA,GAAG,GACiB,CACpB,IAAM,EAAgB,EAAA,sBAAsB,CACtC,CAAC,EAAe,IAAA,EAAA,EAAA,UAAmD,KAAK,CACxE,CAAC,EAAmB,IAAA,EAAA,EAAA,UAAiC,GAAM,CAmDjE,IAjDA,EAAA,EAAA,eAAgB,CACZ,IAAM,MAA8C,CAChD,IAAM,EAAM,IAAI,KAGV,EAFU,IAAI,KAAK,EAAI,CAAC,SAAS,CACvB,EAAI,SAAS,CAkB7B,OAfI,GAAc,EACP,CACH,KAAM,EACN,MAAO,EACP,QAAS,EACT,QAAS,EACT,WAAY,GACf,CAQE,CACH,KANS,KAAK,MAAM,GAAc,IAAO,GAAK,GAAK,IAAI,CAOvD,MANU,KAAK,MAAO,GAAc,IAAO,GAAK,IAAO,GAAG,CAO1D,QANY,KAAK,MAAO,EAAa,IAAO,GAAM,GAAG,CAOrD,QANY,KAAK,MAAO,EAAa,IAAQ,GAAG,CAOhD,WAAY,GACf,EAIL,EAAiB,GAAwB,CAAC,CAG1C,IAAM,EAAW,gBAAkB,CAC/B,IAAM,EAAY,GAAwB,CAC1C,EAAiB,EAAU,CAGvB,EAAU,YAAc,CAAC,IACzB,KAAU,CACV,EAAqB,GAAK,GAE/B,IAAK,CAER,UAAa,cAAc,EAAS,EACrC,CAAC,EAAK,EAAQ,EAAkB,CAAC,CAEhC,CAAC,EACD,OAAO,KAGX,IAAM,MAA2B,CAC7B,GAAI,IAAW,OAAQ,CACnB,IAAM,EAAU,IAAI,KAAK,EAAI,CAC7B,OAAO,EAAc,OAAO,EAAQ,CAGxC,GAAM,CAAE,OAAM,QAAO,UAAS,UAAS,cAAe,EAEtD,GAAI,EACA,MAAO,WAGX,GAAI,IAAW,WAAY,CACvB,IAAM,EAAU,IAAI,KAAK,EAAI,CAG7B,MAAO,GAFY,EAAc,OAAO,EAAQ,CAE3B,GADF,GAAG,OAAO,EAAM,CAAC,SAAS,EAAG,IAAI,CAAC,GAAG,OAAO,EAAQ,CAAC,SAAS,EAAG,IAAI,CAAC,GAAG,OAAO,EAAQ,CAAC,SAAS,EAAG,IAAI,KAQhI,OAJI,EAAO,EACA,GAAG,EAAK,IAAI,OAAO,EAAM,CAAC,SAAS,EAAG,IAAI,CAAC,IAAI,OAAO,EAAQ,CAAC,SAAS,EAAG,IAAI,CAAC,GAGpF,GAAG,OAAO,EAAM,CAAC,SAAS,EAAG,IAAI,CAAC,GAAG,OAAO,EAAQ,CAAC,SAAS,EAAG,IAAI,CAAC,GAAG,OAAO,EAAQ,CAAC,SAAS,EAAG,IAAI,IAG9G,EAAiB,EAAc,WAAa,cAAgB,EAElE,OACI,EAAA,EAAA,KAAC,MAAD,CACI,UAAW,CACP,EAAA,QAAO,eACP,EAAA,QAAO,GACP,EAAc,WAAa,EAAA,QAAO,SAAW,KAC7C,EACH,CACI,OAAO,QAAQ,CACf,KAAK,IAAI,CACd,GAAI,YAEJ,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAA,QAAO,eAAQ,GAAY,CAAQ,CAAA,CAClD,CAAA"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import e from "
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { useDateTimeFormatter as e } from "../GnomeProvider/GnomeContext.js";
|
|
2
|
+
import t from "./CountDownTimer.module.css.js";
|
|
3
|
+
import { useEffect as n, useState as r } from "react";
|
|
4
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
4
5
|
//#region src/components/CountDownTimer/CountDownTimer.tsx
|
|
5
|
-
function
|
|
6
|
-
let [
|
|
7
|
-
if (
|
|
6
|
+
function a({ start: a, end: o, format: s = "time", variant: c = "accent", action: l, className: u, ...d }) {
|
|
7
|
+
let f = e(), [p, m] = r(null), [h, g] = r(!1);
|
|
8
|
+
if (n(() => {
|
|
8
9
|
let e = () => {
|
|
9
|
-
let e = /* @__PURE__ */ new Date(), t = new Date(
|
|
10
|
+
let e = /* @__PURE__ */ new Date(), t = new Date(o).getTime() - e.getTime();
|
|
10
11
|
return t <= 0 ? {
|
|
11
12
|
days: 0,
|
|
12
13
|
hours: 0,
|
|
@@ -21,37 +22,45 @@ function i({ start: i, end: a, format: o = "time", variant: s = "accent", action
|
|
|
21
22
|
isFinished: !1
|
|
22
23
|
};
|
|
23
24
|
};
|
|
24
|
-
|
|
25
|
+
m(e());
|
|
25
26
|
let t = setInterval(() => {
|
|
26
27
|
let t = e();
|
|
27
|
-
|
|
28
|
+
m(t), t.isFinished && !h && (l?.(), g(!0));
|
|
28
29
|
}, 1e3);
|
|
29
30
|
return () => clearInterval(t);
|
|
30
31
|
}, [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
]), !
|
|
35
|
-
let
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
o,
|
|
33
|
+
l,
|
|
34
|
+
h
|
|
35
|
+
]), !p) return null;
|
|
36
|
+
let _ = () => {
|
|
37
|
+
if (s === "date") {
|
|
38
|
+
let e = new Date(o);
|
|
39
|
+
return f.format(e);
|
|
40
|
+
}
|
|
41
|
+
let { days: e, hours: t, minutes: n, seconds: r, isFinished: i } = p;
|
|
42
|
+
if (i) return "00:00:00";
|
|
43
|
+
if (s === "datetime") {
|
|
44
|
+
let e = new Date(o);
|
|
45
|
+
return `${f.format(e)} ${`${String(t).padStart(2, "0")}:${String(n).padStart(2, "0")}:${String(r).padStart(2, "0")}`}`;
|
|
46
|
+
}
|
|
47
|
+
return e > 0 ? `${e}d ${String(t).padStart(2, "0")}h ${String(n).padStart(2, "0")}m` : `${String(t).padStart(2, "0")}:${String(n).padStart(2, "0")}:${String(r).padStart(2, "0")}`;
|
|
48
|
+
}, v = p.isFinished ? "destructive" : c;
|
|
49
|
+
return /* @__PURE__ */ i("div", {
|
|
41
50
|
className: [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
t.countdownTimer,
|
|
52
|
+
t[v],
|
|
53
|
+
p.isFinished ? t.finished : null,
|
|
54
|
+
u
|
|
46
55
|
].filter(Boolean).join(" "),
|
|
47
|
-
...
|
|
48
|
-
children: /* @__PURE__ */
|
|
49
|
-
className:
|
|
50
|
-
children:
|
|
56
|
+
...d,
|
|
57
|
+
children: /* @__PURE__ */ i("span", {
|
|
58
|
+
className: t.value,
|
|
59
|
+
children: _()
|
|
51
60
|
})
|
|
52
61
|
});
|
|
53
62
|
}
|
|
54
63
|
//#endregion
|
|
55
|
-
export {
|
|
64
|
+
export { a as CountDownTimer };
|
|
56
65
|
|
|
57
66
|
//# sourceMappingURL=CountDownTimer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CountDownTimer.js","names":[],"sources":["../../../src/components/CountDownTimer/CountDownTimer.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport styles from \"./CountDownTimer.module.css\";\n\nexport type CountDownVariant = \"accent\" | \"destructive\" | \"success\" | \"warning\";\n\nexport interface CountDownTimerProps extends HTMLAttributes<HTMLDivElement> {\n /** Start date for the countdown */\n start: Date;\n /** End date for the countdown */\n end: Date;\n /** Format to display: \"date\", \"time\", or \"datetime\" */\n format?: \"date\" | \"time\" | \"datetime\";\n /** Visual style variant. Defaults to `\"accent\"`. */\n variant?: CountDownVariant;\n /** Callback action to execute when countdown reaches zero */\n action?: () => void;\n}\n\ninterface TimeRemaining {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n isFinished: boolean;\n}\n\n/**\n * CountDown timer component that displays remaining time and executes an action when time runs out.\n *\n * @see https://developer.gnome.org/hig/patterns/\n */\nexport function CountDownTimer({\n start,\n end,\n format = \"time\",\n variant = \"accent\",\n action,\n className,\n ...props\n}: CountDownTimerProps) {\n const [timeRemaining, setTimeRemaining] = useState<TimeRemaining | null>(null);\n const [hasExecutedAction, setHasExecutedAction] = useState(false);\n\n useEffect(() => {\n const calculateTimeRemaining = (): TimeRemaining => {\n const now = new Date();\n const endTime = new Date(end).getTime();\n const nowTime = now.getTime();\n const difference = endTime - nowTime;\n\n if (difference <= 0) {\n return {\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n isFinished: true,\n };\n }\n\n const days = Math.floor(difference / (1000 * 60 * 60 * 24));\n const hours = Math.floor((difference / (1000 * 60 * 60)) % 24);\n const minutes = Math.floor((difference / 1000 / 60) % 60);\n const seconds = Math.floor((difference / 1000) % 60);\n\n return {\n days,\n hours,\n minutes,\n seconds,\n isFinished: false,\n };\n };\n\n // Initial calculation\n setTimeRemaining(calculateTimeRemaining());\n\n // Update every second\n const interval = setInterval(() => {\n const remaining = calculateTimeRemaining();\n setTimeRemaining(remaining);\n\n // Execute action when countdown finishes\n if (remaining.isFinished && !hasExecutedAction) {\n action?.();\n setHasExecutedAction(true);\n }\n }, 1000);\n\n return () => clearInterval(interval);\n }, [end, action, hasExecutedAction]);\n\n if (!timeRemaining) {\n return null;\n }\n\n const formatTime = (): string => {\n if (format === \"date\") {\n const endDate = new Date(end);\n return
|
|
1
|
+
{"version":3,"file":"CountDownTimer.js","names":[],"sources":["../../../src/components/CountDownTimer/CountDownTimer.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport styles from \"./CountDownTimer.module.css\";\nimport { useDateTimeFormatter } from \"../GnomeProvider/GnomeContext\";\n\nexport type CountDownVariant = \"accent\" | \"destructive\" | \"success\" | \"warning\";\n\nexport interface CountDownTimerProps extends HTMLAttributes<HTMLDivElement> {\n /** Start date for the countdown */\n start: Date;\n /** End date for the countdown */\n end: Date;\n /** Format to display: \"date\", \"time\", or \"datetime\" */\n format?: \"date\" | \"time\" | \"datetime\";\n /** Visual style variant. Defaults to `\"accent\"`. */\n variant?: CountDownVariant;\n /** Callback action to execute when countdown reaches zero */\n action?: () => void;\n}\n\ninterface TimeRemaining {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n isFinished: boolean;\n}\n\n/**\n * CountDown timer component that displays remaining time and executes an action when time runs out.\n *\n * @see https://developer.gnome.org/hig/patterns/\n */\nexport function CountDownTimer({\n start,\n end,\n format = \"time\",\n variant = \"accent\",\n action,\n className,\n ...props\n}: CountDownTimerProps) {\n const dateFormatter = useDateTimeFormatter();\n const [timeRemaining, setTimeRemaining] = useState<TimeRemaining | null>(null);\n const [hasExecutedAction, setHasExecutedAction] = useState(false);\n\n useEffect(() => {\n const calculateTimeRemaining = (): TimeRemaining => {\n const now = new Date();\n const endTime = new Date(end).getTime();\n const nowTime = now.getTime();\n const difference = endTime - nowTime;\n\n if (difference <= 0) {\n return {\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n isFinished: true,\n };\n }\n\n const days = Math.floor(difference / (1000 * 60 * 60 * 24));\n const hours = Math.floor((difference / (1000 * 60 * 60)) % 24);\n const minutes = Math.floor((difference / 1000 / 60) % 60);\n const seconds = Math.floor((difference / 1000) % 60);\n\n return {\n days,\n hours,\n minutes,\n seconds,\n isFinished: false,\n };\n };\n\n // Initial calculation\n setTimeRemaining(calculateTimeRemaining());\n\n // Update every second\n const interval = setInterval(() => {\n const remaining = calculateTimeRemaining();\n setTimeRemaining(remaining);\n\n // Execute action when countdown finishes\n if (remaining.isFinished && !hasExecutedAction) {\n action?.();\n setHasExecutedAction(true);\n }\n }, 1000);\n\n return () => clearInterval(interval);\n }, [end, action, hasExecutedAction]);\n\n if (!timeRemaining) {\n return null;\n }\n\n const formatTime = (): string => {\n if (format === \"date\") {\n const endDate = new Date(end);\n return dateFormatter.format(endDate);\n }\n\n const { days, hours, minutes, seconds, isFinished } = timeRemaining;\n\n if (isFinished) {\n return \"00:00:00\";\n }\n\n if (format === \"datetime\") {\n const endDate = new Date(end);\n const dateString = dateFormatter.format(endDate);\n const timeString = `${String(hours).padStart(2, \"0\")}:${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`;\n return `${dateString} ${timeString}`;\n }\n\n if (days > 0) {\n return `${days}d ${String(hours).padStart(2, \"0\")}h ${String(minutes).padStart(2, \"0\")}m`;\n }\n\n return `${String(hours).padStart(2, \"0\")}:${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`;\n };\n\n const displayVariant = timeRemaining.isFinished ? \"destructive\" : variant;\n\n return (\n <div\n className={[\n styles.countdownTimer,\n styles[displayVariant],\n timeRemaining.isFinished ? styles.finished : null,\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n {...props}\n >\n <span className={styles.value}>{formatTime()}</span>\n </div>\n );\n}\n"],"mappings":";;;;;AAiCA,SAAgB,EAAe,EAC3B,UACA,QACA,YAAS,QACT,aAAU,UACV,WACA,cACA,GAAG,KACiB;CACpB,IAAM,IAAgB,GAAsB,EACtC,CAAC,GAAe,KAAoB,EAA+B,KAAK,EACxE,CAAC,GAAmB,KAAwB,EAAS,GAAM;AAmDjE,KAjDA,QAAgB;EACZ,IAAM,UAA8C;GAChD,IAAM,oBAAM,IAAI,MAAM,EAGhB,IAFU,IAAI,KAAK,EAAI,CAAC,SAAS,GACvB,EAAI,SAAS;AAkB7B,UAfI,KAAc,IACP;IACH,MAAM;IACN,OAAO;IACP,SAAS;IACT,SAAS;IACT,YAAY;IACf,GAQE;IACH,MANS,KAAK,MAAM,KAAc,MAAO,KAAK,KAAK,IAAI;IAOvD,OANU,KAAK,MAAO,KAAc,MAAO,KAAK,MAAO,GAAG;IAO1D,SANY,KAAK,MAAO,IAAa,MAAO,KAAM,GAAG;IAOrD,SANY,KAAK,MAAO,IAAa,MAAQ,GAAG;IAOhD,YAAY;IACf;;AAIL,IAAiB,GAAwB,CAAC;EAG1C,IAAM,IAAW,kBAAkB;GAC/B,IAAM,IAAY,GAAwB;AAI1C,GAHA,EAAiB,EAAU,EAGvB,EAAU,cAAc,CAAC,MACzB,KAAU,EACV,EAAqB,GAAK;KAE/B,IAAK;AAER,eAAa,cAAc,EAAS;IACrC;EAAC;EAAK;EAAQ;EAAkB,CAAC,EAEhC,CAAC,EACD,QAAO;CAGX,IAAM,UAA2B;AAC7B,MAAI,MAAW,QAAQ;GACnB,IAAM,IAAU,IAAI,KAAK,EAAI;AAC7B,UAAO,EAAc,OAAO,EAAQ;;EAGxC,IAAM,EAAE,SAAM,UAAO,YAAS,YAAS,kBAAe;AAEtD,MAAI,EACA,QAAO;AAGX,MAAI,MAAW,YAAY;GACvB,IAAM,IAAU,IAAI,KAAK,EAAI;AAG7B,UAAO,GAFY,EAAc,OAAO,EAAQ,CAE3B,GADF,GAAG,OAAO,EAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,OAAO,EAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,OAAO,EAAQ,CAAC,SAAS,GAAG,IAAI;;AAQhI,SAJI,IAAO,IACA,GAAG,EAAK,IAAI,OAAO,EAAM,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,OAAO,EAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,KAGpF,GAAG,OAAO,EAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,OAAO,EAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,OAAO,EAAQ,CAAC,SAAS,GAAG,IAAI;IAG9G,IAAiB,EAAc,aAAa,gBAAgB;AAElE,QACI,kBAAC,OAAD;EACI,WAAW;GACP,EAAO;GACP,EAAO;GACP,EAAc,aAAa,EAAO,WAAW;GAC7C;GACH,CACI,OAAO,QAAQ,CACf,KAAK,IAAI;EACd,GAAI;YAEJ,kBAAC,QAAD;GAAM,WAAW,EAAO;aAAQ,GAAY;GAAQ,CAAA;EAClD,CAAA"}
|