@activecollab/components 2.0.417 → 2.0.419

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.
Files changed (71) hide show
  1. package/dist/cjs/components/Icons/collection/Portfolio.js +61 -0
  2. package/dist/cjs/components/Icons/collection/Portfolio.js.map +1 -0
  3. package/dist/cjs/components/Icons/collection/PortfolioPlus.js +62 -0
  4. package/dist/cjs/components/Icons/collection/PortfolioPlus.js.map +1 -0
  5. package/dist/cjs/components/Icons/collection/Target.js +65 -0
  6. package/dist/cjs/components/Icons/collection/Target.js.map +1 -0
  7. package/dist/cjs/components/Icons/collection/index.js +21 -0
  8. package/dist/cjs/components/Icons/collection/index.js.map +1 -1
  9. package/dist/cjs/presentation/shared/MessageDialog.js +62 -107
  10. package/dist/cjs/presentation/shared/MessageDialog.js.map +1 -1
  11. package/dist/cjs/presentation/shared/MessageFeedback.js +284 -0
  12. package/dist/cjs/presentation/shared/MessageFeedback.js.map +1 -0
  13. package/dist/cjs/presentation/shared/PortfolioOptionsMenu.js +64 -0
  14. package/dist/cjs/presentation/shared/PortfolioOptionsMenu.js.map +1 -0
  15. package/dist/cjs/presentation/shared/ProjectOptionsMenu.js +367 -0
  16. package/dist/cjs/presentation/shared/ProjectOptionsMenu.js.map +1 -0
  17. package/dist/cjs/presentation/shared/dashboardWidgets.js +726 -0
  18. package/dist/cjs/presentation/shared/dashboardWidgets.js.map +1 -0
  19. package/dist/cjs/presentation/shared/headers.js +25 -360
  20. package/dist/cjs/presentation/shared/headers.js.map +1 -1
  21. package/dist/cjs/presentation/shared/index.js +130 -0
  22. package/dist/cjs/presentation/shared/index.js.map +1 -1
  23. package/dist/esm/components/Icons/collection/Portfolio.d.ts +32 -0
  24. package/dist/esm/components/Icons/collection/Portfolio.d.ts.map +1 -0
  25. package/dist/esm/components/Icons/collection/Portfolio.js +54 -0
  26. package/dist/esm/components/Icons/collection/Portfolio.js.map +1 -0
  27. package/dist/esm/components/Icons/collection/PortfolioPlus.d.ts +32 -0
  28. package/dist/esm/components/Icons/collection/PortfolioPlus.d.ts.map +1 -0
  29. package/dist/esm/components/Icons/collection/PortfolioPlus.js +55 -0
  30. package/dist/esm/components/Icons/collection/PortfolioPlus.js.map +1 -0
  31. package/dist/esm/components/Icons/collection/Target.d.ts +32 -0
  32. package/dist/esm/components/Icons/collection/Target.d.ts.map +1 -0
  33. package/dist/esm/components/Icons/collection/Target.js +58 -0
  34. package/dist/esm/components/Icons/collection/Target.js.map +1 -0
  35. package/dist/esm/components/Icons/collection/index.d.ts +3 -0
  36. package/dist/esm/components/Icons/collection/index.d.ts.map +1 -1
  37. package/dist/esm/components/Icons/collection/index.js +3 -0
  38. package/dist/esm/components/Icons/collection/index.js.map +1 -1
  39. package/dist/esm/presentation/shared/MessageDialog.d.ts +8 -3
  40. package/dist/esm/presentation/shared/MessageDialog.d.ts.map +1 -1
  41. package/dist/esm/presentation/shared/MessageDialog.js +64 -98
  42. package/dist/esm/presentation/shared/MessageDialog.js.map +1 -1
  43. package/dist/esm/presentation/shared/MessageFeedback.d.ts +54 -0
  44. package/dist/esm/presentation/shared/MessageFeedback.d.ts.map +1 -0
  45. package/dist/esm/presentation/shared/MessageFeedback.js +252 -0
  46. package/dist/esm/presentation/shared/MessageFeedback.js.map +1 -0
  47. package/dist/esm/presentation/shared/PortfolioOptionsMenu.d.ts +12 -0
  48. package/dist/esm/presentation/shared/PortfolioOptionsMenu.d.ts.map +1 -0
  49. package/dist/esm/presentation/shared/PortfolioOptionsMenu.js +46 -0
  50. package/dist/esm/presentation/shared/PortfolioOptionsMenu.js.map +1 -0
  51. package/dist/esm/presentation/shared/ProjectOptionsMenu.d.ts +31 -0
  52. package/dist/esm/presentation/shared/ProjectOptionsMenu.d.ts.map +1 -0
  53. package/dist/esm/presentation/shared/ProjectOptionsMenu.js +311 -0
  54. package/dist/esm/presentation/shared/ProjectOptionsMenu.js.map +1 -0
  55. package/dist/esm/presentation/shared/dashboardWidgets.d.ts +203 -0
  56. package/dist/esm/presentation/shared/dashboardWidgets.d.ts.map +1 -0
  57. package/dist/esm/presentation/shared/dashboardWidgets.js +665 -0
  58. package/dist/esm/presentation/shared/dashboardWidgets.js.map +1 -0
  59. package/dist/esm/presentation/shared/headers.d.ts +0 -11
  60. package/dist/esm/presentation/shared/headers.d.ts.map +1 -1
  61. package/dist/esm/presentation/shared/headers.js +23 -315
  62. package/dist/esm/presentation/shared/headers.js.map +1 -1
  63. package/dist/esm/presentation/shared/index.d.ts +8 -0
  64. package/dist/esm/presentation/shared/index.d.ts.map +1 -1
  65. package/dist/esm/presentation/shared/index.js +4 -0
  66. package/dist/esm/presentation/shared/index.js.map +1 -1
  67. package/dist/index.js +666 -508
  68. package/dist/index.js.map +1 -1
  69. package/dist/index.min.js +1 -1
  70. package/dist/index.min.js.map +1 -1
  71. package/package.json +1 -1
@@ -0,0 +1,665 @@
1
+ import React, { useState } from "react";
2
+ import styled from "styled-components";
3
+ import { LG, MD, SM } from "./tokens";
4
+ import { IconButton } from "../../components/IconButton";
5
+ import { InfoSmallIcon, SortListIcon } from "../../components/Icons";
6
+ import { ProgressBar } from "../../components/ProgressBar";
7
+ import { ProgressRing } from "../../components/ProgressRing";
8
+ import { Select } from "../../components/Select";
9
+ import { Tooltip } from "../../components/Tooltip";
10
+ import { Body1, Body2, Header2, Title2 } from "../../components/Typography";
11
+ import { ValueButton } from "../../components/ValueButton";
12
+ import { colors } from "../../utils/colors";
13
+
14
+ /*
15
+ Reusable dashboard widgets for the Presentation mock-ups.
16
+
17
+ These mirror the REAL report widgets in new-activecollab-front
18
+ (src/pages/Reports/Widgets/*): Widget.js (the stat card), WidgetList.js
19
+ (the striped ranked list), ProjectsOverview.js (accent-line sections +
20
+ nested ProgressRings), DailyOpenTasksWidget.js (area line chart),
21
+ DailyCreatedAndCompletedTasksWidget.js (daily +/- bars),
22
+ LeaderboardWidget.js and TotalTrackedHoursChart.js (stacked columns).
23
+ Dimensions, type sizes and colours are copied from that code so any
24
+ dashboard mock built from these reads exactly like the app; the charts are
25
+ plain SVG/CSS here (no chart.js in this Storybook).
26
+
27
+ Data colours (chart palette, tick grey #89898e) are hardcoded on purpose —
28
+ they are data, not theme — while all structure uses var(--…) tokens.
29
+ */
30
+
31
+ /* Raw (non-Typography) text needs an explicit font — no global reset here. */
32
+ const FONT_STACK = '-apple-system, BlinkMacSystemFont, "Roboto", "Helvetica Neue", Arial, sans-serif';
33
+
34
+ /** Axis-tick grey, same literal the real chart widgets use. */
35
+ const TICK_COLOR = "#89898e";
36
+
37
+ /** Stacked-chart series palette, same order as TotalTrackedHoursChart.js. */
38
+ export const CHART_SERIES_COLORS = [colors.blueSky.color, colors.coral.color, colors.greenPale.color, colors.orange.color, colors.purple.color, colors.pink.color];
39
+
40
+ /** Ring/section colour pairs used by the app's Projects Overview widget. */
41
+ export const OVERVIEW_SECTION_COLORS = {
42
+ tasks: {
43
+ color: colors.purple.color,
44
+ track: "rgba(190, 172, 249, 0.2)"
45
+ },
46
+ time: {
47
+ color: colors.blueSky.color,
48
+ track: "rgba(163, 205, 255, 0.2)"
49
+ },
50
+ budget: {
51
+ color: colors.greenPale.color,
52
+ track: "rgba(195, 231, 153, 0.2)"
53
+ }
54
+ };
55
+
56
+ /* ------------------------------------------------------------------ */
57
+ /* Widget grid (mirrors AssignmentsDashboardGrid.js) */
58
+ /* ------------------------------------------------------------------ */
59
+
60
+ /*
61
+ The dashboard grid: 24px gaps, 192px rows, 1/2/3/4 columns by breakpoint.
62
+ Put DS <Paper type="paper-2"> cells directly inside and size them with:
63
+ .cell-overview — the big overview card (2×2 on desktop)
64
+ .cell-tall — a 1×2 card (ranked lists)
65
+ .cell-wide — a full-width row (charts)
66
+ Plain cells are 1×1 (stat cards).
67
+ */
68
+ export const WidgetGrid = styled.div.withConfig({
69
+ displayName: "dashboardWidgets__WidgetGrid",
70
+ componentId: "sc-lm5ek4-0"
71
+ })(["display:grid;gap:24px;width:100%;max-width:1440px;margin:0 auto 32px;grid-template-columns:repeat(1,minmax(0,1fr));grid-auto-rows:192px;@media (min-width:", "){grid-template-columns:repeat(2,minmax(0,1fr));}@media (min-width:", "){grid-template-columns:repeat(3,minmax(0,1fr));}@media (min-width:", "){grid-template-columns:repeat(4,minmax(0,1fr));}> .cell-overview{grid-row:span 3;@media (min-width:", "){grid-row:span 2;grid-column:span 2;}@media (min-width:", "){grid-column:span 3;}@media (min-width:", "){grid-column:span 2;}}> .cell-tall{grid-row:span 2;}> .cell-wide{@media (min-width:", "){grid-column:span 2;}@media (min-width:", "){grid-column:span 3;}@media (min-width:", "){grid-column:span 4;}}"], SM, MD, LG, SM, MD, LG, SM, MD, LG);
72
+ WidgetGrid.displayName = "WidgetGrid";
73
+
74
+ /* ------------------------------------------------------------------ */
75
+ /* Group-by picker (mirrors WidgetTarget in Widget.js) */
76
+ /* ------------------------------------------------------------------ */
77
+
78
+ /** The sort-lines icon button + radio list every widget corner uses. */
79
+ export const WidgetGroupBy = _ref => {
80
+ var _options$;
81
+ let options = _ref.options,
82
+ initial = _ref.initial,
83
+ onChange = _ref.onChange;
84
+ const _useState = useState(initial != null ? initial : (_options$ = options[0]) == null ? void 0 : _options$.id),
85
+ selected = _useState[0],
86
+ setSelected = _useState[1];
87
+ const _useState2 = useState(false),
88
+ open = _useState2[0],
89
+ setOpen = _useState2[1];
90
+ return /*#__PURE__*/React.createElement(Select, {
91
+ options: options,
92
+ selected: selected,
93
+ onChange: value => {
94
+ setSelected(String(value));
95
+ onChange == null || onChange(String(value));
96
+ },
97
+ onSelectOpen: () => setOpen(true),
98
+ onSelectClose: () => setOpen(false),
99
+ position: "bottom-end",
100
+ forceCloseMenu: true,
101
+ disableSearch: true,
102
+ keepSameOptionsOrder: true,
103
+ disabledInternalSort: true,
104
+ target: /*#__PURE__*/React.createElement(IconButton, {
105
+ type: "button",
106
+ variant: "text gray",
107
+ active: open
108
+ }, /*#__PURE__*/React.createElement(SortListIcon, {
109
+ fill: "var(--color-theme-800)"
110
+ }))
111
+ });
112
+ };
113
+ WidgetGroupBy.displayName = "WidgetGroupBy";
114
+
115
+ /* ------------------------------------------------------------------ */
116
+ /* Time-period picker (the completed widgets' shared control) */
117
+ /* ------------------------------------------------------------------ */
118
+
119
+ /** The app's completed-widget periods (CompletedWidgetTarget radio list). */
120
+ export const PERIOD_OPTIONS = [{
121
+ id: "this_week",
122
+ name: "This Week"
123
+ }, {
124
+ id: "last_week",
125
+ name: "Last Week"
126
+ }, {
127
+ id: "this_month",
128
+ name: "This Month"
129
+ }, {
130
+ id: "last_month",
131
+ name: "Last Month"
132
+ }, {
133
+ id: "this_quarter",
134
+ name: "This Quarter"
135
+ }, {
136
+ id: "last_quarter",
137
+ name: "Last Quarter"
138
+ }, {
139
+ id: "this_year",
140
+ name: "This Year"
141
+ }, {
142
+ id: "last_year",
143
+ name: "Last Year"
144
+ }];
145
+ /** One labelled period control (ValueButton + radio list) that a whole
146
+ * section of period-scoped widgets can share. */
147
+ export const PeriodPicker = _ref2 => {
148
+ var _PERIOD_OPTIONS$find$, _PERIOD_OPTIONS$find;
149
+ let selected = _ref2.selected,
150
+ onChange = _ref2.onChange;
151
+ const _useState3 = useState(false),
152
+ open = _useState3[0],
153
+ setOpen = _useState3[1];
154
+ const value = (_PERIOD_OPTIONS$find$ = (_PERIOD_OPTIONS$find = PERIOD_OPTIONS.find(option => option.id === selected)) == null ? void 0 : _PERIOD_OPTIONS$find.name) != null ? _PERIOD_OPTIONS$find$ : "";
155
+ return /*#__PURE__*/React.createElement(Select, {
156
+ options: PERIOD_OPTIONS,
157
+ selected: selected,
158
+ onChange: next => onChange(String(next)),
159
+ onSelectOpen: () => setOpen(true),
160
+ onSelectClose: () => setOpen(false),
161
+ position: "bottom-end",
162
+ forceCloseMenu: true,
163
+ disableSearch: true,
164
+ keepSameOptionsOrder: true,
165
+ disabledInternalSort: true,
166
+ target: /*#__PURE__*/React.createElement(ValueButton, {
167
+ active: open,
168
+ label: "Period",
169
+ value: value
170
+ })
171
+ });
172
+ };
173
+ PeriodPicker.displayName = "PeriodPicker";
174
+
175
+ /* ------------------------------------------------------------------ */
176
+ /* Stat widget (mirrors Widget.js) */
177
+ /* ------------------------------------------------------------------ */
178
+
179
+ const StyledWidget = styled.div.withConfig({
180
+ displayName: "dashboardWidgets__StyledWidget",
181
+ componentId: "sc-lm5ek4-1"
182
+ })(["position:relative;height:100%;padding:16px 20px;box-sizing:border-box;overflow:hidden;.widget-top{display:flex;justify-content:space-between;gap:8px;}.widget-corner{display:flex;align-items:center;gap:4px;flex-shrink:0;}.widget-total{display:flex;width:100%;height:56px;margin-bottom:8px;font-family:", ";font-size:52px;font-weight:700;line-height:1;color:var(--color-theme-900);}.widget-total.alert{color:var(--red-alert);}.widget-total.success{color:", ";}.widget-total .widget-unit{align-self:center;margin-left:10px;font-size:20px;font-weight:600;line-height:1;color:var(--color-theme-600);}.widget-title{margin-bottom:8px;}.widget-desc{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;height:40px;margin-bottom:8px;}.widget-link{display:inline-flex;cursor:pointer;text-decoration:none;}"], FONT_STACK, colors.greenSuccess.color);
183
+ export const StatWidget = _ref3 => {
184
+ let value = _ref3.value,
185
+ unit = _ref3.unit,
186
+ title = _ref3.title,
187
+ description = _ref3.description,
188
+ linkText = _ref3.linkText,
189
+ alert = _ref3.alert,
190
+ success = _ref3.success,
191
+ groupBy = _ref3.groupBy,
192
+ cornerControl = _ref3.cornerControl,
193
+ children = _ref3.children;
194
+ return /*#__PURE__*/React.createElement(StyledWidget, null, /*#__PURE__*/React.createElement("div", {
195
+ className: "widget-top"
196
+ }, /*#__PURE__*/React.createElement("span", {
197
+ className: alert ? "widget-total alert" : success ? "widget-total success" : "widget-total"
198
+ }, value, unit ? /*#__PURE__*/React.createElement("span", {
199
+ className: "widget-unit"
200
+ }, unit) : null), cornerControl || groupBy ? /*#__PURE__*/React.createElement("span", {
201
+ className: "widget-corner"
202
+ }, cornerControl, groupBy ? /*#__PURE__*/React.createElement(WidgetGroupBy, groupBy) : null) : null), /*#__PURE__*/React.createElement(Body1, {
203
+ weight: "bold",
204
+ color: alert ? "alert" : "primary",
205
+ overflow: "truncate",
206
+ whitespace: "no-wrap",
207
+ className: "widget-title"
208
+ }, title), /*#__PURE__*/React.createElement(Body2, {
209
+ color: "tertiary",
210
+ className: "widget-desc"
211
+ }, description), children, linkText ? /*#__PURE__*/React.createElement("a", {
212
+ className: "widget-link"
213
+ }, /*#__PURE__*/React.createElement(Body2, {
214
+ color: "theme-primary",
215
+ weight: "medium"
216
+ }, linkText)) : null);
217
+ };
218
+ StatWidget.displayName = "StatWidget";
219
+
220
+ /* ------------------------------------------------------------------ */
221
+ /* Ranked list (mirrors WidgetList.js) */
222
+ /* ------------------------------------------------------------------ */
223
+
224
+ const StyledRankedList = styled.div.withConfig({
225
+ displayName: "dashboardWidgets__StyledRankedList",
226
+ componentId: "sc-lm5ek4-2"
227
+ })(["height:216px;overflow-y:auto;padding:4px 0;.ranked-row{display:flex;align-items:center;justify-content:space-between;gap:4px;height:24px;padding:0 6px;margin-bottom:4px;border-radius:2px;box-sizing:border-box;}.ranked-row:nth-child(odd){background-color:var(--color-theme-200);}.ranked-name{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.ranked-value{flex-shrink:0;}"]);
228
+
229
+ /** The striped name/count rows inside a tall stat widget. */
230
+ export const WidgetRankedList = _ref4 => {
231
+ let items = _ref4.items;
232
+ return /*#__PURE__*/React.createElement(StyledRankedList, null, items.map(item => /*#__PURE__*/React.createElement("div", {
233
+ className: "ranked-row",
234
+ key: item.name
235
+ }, /*#__PURE__*/React.createElement(Body2, {
236
+ color: "secondary",
237
+ className: "ranked-name"
238
+ }, item.name), /*#__PURE__*/React.createElement(Body2, {
239
+ color: "secondary",
240
+ className: "ranked-value"
241
+ }, item.value))));
242
+ };
243
+ WidgetRankedList.displayName = "WidgetRankedList";
244
+
245
+ /* ------------------------------------------------------------------ */
246
+ /* Overview widget (mirrors ProjectsOverview.js) */
247
+ /* ------------------------------------------------------------------ */
248
+
249
+ const RING_RADII = [121, 93, 63];
250
+ const RING_STROKE = 20;
251
+ const StyledOverview = styled.div.withConfig({
252
+ displayName: "dashboardWidgets__StyledOverview",
253
+ componentId: "sc-lm5ek4-3"
254
+ })(["position:relative;display:flex;flex-direction:column;height:100%;padding:16px 20px;box-sizing:border-box;overflow:hidden;.overview-head{display:flex;justify-content:space-between;gap:8px;}.overview-body{display:flex;flex-direction:column-reverse;justify-content:space-between;gap:4px;height:100%;@media (min-width:", "){flex-direction:row;margin-top:48px;}}.overview-sections{display:flex;flex-direction:column;gap:24px;width:100%;height:fit-content;@media (min-width:", "){height:100%;}}.overview-section{display:flex;width:fit-content;height:fit-content;}.overview-line{width:2px;margin-right:12px;align-self:stretch;flex-shrink:0;}.overview-value{height:28px;margin-bottom:2px;}.overview-value-row{display:flex;align-items:flex-end;gap:4px;}.overview-desc{display:flex;align-items:center;gap:8px;}.overview-desc svg{cursor:help;flex-shrink:0;}.overview-link{display:inline-flex;margin-top:4px;cursor:pointer;text-decoration:none;}.overview-rings{display:flex;align-self:center;@media (min-width:", "){align-self:flex-end;}}@media (max-width:639px){.overview-rings{transform:scale(0.6);transform-origin:center;margin:-48px 0;}}"], SM, SM, SM);
255
+ const ringColor = (section, hovered) => {
256
+ const active = !hovered || hovered === section.id;
257
+ if (section.progress > 100) {
258
+ return active ? "var(--red-alert)" : "rgba(237, 97, 97, 0.25)";
259
+ }
260
+ return active ? section.color : "var(--color-theme-200)";
261
+ };
262
+ const ringTrack = (section, hovered) => {
263
+ const active = !hovered || hovered === section.id;
264
+ return active ? section.trackColor : "var(--color-theme-200)";
265
+ };
266
+ const OverviewSection = _ref5 => {
267
+ let section = _ref5.section,
268
+ onHover = _ref5.onHover;
269
+ const alert = section.progress > 100;
270
+ return /*#__PURE__*/React.createElement("div", {
271
+ className: "overview-section",
272
+ onMouseEnter: () => onHover(section.id),
273
+ onMouseLeave: () => onHover(null)
274
+ }, /*#__PURE__*/React.createElement("span", {
275
+ className: "overview-line",
276
+ style: {
277
+ backgroundColor: alert ? "var(--red-alert)" : section.color
278
+ }
279
+ }), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
280
+ className: "overview-value"
281
+ }, /*#__PURE__*/React.createElement(Title2, {
282
+ lineHeight: "tight",
283
+ weight: "bold",
284
+ color: alert ? "alert" : "primary"
285
+ }, /*#__PURE__*/React.createElement("span", {
286
+ className: "overview-value-row"
287
+ }, section.value, section.unit ? /*#__PURE__*/React.createElement(Body2, {
288
+ color: "tertiary"
289
+ }, section.unit) : null))), /*#__PURE__*/React.createElement("div", {
290
+ className: "overview-desc"
291
+ }, /*#__PURE__*/React.createElement(Body2, {
292
+ color: "tertiary"
293
+ }, section.description), section.explainer ? /*#__PURE__*/React.createElement(Tooltip, {
294
+ title: section.explainer
295
+ }, /*#__PURE__*/React.createElement(InfoSmallIcon, null)) : null), /*#__PURE__*/React.createElement("a", {
296
+ className: "overview-link"
297
+ }, /*#__PURE__*/React.createElement(Body2, {
298
+ color: "theme-primary",
299
+ weight: "medium"
300
+ }, section.linkText))));
301
+ };
302
+
303
+ /** The big overview card: accent-line metric sections + nested rings.
304
+ * Hovering a section highlights its ring and mutes the other rings,
305
+ * exactly like the app's Projects Overview. */
306
+ export const OverviewWidget = _ref6 => {
307
+ let title = _ref6.title,
308
+ subtitle = _ref6.subtitle,
309
+ sections = _ref6.sections,
310
+ headerRight = _ref6.headerRight;
311
+ const _useState4 = useState(null),
312
+ hovered = _useState4[0],
313
+ setHovered = _useState4[1];
314
+ const nestRings = index => {
315
+ const section = sections[index];
316
+ if (!section) {
317
+ return null;
318
+ }
319
+ return /*#__PURE__*/React.createElement(ProgressRing, {
320
+ roundStroke: true,
321
+ progress: section.progress,
322
+ stroke: RING_STROKE,
323
+ radius: RING_RADII[index],
324
+ progressColor: ringColor(section, hovered),
325
+ backgroundColor: ringTrack(section, hovered)
326
+ }, nestRings(index + 1));
327
+ };
328
+ return /*#__PURE__*/React.createElement(StyledOverview, null, /*#__PURE__*/React.createElement("div", {
329
+ className: "overview-head"
330
+ }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Body1, {
331
+ weight: "bold"
332
+ }, title), /*#__PURE__*/React.createElement(Body2, {
333
+ color: "secondary"
334
+ }, subtitle)), headerRight), /*#__PURE__*/React.createElement("div", {
335
+ className: "overview-body"
336
+ }, /*#__PURE__*/React.createElement("div", {
337
+ className: "overview-sections"
338
+ }, sections.map(section => /*#__PURE__*/React.createElement(OverviewSection, {
339
+ key: section.id,
340
+ section: section,
341
+ onHover: setHovered
342
+ }))), /*#__PURE__*/React.createElement("div", {
343
+ className: "overview-rings"
344
+ }, nestRings(0))));
345
+ };
346
+ OverviewWidget.displayName = "OverviewWidget";
347
+
348
+ /* ------------------------------------------------------------------ */
349
+ /* Chart scaffolding shared by the chart widgets */
350
+ /* ------------------------------------------------------------------ */
351
+
352
+ const PLOT_HEIGHT = 116;
353
+ const StyledChartWidget = styled.div.withConfig({
354
+ displayName: "dashboardWidgets__StyledChartWidget",
355
+ componentId: "sc-lm5ek4-4"
356
+ })(["position:relative;height:100%;padding:16px 20px 0;box-sizing:border-box;overflow:hidden;.chart-head{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px;}.chart-link{display:inline-flex;cursor:pointer;text-decoration:none;flex-shrink:0;}.chart-row{display:flex;gap:10px;}.chart-y-axis{position:relative;width:30px;height:", "px;flex-shrink:0;}.chart-y-tick{position:absolute;right:0;transform:translateY(-50%);font-family:", ";font-size:11px;color:", ";white-space:nowrap;}.chart-plot{position:relative;flex:1;min-width:0;height:", "px;}.chart-x-axis{display:flex;justify-content:space-between;margin-top:6px;padding-left:40px;font-family:", ";font-size:11px;color:", ";}.chart-x-axis span{white-space:nowrap;}"], PLOT_HEIGHT, FONT_STACK, TICK_COLOR, PLOT_HEIGHT, FONT_STACK, TICK_COLOR);
357
+ const ChartHead = _ref7 => {
358
+ let title = _ref7.title,
359
+ linkText = _ref7.linkText;
360
+ return /*#__PURE__*/React.createElement("div", {
361
+ className: "chart-head"
362
+ }, /*#__PURE__*/React.createElement(Body1, {
363
+ weight: "bold",
364
+ overflow: "truncate",
365
+ whitespace: "no-wrap"
366
+ }, title), linkText ? /*#__PURE__*/React.createElement("a", {
367
+ className: "chart-link"
368
+ }, /*#__PURE__*/React.createElement(Body2, {
369
+ color: "theme-primary",
370
+ weight: "medium"
371
+ }, linkText)) : null);
372
+ };
373
+
374
+ /* ------------------------------------------------------------------ */
375
+ /* Area line chart (mirrors DailyOpenTasksWidget.js) */
376
+ /* ------------------------------------------------------------------ */
377
+
378
+ /** Line + gradient fill colours from the real widget. */
379
+ const AREA_LINE = "#A3CDFF";
380
+ /** Sharp-edged line with a soft gradient below, like "Number of Open Tasks". */
381
+ export const AreaChartWidget = _ref8 => {
382
+ let title = _ref8.title,
383
+ linkText = _ref8.linkText,
384
+ points = _ref8.points,
385
+ xLabels = _ref8.xLabels,
386
+ yTicks = _ref8.yTicks;
387
+ const min = Math.min(...yTicks);
388
+ const max = Math.max(...yTicks);
389
+ const range = max - min || 1;
390
+ const W = 1000;
391
+ const toXY = (value, index) => {
392
+ const x = index / Math.max(points.length - 1, 1) * W;
393
+ const y = (max - value) / range * PLOT_HEIGHT;
394
+ return x.toFixed(1) + "," + y.toFixed(1);
395
+ };
396
+ const linePoints = points.map(toXY).join(" ");
397
+ const areaPoints = "0," + PLOT_HEIGHT + " " + linePoints + " " + W + "," + PLOT_HEIGHT;
398
+ return /*#__PURE__*/React.createElement(StyledChartWidget, null, /*#__PURE__*/React.createElement(ChartHead, {
399
+ title: title,
400
+ linkText: linkText
401
+ }), /*#__PURE__*/React.createElement("div", {
402
+ className: "chart-row"
403
+ }, /*#__PURE__*/React.createElement("div", {
404
+ className: "chart-y-axis"
405
+ }, yTicks.map(tick => /*#__PURE__*/React.createElement("span", {
406
+ key: tick,
407
+ className: "chart-y-tick",
408
+ style: {
409
+ top: (max - tick) / range * PLOT_HEIGHT + "px"
410
+ }
411
+ }, tick))), /*#__PURE__*/React.createElement("div", {
412
+ className: "chart-plot"
413
+ }, /*#__PURE__*/React.createElement("svg", {
414
+ width: "100%",
415
+ height: PLOT_HEIGHT,
416
+ viewBox: "0 0 " + W + " " + PLOT_HEIGHT,
417
+ preserveAspectRatio: "none",
418
+ style: {
419
+ display: "block"
420
+ }
421
+ }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("linearGradient", {
422
+ id: "ac-area-gradient",
423
+ x1: "0",
424
+ y1: "0",
425
+ x2: "0",
426
+ y2: "1"
427
+ }, /*#__PURE__*/React.createElement("stop", {
428
+ offset: "0%",
429
+ stopColor: "rgba(163, 205, 255, 0.4)"
430
+ }), /*#__PURE__*/React.createElement("stop", {
431
+ offset: "100%",
432
+ stopColor: "rgba(163, 205, 255, 0)"
433
+ }))), /*#__PURE__*/React.createElement("polygon", {
434
+ points: areaPoints,
435
+ fill: "url(#ac-area-gradient)"
436
+ }), /*#__PURE__*/React.createElement("polyline", {
437
+ points: linePoints,
438
+ fill: "none",
439
+ stroke: AREA_LINE,
440
+ strokeWidth: 2.5,
441
+ vectorEffect: "non-scaling-stroke"
442
+ })))), /*#__PURE__*/React.createElement("div", {
443
+ className: "chart-x-axis"
444
+ }, xLabels.map(label => /*#__PURE__*/React.createElement("span", {
445
+ key: label
446
+ }, label))));
447
+ };
448
+ AreaChartWidget.displayName = "AreaChartWidget";
449
+
450
+ /* ------------------------------------------------------------------ */
451
+ /* Daily +/- bars (mirrors DailyCreatedAndCompletedTasksWidget.js) */
452
+ /* ------------------------------------------------------------------ */
453
+
454
+ /** Bar colours from the real widget: new above, completed below. */
455
+ const DELTA_UP = "#A3CDFF";
456
+ const DELTA_DOWN = "#FF9C9C";
457
+ const StyledDeltaBars = styled.div.withConfig({
458
+ displayName: "dashboardWidgets__StyledDeltaBars",
459
+ componentId: "sc-lm5ek4-5"
460
+ })(["display:flex;height:100%;.delta-col{position:relative;flex:1;min-width:0;}.delta-bar{position:absolute;left:50%;width:4px;max-width:80%;transform:translateX(-50%);}.delta-zero{position:absolute;left:0;right:0;height:1px;background-color:", ";}"], TICK_COLOR);
461
+
462
+ /** Thin daily bars above/below a zero line, like "New vs Completed Tasks". */
463
+ export const DailyDeltaChartWidget = _ref9 => {
464
+ let title = _ref9.title,
465
+ linkText = _ref9.linkText,
466
+ data = _ref9.data,
467
+ xLabels = _ref9.xLabels,
468
+ upMax = _ref9.upMax,
469
+ downMax = _ref9.downMax,
470
+ yTicksUp = _ref9.yTicksUp,
471
+ yTicksDown = _ref9.yTicksDown;
472
+ const upFrac = upMax / (upMax + downMax);
473
+ const zeroTop = upFrac * PLOT_HEIGHT;
474
+ const tickTop = (value, below) => below ? zeroTop + value / downMax * (PLOT_HEIGHT - zeroTop) : zeroTop - value / upMax * zeroTop;
475
+ return /*#__PURE__*/React.createElement(StyledChartWidget, null, /*#__PURE__*/React.createElement(ChartHead, {
476
+ title: title,
477
+ linkText: linkText
478
+ }), /*#__PURE__*/React.createElement("div", {
479
+ className: "chart-row"
480
+ }, /*#__PURE__*/React.createElement("div", {
481
+ className: "chart-y-axis"
482
+ }, yTicksUp.map(tick => /*#__PURE__*/React.createElement("span", {
483
+ key: "up-" + tick,
484
+ className: "chart-y-tick",
485
+ style: {
486
+ top: tickTop(tick, false) + "px"
487
+ }
488
+ }, tick)), /*#__PURE__*/React.createElement("span", {
489
+ className: "chart-y-tick",
490
+ style: {
491
+ top: zeroTop + "px"
492
+ }
493
+ }, "0"), yTicksDown.map(tick => /*#__PURE__*/React.createElement("span", {
494
+ key: "down-" + tick,
495
+ className: "chart-y-tick",
496
+ style: {
497
+ top: tickTop(tick, true) + "px"
498
+ }
499
+ }, tick))), /*#__PURE__*/React.createElement("div", {
500
+ className: "chart-plot"
501
+ }, /*#__PURE__*/React.createElement(StyledDeltaBars, null, /*#__PURE__*/React.createElement("span", {
502
+ className: "delta-zero",
503
+ style: {
504
+ top: zeroTop + "px"
505
+ }
506
+ }), data.map((point, index) => /*#__PURE__*/React.createElement("span", {
507
+ className: "delta-col",
508
+ key: index
509
+ }, point.up > 0 ? /*#__PURE__*/React.createElement("span", {
510
+ className: "delta-bar",
511
+ style: {
512
+ backgroundColor: DELTA_UP,
513
+ bottom: PLOT_HEIGHT - zeroTop + "px",
514
+ height: point.up / upMax * zeroTop + "px"
515
+ }
516
+ }) : null, point.down > 0 ? /*#__PURE__*/React.createElement("span", {
517
+ className: "delta-bar",
518
+ style: {
519
+ backgroundColor: DELTA_DOWN,
520
+ top: zeroTop + 1 + "px",
521
+ height: point.down / downMax * (PLOT_HEIGHT - zeroTop) + "px"
522
+ }
523
+ }) : null))))), /*#__PURE__*/React.createElement("div", {
524
+ className: "chart-x-axis"
525
+ }, xLabels.map(label => /*#__PURE__*/React.createElement("span", {
526
+ key: label
527
+ }, label))));
528
+ };
529
+ DailyDeltaChartWidget.displayName = "DailyDeltaChartWidget";
530
+
531
+ /* ------------------------------------------------------------------ */
532
+ /* Leaderboard (mirrors LeaderboardWidget.js) */
533
+ /* ------------------------------------------------------------------ */
534
+
535
+ const StyledLeaderboard = styled.div.withConfig({
536
+ displayName: "dashboardWidgets__StyledLeaderboard",
537
+ componentId: "sc-lm5ek4-6"
538
+ })(["position:relative;height:100%;padding:16px 20px;box-sizing:border-box;overflow:hidden;.lb-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;}.lb-desc{margin-bottom:12px;}.lb-sep{border-bottom:1px solid var(--border-primary);margin-bottom:12px;}.lb-rows{max-height:288px;overflow-y:auto;}.lb-row{display:flex;align-items:center;gap:16px;height:32px;margin-bottom:4px;}.lb-label{width:208px;max-width:40%;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;cursor:pointer;}.lb-bar{flex:1;min-width:0;height:8px;}.lb-bar-inner{min-width:8px;height:100%;border-radius:4px;overflow:hidden;}.lb-value{width:80px;flex-shrink:0;text-align:right;}"]);
539
+
540
+ /** Ranked bars: label, billable/non-billable bar, value — like Time's
541
+ * Leaderboard. Bar length = share of the leader; green = billable part. */
542
+ export const LeaderboardWidget = _ref0 => {
543
+ let title = _ref0.title,
544
+ description = _ref0.description,
545
+ rows = _ref0.rows,
546
+ groupBy = _ref0.groupBy;
547
+ return /*#__PURE__*/React.createElement(StyledLeaderboard, null, /*#__PURE__*/React.createElement("div", {
548
+ className: "lb-head"
549
+ }, /*#__PURE__*/React.createElement(Header2, null, title), groupBy ? /*#__PURE__*/React.createElement(WidgetGroupBy, groupBy) : null), /*#__PURE__*/React.createElement(Body2, {
550
+ color: "tertiary",
551
+ className: "lb-desc"
552
+ }, description), /*#__PURE__*/React.createElement("div", {
553
+ className: "lb-sep"
554
+ }), /*#__PURE__*/React.createElement("div", {
555
+ className: "lb-rows"
556
+ }, rows.map(row => /*#__PURE__*/React.createElement("div", {
557
+ className: "lb-row",
558
+ key: row.label
559
+ }, /*#__PURE__*/React.createElement("span", {
560
+ className: "lb-label"
561
+ }, /*#__PURE__*/React.createElement(Body2, {
562
+ color: "theme-primary"
563
+ }, row.label)), /*#__PURE__*/React.createElement("span", {
564
+ className: "lb-bar"
565
+ }, /*#__PURE__*/React.createElement("span", {
566
+ className: "lb-bar-inner",
567
+ style: {
568
+ width: row.percentOfMax + "%",
569
+ display: "block"
570
+ }
571
+ }, /*#__PURE__*/React.createElement(ProgressBar, {
572
+ progress: row.billableShare,
573
+ stroke: 8,
574
+ progressColor: colors.greenSuccess.color
575
+ }))), /*#__PURE__*/React.createElement("span", {
576
+ className: "lb-value"
577
+ }, /*#__PURE__*/React.createElement(Body2, {
578
+ color: "secondary"
579
+ }, row.value))))));
580
+ };
581
+ LeaderboardWidget.displayName = "LeaderboardWidget";
582
+
583
+ /* ------------------------------------------------------------------ */
584
+ /* Stacked columns (mirrors TotalTrackedHoursChart.js bar mode) */
585
+ /* ------------------------------------------------------------------ */
586
+
587
+ const StyledStackedChart = styled.div.withConfig({
588
+ displayName: "dashboardWidgets__StyledStackedChart",
589
+ componentId: "sc-lm5ek4-7"
590
+ })(["position:relative;height:100%;padding:16px 20px;box-sizing:border-box;overflow:hidden;.sb-head{display:flex;justify-content:space-between;align-items:flex-start;gap:8px;margin-bottom:8px;}.sb-total-wrap{display:flex;align-items:flex-start;gap:8px;margin-left:auto;}.sb-total{font-family:", ";font-size:52px;font-weight:700;line-height:1;color:var(--color-theme-900);}.sb-row{display:flex;gap:10px;}.sb-y-axis{position:relative;width:30px;flex-shrink:0;}.sb-y-tick{position:absolute;right:0;transform:translateY(-50%);font-family:", ";font-size:11px;color:", ";}.sb-plot{position:relative;flex:1;min-width:0;}.sb-grid-line{position:absolute;left:0;right:0;height:1px;background-color:var(--color-theme-300);}.sb-cols{position:relative;display:flex;justify-content:space-around;align-items:flex-end;height:100%;}.sb-slot{display:flex;flex-direction:column-reverse;flex-shrink:0;}.sb-labels{display:flex;justify-content:space-around;margin-top:8px;padding-left:40px;font-family:", ";font-size:11px;color:", ";}"], FONT_STACK, FONT_STACK, TICK_COLOR, FONT_STACK, TICK_COLOR);
591
+
592
+ /** Narrow stacked time columns, like the Time dashboard's tracked-hours
593
+ * chart. Segment order and palette follow the real chart. */
594
+ export const StackedBarChartWidget = _ref1 => {
595
+ let title = _ref1.title,
596
+ total = _ref1.total,
597
+ data = _ref1.data,
598
+ seriesLabels = _ref1.seriesLabels,
599
+ yTicks = _ref1.yTicks,
600
+ _ref1$barWidth = _ref1.barWidth,
601
+ barWidth = _ref1$barWidth === void 0 ? 28 : _ref1$barWidth,
602
+ _ref1$height = _ref1.height,
603
+ height = _ref1$height === void 0 ? 220 : _ref1$height,
604
+ groupBy = _ref1.groupBy;
605
+ const max = Math.max(...yTicks) || 1;
606
+ return /*#__PURE__*/React.createElement(StyledStackedChart, null, /*#__PURE__*/React.createElement("div", {
607
+ className: "sb-head"
608
+ }, title ? /*#__PURE__*/React.createElement(Body1, {
609
+ weight: "bold"
610
+ }, title) : null, /*#__PURE__*/React.createElement("span", {
611
+ className: "sb-total-wrap"
612
+ }, total ? /*#__PURE__*/React.createElement("span", {
613
+ className: "sb-total"
614
+ }, total) : null, groupBy ? /*#__PURE__*/React.createElement(WidgetGroupBy, groupBy) : null)), /*#__PURE__*/React.createElement("div", {
615
+ className: "sb-row"
616
+ }, /*#__PURE__*/React.createElement("div", {
617
+ className: "sb-y-axis",
618
+ style: {
619
+ height: height + "px"
620
+ }
621
+ }, yTicks.map(tick => /*#__PURE__*/React.createElement("span", {
622
+ key: tick,
623
+ className: "sb-y-tick",
624
+ style: {
625
+ top: (max - tick) / max * height + "px"
626
+ }
627
+ }, tick))), /*#__PURE__*/React.createElement("div", {
628
+ className: "sb-plot",
629
+ style: {
630
+ height: height + "px"
631
+ }
632
+ }, yTicks.map(tick => /*#__PURE__*/React.createElement("span", {
633
+ key: tick,
634
+ className: "sb-grid-line",
635
+ style: {
636
+ top: (max - tick) / max * height + "px"
637
+ }
638
+ })), /*#__PURE__*/React.createElement("div", {
639
+ className: "sb-cols"
640
+ }, data.map(column => /*#__PURE__*/React.createElement("div", {
641
+ className: "sb-slot",
642
+ key: column.label,
643
+ style: {
644
+ width: barWidth + "px"
645
+ }
646
+ }, column.segments.map((value, index) => {
647
+ var _seriesLabels$index;
648
+ return value > 0 ? /*#__PURE__*/React.createElement(Tooltip, {
649
+ key: (_seriesLabels$index = seriesLabels[index]) != null ? _seriesLabels$index : index,
650
+ title: seriesLabels[index] + ": " + value + "h"
651
+ }, /*#__PURE__*/React.createElement("span", {
652
+ style: {
653
+ display: "block",
654
+ height: value / max * height + "px",
655
+ backgroundColor: CHART_SERIES_COLORS[index % CHART_SERIES_COLORS.length]
656
+ }
657
+ })) : null;
658
+ })))))), /*#__PURE__*/React.createElement("div", {
659
+ className: "sb-labels"
660
+ }, data.map(column => /*#__PURE__*/React.createElement("span", {
661
+ key: column.label
662
+ }, column.label))));
663
+ };
664
+ StackedBarChartWidget.displayName = "StackedBarChartWidget";
665
+ //# sourceMappingURL=dashboardWidgets.js.map