@burdenoff/microfe-timecampus 2026.830.2 → 2026.904.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/timecampus/components/index.js +4 -4
- package/dist/timecampus/pages/HomePage.d.ts.map +1 -1
- package/dist/timecampus/pages/HomePage.js +149 -133
- package/dist/timecampus/pages/HomePage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +7 -7
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +7 -7
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +13 -13
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +7 -7
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +7 -7
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScorePage.js +13 -13
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +135 -135
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/invoicing/InvoicingPage.js +7 -7
- package/dist/timecampus/pages/invoicing/InvoicingPage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/DeadTimeRadarPage.js +8 -8
- package/dist/timecampus/pages/lifetime/FiniteLifePage.js +4 -4
- package/dist/timecampus/pages/lifetime/FiniteLifePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/LifeBalancePage.js +104 -104
- package/dist/timecampus/pages/lifetime/LifeBalancePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/LifeTimelinePage.js +7 -7
- package/dist/timecampus/pages/lifetime/LifeTimelinePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/PersonalCorporatePage.js +33 -33
- package/dist/timecampus/pages/lifetime/PersonalCorporatePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/RecommendationsPage.js +80 -80
- package/dist/timecampus/pages/lifetime/RecommendationsPage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/TimeWellSpentPage.js +16 -16
- package/dist/timecampus/pages/lifetime/ValuesGoalsPage.js +11 -11
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +11 -11
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +14 -14
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingsPage.js +12 -12
- package/dist/timecampus/pages/projects/ProjectsPage.js +5 -5
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +8 -8
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +8 -8
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +8 -8
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js +13 -13
- package/dist/timecampus/pages/time/TimeEntriesPage.js +5 -5
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +138 -138
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +14 -14
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +26 -26
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/timeline/TimelinePage.js +8 -8
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +79 -79
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { StatCard as e } from "./StatCard.js";
|
|
2
2
|
import { LoadingSkeleton as t } from "./LoadingSkeleton.js";
|
|
3
|
+
import { EmptyState as n } from "./EmptyState.js";
|
|
3
4
|
import "./ErrorBoundary.js";
|
|
4
|
-
import { PageLayout as
|
|
5
|
-
import { StatusBadge as
|
|
6
|
-
import { EmptyState as i } from "./EmptyState.js";
|
|
5
|
+
import { PageLayout as r } from "./PageLayout.js";
|
|
6
|
+
import { StatusBadge as i } from "./StatusBadge.js";
|
|
7
7
|
import { Modal as a } from "./Modal.js";
|
|
8
8
|
import "./DataTable.js";
|
|
9
9
|
import { ChartCard as o } from "./ChartCard.js";
|
|
@@ -20,4 +20,4 @@ import { Heatmap as g } from "./charts/Heatmap.js";
|
|
|
20
20
|
import { BalanceWheel as _ } from "./charts/BalanceWheel.js";
|
|
21
21
|
import { WeeksGrid as v } from "./charts/WeeksGrid.js";
|
|
22
22
|
import "./charts/index.js";
|
|
23
|
-
export { _ as BalanceWheel, f as BarsChart, o as ChartCard, p as DonutChart,
|
|
23
|
+
export { _ as BalanceWheel, f as BarsChart, o as ChartCard, p as DonutChart, n as EmptyState, g as Heatmap, t as LoadingSkeleton, a as Modal, r as PageLayout, h as ProgressMeter, m as RadialGauge, e as StatCard, i as StatusBadge, s as ToastContainer, d as TrendChart, v as WeeksGrid, l as chartTokens, u as formatNumber, c as useToast };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage.d.ts","sourceRoot":"","sources":["../../../src/timecampus/pages/HomePage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"HomePage.d.ts","sourceRoot":"","sources":["../../../src/timecampus/pages/HomePage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AA8BhC,eAAO,MAAM,QAAQ,EAAE,EAyatB,CAAC"}
|
|
@@ -2,264 +2,280 @@ import { useTimeCampusNavigate as e } from "../providers/TimeCampusProvider.js";
|
|
|
2
2
|
import { cn as t, formatHours as n } from "../utils/helpers.js";
|
|
3
3
|
import { StatCard as r } from "../components/StatCard.js";
|
|
4
4
|
import { LoadingSkeleton as i } from "../components/LoadingSkeleton.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { EmptyState as a } from "../components/EmptyState.js";
|
|
6
|
+
import { useGetTimeEntryStatsQuery as o, useListTimeEntriesQuery as s } from "../../generated/wspace-operations.js";
|
|
7
|
+
import { useTr as c } from "../shared/hooks/useTr.js";
|
|
7
8
|
import "../hooks/index.js";
|
|
8
|
-
import { ArrowRight as
|
|
9
|
-
import { jsx as
|
|
10
|
-
import { AuroraBackground as
|
|
9
|
+
import { ArrowRight as l, BarChart3 as u, CheckCircle as d, Clock as f, FolderOpen as p, Play as m, TrendingUp as h, Users as g } from "lucide-react";
|
|
10
|
+
import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
11
|
+
import { AuroraBackground as b, CTAOverflowMenu as x, EmphasisPanel as S, GlassCard as C, GradientText as w } from "@burdenoff/fe-libs/ui";
|
|
11
12
|
//#region src/timecampus/pages/HomePage.tsx
|
|
12
|
-
var
|
|
13
|
-
let
|
|
13
|
+
var T = () => {
|
|
14
|
+
let T = c(), E = e(), { data: D, loading: O } = o(), { data: k, loading: A } = s({ variables: { pagination: { limit: 4 } } }), j = D?.timeEntryStats, M = k?.timeEntries?.items ?? [], N = !O && !A && (j?.totalEntries ?? 0) === 0, P = /* @__PURE__ */ v(x, {
|
|
14
15
|
primary: {
|
|
15
|
-
label:
|
|
16
|
-
onSelect: () =>
|
|
17
|
-
icon: /* @__PURE__ */
|
|
16
|
+
label: T("timecampus.home.actions.startTimer", "Start Timer"),
|
|
17
|
+
onSelect: () => E("/time/timer"),
|
|
18
|
+
icon: /* @__PURE__ */ v(m, { className: "h-4 w-4" })
|
|
18
19
|
},
|
|
19
20
|
actions: [{
|
|
20
|
-
label:
|
|
21
|
-
onSelect: () =>
|
|
22
|
-
icon: /* @__PURE__ */
|
|
21
|
+
label: T("timecampus.home.quickActions.viewProjects.label", "View Projects"),
|
|
22
|
+
onSelect: () => E("/projects"),
|
|
23
|
+
icon: /* @__PURE__ */ v(p, { className: "h-4 w-4" })
|
|
23
24
|
}, {
|
|
24
|
-
label:
|
|
25
|
-
onSelect: () =>
|
|
26
|
-
icon: /* @__PURE__ */
|
|
25
|
+
label: T("timecampus.home.quickActions.reports.label", "Reports"),
|
|
26
|
+
onSelect: () => E("/reports"),
|
|
27
|
+
icon: /* @__PURE__ */ v(u, { className: "h-4 w-4" })
|
|
27
28
|
}]
|
|
28
|
-
}),
|
|
29
|
+
}), F = () => /* @__PURE__ */ y("div", {
|
|
29
30
|
className: "relative overflow-hidden rounded-2xl border border-border-seam bg-gloss-card p-5 sm:p-6",
|
|
30
|
-
children: [/* @__PURE__ */
|
|
31
|
+
children: [/* @__PURE__ */ v(b, { intensity: "subtle" }), /* @__PURE__ */ y("div", {
|
|
31
32
|
className: "relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
|
|
32
|
-
children: [/* @__PURE__ */
|
|
33
|
+
children: [/* @__PURE__ */ y("div", {
|
|
33
34
|
className: "min-w-0",
|
|
34
|
-
children: [/* @__PURE__ */
|
|
35
|
+
children: [/* @__PURE__ */ v("h1", {
|
|
35
36
|
className: "text-2xl font-bold text-text-primary",
|
|
36
|
-
children: /* @__PURE__ */
|
|
37
|
-
}), /* @__PURE__ */
|
|
37
|
+
children: /* @__PURE__ */ v(w, { children: T("timecampus.home.title", "Dashboard") })
|
|
38
|
+
}), /* @__PURE__ */ v("p", {
|
|
38
39
|
className: "mt-1 text-sm text-text-secondary",
|
|
39
|
-
children:
|
|
40
|
+
children: T("timecampus.home.description", "Overview of your time tracking and productivity")
|
|
40
41
|
})]
|
|
41
|
-
}),
|
|
42
|
+
}), P]
|
|
42
43
|
})]
|
|
43
44
|
});
|
|
44
|
-
return
|
|
45
|
+
return O && A ? /* @__PURE__ */ y("div", {
|
|
45
46
|
className: "min-h-full space-y-6 p-4 sm:p-6",
|
|
46
|
-
children: [
|
|
47
|
+
children: [F(), /* @__PURE__ */ v(i, {
|
|
47
48
|
variant: "card",
|
|
48
49
|
count: 4
|
|
49
50
|
})]
|
|
50
|
-
}) : /* @__PURE__ */
|
|
51
|
+
}) : /* @__PURE__ */ y("div", {
|
|
51
52
|
className: "min-h-full space-y-6 p-4 sm:p-6",
|
|
52
53
|
children: [
|
|
53
|
-
|
|
54
|
-
/* @__PURE__ */
|
|
54
|
+
F(),
|
|
55
|
+
N ? /* @__PURE__ */ y("div", {
|
|
56
|
+
className: "flex flex-col items-center gap-3",
|
|
57
|
+
children: [/* @__PURE__ */ v(a, {
|
|
58
|
+
illustration: "empty-data",
|
|
59
|
+
title: T("timecampus.home.gettingStarted.title", "Let's get you started"),
|
|
60
|
+
description: T("timecampus.home.gettingStarted.description", "TimeCampus tracks your time when you start a timer — stop it when you're done, and everything else (your Timeline, Focus Score, and Reports) fills in automatically from what you track. No extra setup needed."),
|
|
61
|
+
action: /* @__PURE__ */ y("button", {
|
|
62
|
+
type: "button",
|
|
63
|
+
onClick: () => E("/time/timer"),
|
|
64
|
+
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
65
|
+
children: [/* @__PURE__ */ v(m, { className: "h-4 w-4" }), T("timecampus.home.gettingStarted.action", "Start your first timer")]
|
|
66
|
+
})
|
|
67
|
+
}), /* @__PURE__ */ v("p", {
|
|
68
|
+
className: "max-w-md text-center text-xs text-text-secondary",
|
|
69
|
+
children: T("timecampus.home.gettingStarted.footnote", "That's the only thing to set up. Pomodoro, Life tracking, reports and everything else in the sidebar are there whenever you're curious — nothing else needs configuring first.")
|
|
70
|
+
})]
|
|
71
|
+
}) : /* @__PURE__ */ y("div", {
|
|
55
72
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
|
|
56
73
|
children: [
|
|
57
|
-
/* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ v(r, {
|
|
58
75
|
featured: !0,
|
|
59
|
-
title:
|
|
60
|
-
value: n(
|
|
61
|
-
icon: /* @__PURE__ */
|
|
76
|
+
title: T("timecampus.home.stats.today", "Today"),
|
|
77
|
+
value: n(j?.totalHours ?? 0),
|
|
78
|
+
icon: /* @__PURE__ */ v(f, { className: "h-5 w-5" }),
|
|
62
79
|
trend: {
|
|
63
80
|
value: 12.5,
|
|
64
|
-
label:
|
|
81
|
+
label: T("timecampus.home.stats.vsYesterday", "vs yesterday")
|
|
65
82
|
}
|
|
66
83
|
}),
|
|
67
|
-
/* @__PURE__ */
|
|
68
|
-
title:
|
|
69
|
-
value: n(
|
|
70
|
-
icon: /* @__PURE__ */
|
|
71
|
-
description: `${
|
|
84
|
+
/* @__PURE__ */ v(r, {
|
|
85
|
+
title: T("timecampus.home.stats.billable", "Billable"),
|
|
86
|
+
value: n(j?.billableHours ?? 0),
|
|
87
|
+
icon: /* @__PURE__ */ v(h, { className: "h-5 w-5" }),
|
|
88
|
+
description: `${j?.totalEntries ?? 0} ${T("timecampus.home.stats.entries", "entries")}`
|
|
72
89
|
}),
|
|
73
|
-
/* @__PURE__ */
|
|
74
|
-
title:
|
|
75
|
-
value:
|
|
76
|
-
icon: /* @__PURE__ */
|
|
77
|
-
description:
|
|
90
|
+
/* @__PURE__ */ v(r, {
|
|
91
|
+
title: T("timecampus.home.stats.activeTimers", "Active Timers"),
|
|
92
|
+
value: j?.activeTimers ?? 0,
|
|
93
|
+
icon: /* @__PURE__ */ v(p, { className: "h-5 w-5" }),
|
|
94
|
+
description: T("timecampus.home.stats.currentlyRunning", "Currently running")
|
|
78
95
|
}),
|
|
79
|
-
/* @__PURE__ */
|
|
80
|
-
title:
|
|
81
|
-
value:
|
|
82
|
-
icon: /* @__PURE__ */
|
|
83
|
-
description:
|
|
96
|
+
/* @__PURE__ */ v(r, {
|
|
97
|
+
title: T("timecampus.home.stats.totalEntries", "Entries"),
|
|
98
|
+
value: j?.totalEntries ?? 0,
|
|
99
|
+
icon: /* @__PURE__ */ v(u, { className: "h-5 w-5" }),
|
|
100
|
+
description: T("timecampus.home.stats.totalEntriesDescription", "Total time entries")
|
|
84
101
|
})
|
|
85
102
|
]
|
|
86
103
|
}),
|
|
87
|
-
/* @__PURE__ */ _("div", {
|
|
104
|
+
!N && /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ y("div", {
|
|
88
105
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
89
|
-
children: [/* @__PURE__ */
|
|
106
|
+
children: [/* @__PURE__ */ y(C, {
|
|
90
107
|
treatment: "plain",
|
|
91
108
|
className: "border-border-seam p-6 lg:col-span-2",
|
|
92
|
-
children: [/* @__PURE__ */
|
|
109
|
+
children: [/* @__PURE__ */ y("div", {
|
|
93
110
|
className: "mb-4 flex items-center justify-between",
|
|
94
|
-
children: [/* @__PURE__ */
|
|
111
|
+
children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("h3", {
|
|
95
112
|
className: "text-sm font-semibold text-text-primary",
|
|
96
|
-
children:
|
|
97
|
-
}), /* @__PURE__ */
|
|
113
|
+
children: T("timecampus.home.recentEntries.title", "Recent Time Entries")
|
|
114
|
+
}), /* @__PURE__ */ v("p", {
|
|
98
115
|
className: "text-xs text-text-secondary",
|
|
99
|
-
children:
|
|
100
|
-
})] }), /* @__PURE__ */
|
|
101
|
-
onClick: () =>
|
|
116
|
+
children: T("timecampus.home.recentEntries.description", "Your latest tracked activities")
|
|
117
|
+
})] }), /* @__PURE__ */ y("button", {
|
|
118
|
+
onClick: () => E("/time/entries"),
|
|
102
119
|
className: "inline-flex min-h-[2.75rem] items-center gap-1 rounded-md px-2 text-xs font-medium text-primary transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border",
|
|
103
120
|
children: [
|
|
104
|
-
|
|
121
|
+
T("timecampus.home.recentEntries.viewAll", "View all"),
|
|
105
122
|
" ",
|
|
106
|
-
/* @__PURE__ */
|
|
123
|
+
/* @__PURE__ */ v(l, { className: "h-3 w-3" })
|
|
107
124
|
]
|
|
108
125
|
})]
|
|
109
|
-
}),
|
|
126
|
+
}), A ? /* @__PURE__ */ v(i, {
|
|
110
127
|
variant: "list",
|
|
111
128
|
count: 4
|
|
112
|
-
}) : /* @__PURE__ */
|
|
129
|
+
}) : /* @__PURE__ */ y("div", {
|
|
113
130
|
className: "flex flex-col gap-3",
|
|
114
|
-
children: [
|
|
131
|
+
children: [M.map((e) => /* @__PURE__ */ y("div", {
|
|
115
132
|
className: "flex items-center justify-between rounded-lg border border-border-seam p-3 transition-colors hover:bg-bg-sunken/50",
|
|
116
|
-
children: [/* @__PURE__ */
|
|
133
|
+
children: [/* @__PURE__ */ y("div", {
|
|
117
134
|
className: "min-w-0 flex-1",
|
|
118
|
-
children: [/* @__PURE__ */
|
|
135
|
+
children: [/* @__PURE__ */ v("p", {
|
|
119
136
|
className: "text-sm font-medium text-text-primary",
|
|
120
|
-
children: e.project?.name ??
|
|
121
|
-
}), /* @__PURE__ */
|
|
137
|
+
children: e.project?.name ?? T("timecampus.home.recentEntries.noProject", "No Project")
|
|
138
|
+
}), /* @__PURE__ */ v("p", {
|
|
122
139
|
className: "text-xs text-text-secondary",
|
|
123
|
-
children: e.description ??
|
|
140
|
+
children: e.description ?? T("timecampus.home.recentEntries.noDescription", "No description")
|
|
124
141
|
})]
|
|
125
|
-
}), /* @__PURE__ */
|
|
142
|
+
}), /* @__PURE__ */ y("div", {
|
|
126
143
|
className: "ml-4 text-right",
|
|
127
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ v("p", {
|
|
128
145
|
className: "font-mono text-sm font-medium tabular-nums text-text-primary",
|
|
129
146
|
children: n((e.duration ?? 0) / 3600)
|
|
130
|
-
}), /* @__PURE__ */
|
|
147
|
+
}), /* @__PURE__ */ y("span", {
|
|
131
148
|
className: t("inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium", e.isRunning ? "bg-status-info-bg text-status-info-text" : "bg-status-success-bg text-status-success-text"),
|
|
132
|
-
children: [e.isRunning && /* @__PURE__ */
|
|
149
|
+
children: [e.isRunning && /* @__PURE__ */ v("span", { className: "h-1.5 w-1.5 rounded-full bg-status-info-text motion-safe:animate-vc-glow-pulse" }), e.isRunning ? T("timecampus.home.recentEntries.status.running", "running") : T("timecampus.home.recentEntries.status.completed", "completed")]
|
|
133
150
|
})]
|
|
134
151
|
})]
|
|
135
|
-
}, e.id)),
|
|
152
|
+
}, e.id)), M.length === 0 && /* @__PURE__ */ v("p", {
|
|
136
153
|
className: "py-4 text-center text-sm text-text-secondary",
|
|
137
|
-
children:
|
|
154
|
+
children: T("timecampus.home.recentEntries.empty", "No time entries yet")
|
|
138
155
|
})]
|
|
139
156
|
})]
|
|
140
|
-
}), /* @__PURE__ */
|
|
157
|
+
}), /* @__PURE__ */ y(S, {
|
|
141
158
|
className: "p-6",
|
|
142
|
-
children: [/* @__PURE__ */
|
|
159
|
+
children: [/* @__PURE__ */ y("div", {
|
|
143
160
|
className: "mb-4",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
161
|
+
children: [/* @__PURE__ */ v("h3", {
|
|
145
162
|
className: "text-sm font-semibold text-text-primary",
|
|
146
|
-
children:
|
|
147
|
-
}), /* @__PURE__ */
|
|
163
|
+
children: T("timecampus.home.summary.title", "Quick Summary")
|
|
164
|
+
}), /* @__PURE__ */ v("p", {
|
|
148
165
|
className: "text-xs text-text-secondary",
|
|
149
|
-
children:
|
|
166
|
+
children: T("timecampus.home.summary.description", "Time tracking overview")
|
|
150
167
|
})]
|
|
151
|
-
}), /* @__PURE__ */
|
|
168
|
+
}), /* @__PURE__ */ y("div", {
|
|
152
169
|
className: "flex flex-col gap-4",
|
|
153
170
|
children: [
|
|
154
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ y("div", {
|
|
155
172
|
className: "flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3",
|
|
156
|
-
children: [/* @__PURE__ */
|
|
173
|
+
children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
157
174
|
className: "text-xs font-medium text-text-secondary",
|
|
158
|
-
children:
|
|
159
|
-
}), /* @__PURE__ */
|
|
175
|
+
children: T("timecampus.home.summary.totalHours", "Total Hours")
|
|
176
|
+
}), /* @__PURE__ */ v("p", {
|
|
160
177
|
className: "mt-1 text-xl font-bold tabular-nums text-text-primary",
|
|
161
|
-
children: n(
|
|
162
|
-
})] }), /* @__PURE__ */
|
|
178
|
+
children: n(j?.totalHours ?? 0)
|
|
179
|
+
})] }), /* @__PURE__ */ v(f, { className: "h-5 w-5 text-text-secondary" })]
|
|
163
180
|
}),
|
|
164
|
-
/* @__PURE__ */
|
|
181
|
+
/* @__PURE__ */ y("div", {
|
|
165
182
|
className: "flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3",
|
|
166
|
-
children: [/* @__PURE__ */
|
|
183
|
+
children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
167
184
|
className: "text-xs font-medium text-text-secondary",
|
|
168
|
-
children:
|
|
169
|
-
}), /* @__PURE__ */
|
|
185
|
+
children: T("timecampus.home.summary.billableHours", "Billable Hours")
|
|
186
|
+
}), /* @__PURE__ */ v("p", {
|
|
170
187
|
className: "mt-1 text-xl font-bold tabular-nums text-text-primary",
|
|
171
|
-
children: n(
|
|
172
|
-
})] }), /* @__PURE__ */
|
|
188
|
+
children: n(j?.billableHours ?? 0)
|
|
189
|
+
})] }), /* @__PURE__ */ v(h, { className: "h-5 w-5 text-text-secondary" })]
|
|
173
190
|
}),
|
|
174
|
-
/* @__PURE__ */
|
|
191
|
+
/* @__PURE__ */ y("div", {
|
|
175
192
|
className: "flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3",
|
|
176
|
-
children: [/* @__PURE__ */
|
|
193
|
+
children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
177
194
|
className: "text-xs font-medium text-text-secondary",
|
|
178
|
-
children:
|
|
179
|
-
}), /* @__PURE__ */
|
|
195
|
+
children: T("timecampus.home.summary.activeTimers", "Active Timers")
|
|
196
|
+
}), /* @__PURE__ */ v("p", {
|
|
180
197
|
className: "mt-1 text-xl font-bold tabular-nums text-text-primary",
|
|
181
|
-
children:
|
|
182
|
-
})] }), /* @__PURE__ */ g
|
|
198
|
+
children: j?.activeTimers ?? 0
|
|
199
|
+
})] }), /* @__PURE__ */ v(g, { className: "h-5 w-5 text-text-secondary" })]
|
|
183
200
|
})
|
|
184
201
|
]
|
|
185
202
|
})]
|
|
186
203
|
})]
|
|
187
|
-
}),
|
|
188
|
-
/* @__PURE__ */ _(x, {
|
|
204
|
+
}), /* @__PURE__ */ y(C, {
|
|
189
205
|
treatment: "plain",
|
|
190
206
|
className: "border-border-seam p-6",
|
|
191
|
-
children: [/* @__PURE__ */
|
|
207
|
+
children: [/* @__PURE__ */ y("div", {
|
|
192
208
|
className: "mb-4",
|
|
193
|
-
children: [/* @__PURE__ */
|
|
209
|
+
children: [/* @__PURE__ */ v("h3", {
|
|
194
210
|
className: "text-sm font-semibold text-text-primary",
|
|
195
|
-
children:
|
|
196
|
-
}), /* @__PURE__ */
|
|
211
|
+
children: T("timecampus.home.quickActions.title", "Quick Actions")
|
|
212
|
+
}), /* @__PURE__ */ v("p", {
|
|
197
213
|
className: "text-xs text-text-secondary",
|
|
198
|
-
children:
|
|
214
|
+
children: T("timecampus.home.quickActions.description", "Frequently used features")
|
|
199
215
|
})]
|
|
200
|
-
}), /* @__PURE__ */
|
|
216
|
+
}), /* @__PURE__ */ v("div", {
|
|
201
217
|
className: "grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6",
|
|
202
218
|
children: [
|
|
203
219
|
{
|
|
204
|
-
label:
|
|
205
|
-
icon:
|
|
220
|
+
label: T("timecampus.home.quickActions.startTimer.label", "Start Timer"),
|
|
221
|
+
icon: m,
|
|
206
222
|
route: "/time/timer",
|
|
207
|
-
description:
|
|
223
|
+
description: T("timecampus.home.quickActions.startTimer.description", "Track your time")
|
|
208
224
|
},
|
|
209
225
|
{
|
|
210
|
-
label:
|
|
211
|
-
icon:
|
|
226
|
+
label: T("timecampus.home.quickActions.viewProjects.label", "View Projects"),
|
|
227
|
+
icon: p,
|
|
212
228
|
route: "/projects",
|
|
213
|
-
description:
|
|
229
|
+
description: T("timecampus.home.quickActions.viewProjects.description", "Manage projects")
|
|
214
230
|
},
|
|
215
231
|
{
|
|
216
|
-
label:
|
|
217
|
-
icon:
|
|
232
|
+
label: T("timecampus.home.quickActions.timeEntries.label", "Time Entries"),
|
|
233
|
+
icon: f,
|
|
218
234
|
route: "/time/entries",
|
|
219
|
-
description:
|
|
235
|
+
description: T("timecampus.home.quickActions.timeEntries.description", "View all entries")
|
|
220
236
|
},
|
|
221
237
|
{
|
|
222
|
-
label:
|
|
223
|
-
icon:
|
|
238
|
+
label: T("timecampus.home.quickActions.teamActivity.label", "Team Activity"),
|
|
239
|
+
icon: g,
|
|
224
240
|
route: "/team-activity",
|
|
225
|
-
description:
|
|
241
|
+
description: T("timecampus.home.quickActions.teamActivity.description", "See team status")
|
|
226
242
|
},
|
|
227
243
|
{
|
|
228
|
-
label:
|
|
229
|
-
icon:
|
|
244
|
+
label: T("timecampus.home.quickActions.reports.label", "Reports"),
|
|
245
|
+
icon: u,
|
|
230
246
|
route: "/reports",
|
|
231
|
-
description:
|
|
247
|
+
description: T("timecampus.home.quickActions.reports.description", "Generate reports")
|
|
232
248
|
},
|
|
233
249
|
{
|
|
234
|
-
label:
|
|
235
|
-
icon:
|
|
250
|
+
label: T("timecampus.home.quickActions.approvals.label", "Approvals"),
|
|
251
|
+
icon: d,
|
|
236
252
|
route: "/time-approval",
|
|
237
|
-
description:
|
|
253
|
+
description: T("timecampus.home.quickActions.approvals.description", "Review timesheets")
|
|
238
254
|
}
|
|
239
|
-
].map(({ label: e, icon: t, description: n, route: r }) => /* @__PURE__ */
|
|
240
|
-
onClick: () =>
|
|
255
|
+
].map(({ label: e, icon: t, description: n, route: r }) => /* @__PURE__ */ y("button", {
|
|
256
|
+
onClick: () => E(r),
|
|
241
257
|
className: "flex min-h-[2.75rem] flex-col items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-center transition-colors hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border",
|
|
242
258
|
children: [
|
|
243
|
-
/* @__PURE__ */
|
|
259
|
+
/* @__PURE__ */ v("div", {
|
|
244
260
|
className: "rounded-full bg-action-primary-bg/10 p-3",
|
|
245
|
-
children: /* @__PURE__ */
|
|
261
|
+
children: /* @__PURE__ */ v(t, { className: "h-5 w-5 text-primary" })
|
|
246
262
|
}),
|
|
247
|
-
/* @__PURE__ */
|
|
263
|
+
/* @__PURE__ */ v("span", {
|
|
248
264
|
className: "text-sm font-medium text-text-primary",
|
|
249
265
|
children: e
|
|
250
266
|
}),
|
|
251
|
-
/* @__PURE__ */
|
|
267
|
+
/* @__PURE__ */ v("span", {
|
|
252
268
|
className: "text-xs text-text-secondary",
|
|
253
269
|
children: n
|
|
254
270
|
})
|
|
255
271
|
]
|
|
256
272
|
}, e))
|
|
257
273
|
})]
|
|
258
|
-
})
|
|
274
|
+
})] })
|
|
259
275
|
]
|
|
260
276
|
});
|
|
261
277
|
};
|
|
262
278
|
//#endregion
|
|
263
|
-
export {
|
|
279
|
+
export { T as HomePage };
|
|
264
280
|
|
|
265
281
|
//# sourceMappingURL=HomePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/timecampus/pages/HomePage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport {\n Clock,\n FolderOpen,\n Users,\n TrendingUp,\n CheckCircle,\n BarChart3,\n Play,\n ArrowRight,\n} from \"lucide-react\";\nimport {\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n CTAOverflowMenu,\n} from \"@burdenoff/fe-libs/ui\";\nimport { StatCard } from \"../components/StatCard\";\nimport { LoadingSkeleton } from \"../components/LoadingSkeleton\";\nimport { cn, formatHours } from \"../utils/helpers\";\nimport { useTimeCampusNavigate } from \"../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useListTimeEntriesQuery,\n type TimeEntryFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport { useTr } from \"../hooks\";\n\nexport const HomePage: FC = () => {\n const t = useTr();\n const navigate = useTimeCampusNavigate();\n\n const { data: statsData, loading: statsLoading } =\n useGetTimeEntryStatsQuery();\n const { data: entriesData, loading: entriesLoading } =\n useListTimeEntriesQuery({\n variables: { pagination: { limit: 4 } },\n });\n\n const stats = statsData?.timeEntryStats;\n const recentEntries = entriesData?.timeEntries?.items ?? [];\n\n const headerActions = (\n <CTAOverflowMenu\n primary={{\n label: t(\"timecampus.home.actions.startTimer\", \"Start Timer\"),\n onSelect: () => navigate(\"/time/timer\"),\n icon: <Play className=\"h-4 w-4\" />,\n }}\n actions={[\n {\n label: t(\n \"timecampus.home.quickActions.viewProjects.label\",\n \"View Projects\",\n ),\n onSelect: () => navigate(\"/projects\"),\n icon: <FolderOpen className=\"h-4 w-4\" />,\n },\n {\n label: t(\"timecampus.home.quickActions.reports.label\", \"Reports\"),\n onSelect: () => navigate(\"/reports\"),\n icon: <BarChart3 className=\"h-4 w-4\" />,\n },\n ]}\n />\n );\n\n const renderHeader = () => (\n <div className=\"relative overflow-hidden rounded-2xl border border-border-seam bg-gloss-card p-5 sm:p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0\">\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>\n {t(\"timecampus.home.title\", \"Dashboard\")}\n </GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {t(\n \"timecampus.home.description\",\n \"Overview of your time tracking and productivity\",\n )}\n </p>\n </div>\n {headerActions}\n </div>\n </div>\n );\n\n if (statsLoading && entriesLoading) {\n return (\n <div className=\"min-h-full space-y-6 p-4 sm:p-6\">\n {renderHeader()}\n <LoadingSkeleton variant=\"card\" count={4} />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full space-y-6 p-4 sm:p-6\">\n {renderHeader()}\n\n {/* Hero metric + supporting metrics */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n <StatCard\n featured\n title={t(\"timecampus.home.stats.today\", \"Today\")}\n value={formatHours(stats?.totalHours ?? 0)}\n icon={<Clock className=\"h-5 w-5\" />}\n trend={{\n value: 12.5,\n label: t(\"timecampus.home.stats.vsYesterday\", \"vs yesterday\"),\n }}\n />\n <StatCard\n title={t(\"timecampus.home.stats.billable\", \"Billable\")}\n value={formatHours(stats?.billableHours ?? 0)}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n description={`${stats?.totalEntries ?? 0} ${t(\"timecampus.home.stats.entries\", \"entries\")}`}\n />\n <StatCard\n title={t(\"timecampus.home.stats.activeTimers\", \"Active Timers\")}\n value={stats?.activeTimers ?? 0}\n icon={<FolderOpen className=\"h-5 w-5\" />}\n description={t(\n \"timecampus.home.stats.currentlyRunning\",\n \"Currently running\",\n )}\n />\n <StatCard\n title={t(\"timecampus.home.stats.totalEntries\", \"Entries\")}\n value={stats?.totalEntries ?? 0}\n icon={<BarChart3 className=\"h-5 w-5\" />}\n description={t(\n \"timecampus.home.stats.totalEntriesDescription\",\n \"Total time entries\",\n )}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Recent Time Entries */}\n <GlassCard\n treatment=\"plain\"\n className=\"border-border-seam p-6 lg:col-span-2\"\n >\n <div className=\"mb-4 flex items-center justify-between\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\n \"timecampus.home.recentEntries.title\",\n \"Recent Time Entries\",\n )}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.recentEntries.description\",\n \"Your latest tracked activities\",\n )}\n </p>\n </div>\n <button\n onClick={() => navigate(\"/time/entries\")}\n className=\"inline-flex min-h-[2.75rem] items-center gap-1 rounded-md px-2 text-xs font-medium text-primary transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border\"\n >\n {t(\"timecampus.home.recentEntries.viewAll\", \"View all\")}{\" \"}\n <ArrowRight className=\"h-3 w-3\" />\n </button>\n </div>\n {entriesLoading ? (\n <LoadingSkeleton variant=\"list\" count={4} />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {recentEntries.map((entry: TimeEntryFieldsFragment) => (\n <div\n key={entry.id}\n className=\"flex items-center justify-between rounded-lg border border-border-seam p-3 transition-colors hover:bg-bg-sunken/50\"\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {entry.project?.name ??\n t(\n \"timecampus.home.recentEntries.noProject\",\n \"No Project\",\n )}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {entry.description ??\n t(\n \"timecampus.home.recentEntries.noDescription\",\n \"No description\",\n )}\n </p>\n </div>\n <div className=\"ml-4 text-right\">\n <p className=\"font-mono text-sm font-medium tabular-nums text-text-primary\">\n {formatHours((entry.duration ?? 0) / 3600)}\n </p>\n <span\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium\",\n entry.isRunning\n ? \"bg-status-info-bg text-status-info-text\"\n : \"bg-status-success-bg text-status-success-text\",\n )}\n >\n {entry.isRunning && (\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-info-text motion-safe:animate-vc-glow-pulse\" />\n )}\n {entry.isRunning\n ? t(\n \"timecampus.home.recentEntries.status.running\",\n \"running\",\n )\n : t(\n \"timecampus.home.recentEntries.status.completed\",\n \"completed\",\n )}\n </span>\n </div>\n </div>\n ))}\n {recentEntries.length === 0 && (\n <p className=\"py-4 text-center text-sm text-text-secondary\">\n {t(\n \"timecampus.home.recentEntries.empty\",\n \"No time entries yet\",\n )}\n </p>\n )}\n </div>\n )}\n </GlassCard>\n\n {/* Quick Summary — the one emphasis zone */}\n <EmphasisPanel className=\"p-6\">\n <div className=\"mb-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\"timecampus.home.summary.title\", \"Quick Summary\")}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.summary.description\",\n \"Time tracking overview\",\n )}\n </p>\n </div>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.totalHours\", \"Total Hours\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {formatHours(stats?.totalHours ?? 0)}\n </p>\n </div>\n <Clock className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.billableHours\", \"Billable Hours\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {formatHours(stats?.billableHours ?? 0)}\n </p>\n </div>\n <TrendingUp className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.activeTimers\", \"Active Timers\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {stats?.activeTimers ?? 0}\n </p>\n </div>\n <Users className=\"h-5 w-5 text-text-secondary\" />\n </div>\n </div>\n </EmphasisPanel>\n </div>\n\n {/* Quick Actions */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <div className=\"mb-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\"timecampus.home.quickActions.title\", \"Quick Actions\")}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.quickActions.description\",\n \"Frequently used features\",\n )}\n </p>\n </div>\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6\">\n {[\n {\n label: t(\n \"timecampus.home.quickActions.startTimer.label\",\n \"Start Timer\",\n ),\n icon: Play,\n route: \"/time/timer\",\n description: t(\n \"timecampus.home.quickActions.startTimer.description\",\n \"Track your time\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.viewProjects.label\",\n \"View Projects\",\n ),\n icon: FolderOpen,\n route: \"/projects\",\n description: t(\n \"timecampus.home.quickActions.viewProjects.description\",\n \"Manage projects\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.timeEntries.label\",\n \"Time Entries\",\n ),\n icon: Clock,\n route: \"/time/entries\",\n description: t(\n \"timecampus.home.quickActions.timeEntries.description\",\n \"View all entries\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.teamActivity.label\",\n \"Team Activity\",\n ),\n icon: Users,\n route: \"/team-activity\",\n description: t(\n \"timecampus.home.quickActions.teamActivity.description\",\n \"See team status\",\n ),\n },\n {\n label: t(\"timecampus.home.quickActions.reports.label\", \"Reports\"),\n icon: BarChart3,\n route: \"/reports\",\n description: t(\n \"timecampus.home.quickActions.reports.description\",\n \"Generate reports\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.approvals.label\",\n \"Approvals\",\n ),\n icon: CheckCircle,\n route: \"/time-approval\",\n description: t(\n \"timecampus.home.quickActions.approvals.description\",\n \"Review timesheets\",\n ),\n },\n ].map(({ label, icon: Icon, description, route }) => (\n <button\n key={label}\n onClick={() => navigate(route)}\n className=\"flex min-h-[2.75rem] flex-col items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-center transition-colors hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border\"\n >\n <div className=\"rounded-full bg-action-primary-bg/10 p-3\">\n <Icon className=\"h-5 w-5 text-primary\" />\n </div>\n <span className=\"text-sm font-medium text-text-primary\">\n {label}\n </span>\n <span className=\"text-xs text-text-secondary\">{description}</span>\n </button>\n ))}\n </div>\n </GlassCard>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/timecampus/pages/HomePage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport {\n Clock,\n FolderOpen,\n Users,\n TrendingUp,\n CheckCircle,\n BarChart3,\n Play,\n ArrowRight,\n} from \"lucide-react\";\nimport {\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n CTAOverflowMenu,\n} from \"@burdenoff/fe-libs/ui\";\nimport { StatCard } from \"../components/StatCard\";\nimport { LoadingSkeleton } from \"../components/LoadingSkeleton\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { cn, formatHours } from \"../utils/helpers\";\nimport { useTimeCampusNavigate } from \"../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useListTimeEntriesQuery,\n type TimeEntryFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport { useTr } from \"../hooks\";\n\nexport const HomePage: FC = () => {\n const t = useTr();\n const navigate = useTimeCampusNavigate();\n\n const { data: statsData, loading: statsLoading } =\n useGetTimeEntryStatsQuery();\n const { data: entriesData, loading: entriesLoading } =\n useListTimeEntriesQuery({\n variables: { pagination: { limit: 4 } },\n });\n\n const stats = statsData?.timeEntryStats;\n const recentEntries = entriesData?.timeEntries?.items ?? [];\n\n // No time entries at all yet — a genuinely new user, not just a quiet day.\n // Swap the stat grid (which would otherwise read as four confusing zeroes)\n // for a single, honest explanation of the core loop before anything else.\n const isNewUser =\n !statsLoading && !entriesLoading && (stats?.totalEntries ?? 0) === 0;\n\n const headerActions = (\n <CTAOverflowMenu\n primary={{\n label: t(\"timecampus.home.actions.startTimer\", \"Start Timer\"),\n onSelect: () => navigate(\"/time/timer\"),\n icon: <Play className=\"h-4 w-4\" />,\n }}\n actions={[\n {\n label: t(\n \"timecampus.home.quickActions.viewProjects.label\",\n \"View Projects\",\n ),\n onSelect: () => navigate(\"/projects\"),\n icon: <FolderOpen className=\"h-4 w-4\" />,\n },\n {\n label: t(\"timecampus.home.quickActions.reports.label\", \"Reports\"),\n onSelect: () => navigate(\"/reports\"),\n icon: <BarChart3 className=\"h-4 w-4\" />,\n },\n ]}\n />\n );\n\n const renderHeader = () => (\n <div className=\"relative overflow-hidden rounded-2xl border border-border-seam bg-gloss-card p-5 sm:p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0\">\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>\n {t(\"timecampus.home.title\", \"Dashboard\")}\n </GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {t(\n \"timecampus.home.description\",\n \"Overview of your time tracking and productivity\",\n )}\n </p>\n </div>\n {headerActions}\n </div>\n </div>\n );\n\n if (statsLoading && entriesLoading) {\n return (\n <div className=\"min-h-full space-y-6 p-4 sm:p-6\">\n {renderHeader()}\n <LoadingSkeleton variant=\"card\" count={4} />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full space-y-6 p-4 sm:p-6\">\n {renderHeader()}\n\n {/* Hero metric + supporting metrics — or, for a genuinely new user with\n no time entries yet, a single honest explanation of the core loop\n instead of a grid of confusing zeroes. */}\n {isNewUser ? (\n <div className=\"flex flex-col items-center gap-3\">\n <EmptyState\n illustration=\"empty-data\"\n title={t(\n \"timecampus.home.gettingStarted.title\",\n \"Let's get you started\",\n )}\n description={t(\n \"timecampus.home.gettingStarted.description\",\n \"TimeCampus tracks your time when you start a timer — stop it when you're done, and everything else (your Timeline, Focus Score, and Reports) fills in automatically from what you track. No extra setup needed.\",\n )}\n action={\n <button\n type=\"button\"\n onClick={() => navigate(\"/time/timer\")}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Play className=\"h-4 w-4\" />\n {t(\n \"timecampus.home.gettingStarted.action\",\n \"Start your first timer\",\n )}\n </button>\n }\n />\n <p className=\"max-w-md text-center text-xs text-text-secondary\">\n {t(\n \"timecampus.home.gettingStarted.footnote\",\n \"That's the only thing to set up. Pomodoro, Life tracking, reports and everything else in the sidebar are there whenever you're curious — nothing else needs configuring first.\",\n )}\n </p>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n <StatCard\n featured\n title={t(\"timecampus.home.stats.today\", \"Today\")}\n value={formatHours(stats?.totalHours ?? 0)}\n icon={<Clock className=\"h-5 w-5\" />}\n trend={{\n value: 12.5,\n label: t(\"timecampus.home.stats.vsYesterday\", \"vs yesterday\"),\n }}\n />\n <StatCard\n title={t(\"timecampus.home.stats.billable\", \"Billable\")}\n value={formatHours(stats?.billableHours ?? 0)}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n description={`${stats?.totalEntries ?? 0} ${t(\"timecampus.home.stats.entries\", \"entries\")}`}\n />\n <StatCard\n title={t(\"timecampus.home.stats.activeTimers\", \"Active Timers\")}\n value={stats?.activeTimers ?? 0}\n icon={<FolderOpen className=\"h-5 w-5\" />}\n description={t(\n \"timecampus.home.stats.currentlyRunning\",\n \"Currently running\",\n )}\n />\n <StatCard\n title={t(\"timecampus.home.stats.totalEntries\", \"Entries\")}\n value={stats?.totalEntries ?? 0}\n icon={<BarChart3 className=\"h-5 w-5\" />}\n description={t(\n \"timecampus.home.stats.totalEntriesDescription\",\n \"Total time entries\",\n )}\n />\n </div>\n )}\n\n {/* Everything below is exploration/secondary surface — Recent Entries,\n Quick Summary, and the 6-button Quick Actions grid (which includes\n Team Activity and Approvals, not relevant before someone has\n tracked anything). Showing it alongside the single-CTA getting-\n started card undercuts \"just do this one thing\"; hold it back\n until the user has a first entry, then it appears exactly as\n before — same order, same content, no other pages changed. */}\n {!isNewUser && (\n <>\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Recent Time Entries */}\n <GlassCard\n treatment=\"plain\"\n className=\"border-border-seam p-6 lg:col-span-2\"\n >\n <div className=\"mb-4 flex items-center justify-between\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\n \"timecampus.home.recentEntries.title\",\n \"Recent Time Entries\",\n )}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.recentEntries.description\",\n \"Your latest tracked activities\",\n )}\n </p>\n </div>\n <button\n onClick={() => navigate(\"/time/entries\")}\n className=\"inline-flex min-h-[2.75rem] items-center gap-1 rounded-md px-2 text-xs font-medium text-primary transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border\"\n >\n {t(\"timecampus.home.recentEntries.viewAll\", \"View all\")}{\" \"}\n <ArrowRight className=\"h-3 w-3\" />\n </button>\n </div>\n {entriesLoading ? (\n <LoadingSkeleton variant=\"list\" count={4} />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {recentEntries.map((entry: TimeEntryFieldsFragment) => (\n <div\n key={entry.id}\n className=\"flex items-center justify-between rounded-lg border border-border-seam p-3 transition-colors hover:bg-bg-sunken/50\"\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {entry.project?.name ??\n t(\n \"timecampus.home.recentEntries.noProject\",\n \"No Project\",\n )}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {entry.description ??\n t(\n \"timecampus.home.recentEntries.noDescription\",\n \"No description\",\n )}\n </p>\n </div>\n <div className=\"ml-4 text-right\">\n <p className=\"font-mono text-sm font-medium tabular-nums text-text-primary\">\n {formatHours((entry.duration ?? 0) / 3600)}\n </p>\n <span\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium\",\n entry.isRunning\n ? \"bg-status-info-bg text-status-info-text\"\n : \"bg-status-success-bg text-status-success-text\",\n )}\n >\n {entry.isRunning && (\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-info-text motion-safe:animate-vc-glow-pulse\" />\n )}\n {entry.isRunning\n ? t(\n \"timecampus.home.recentEntries.status.running\",\n \"running\",\n )\n : t(\n \"timecampus.home.recentEntries.status.completed\",\n \"completed\",\n )}\n </span>\n </div>\n </div>\n ))}\n {recentEntries.length === 0 && (\n <p className=\"py-4 text-center text-sm text-text-secondary\">\n {t(\n \"timecampus.home.recentEntries.empty\",\n \"No time entries yet\",\n )}\n </p>\n )}\n </div>\n )}\n </GlassCard>\n\n {/* Quick Summary — the one emphasis zone */}\n <EmphasisPanel className=\"p-6\">\n <div className=\"mb-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\"timecampus.home.summary.title\", \"Quick Summary\")}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.summary.description\",\n \"Time tracking overview\",\n )}\n </p>\n </div>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.totalHours\", \"Total Hours\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {formatHours(stats?.totalHours ?? 0)}\n </p>\n </div>\n <Clock className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\n \"timecampus.home.summary.billableHours\",\n \"Billable Hours\",\n )}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {formatHours(stats?.billableHours ?? 0)}\n </p>\n </div>\n <TrendingUp className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\n \"timecampus.home.summary.activeTimers\",\n \"Active Timers\",\n )}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {stats?.activeTimers ?? 0}\n </p>\n </div>\n <Users className=\"h-5 w-5 text-text-secondary\" />\n </div>\n </div>\n </EmphasisPanel>\n </div>\n\n {/* Quick Actions */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <div className=\"mb-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\"timecampus.home.quickActions.title\", \"Quick Actions\")}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.quickActions.description\",\n \"Frequently used features\",\n )}\n </p>\n </div>\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6\">\n {[\n {\n label: t(\n \"timecampus.home.quickActions.startTimer.label\",\n \"Start Timer\",\n ),\n icon: Play,\n route: \"/time/timer\",\n description: t(\n \"timecampus.home.quickActions.startTimer.description\",\n \"Track your time\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.viewProjects.label\",\n \"View Projects\",\n ),\n icon: FolderOpen,\n route: \"/projects\",\n description: t(\n \"timecampus.home.quickActions.viewProjects.description\",\n \"Manage projects\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.timeEntries.label\",\n \"Time Entries\",\n ),\n icon: Clock,\n route: \"/time/entries\",\n description: t(\n \"timecampus.home.quickActions.timeEntries.description\",\n \"View all entries\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.teamActivity.label\",\n \"Team Activity\",\n ),\n icon: Users,\n route: \"/team-activity\",\n description: t(\n \"timecampus.home.quickActions.teamActivity.description\",\n \"See team status\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.reports.label\",\n \"Reports\",\n ),\n icon: BarChart3,\n route: \"/reports\",\n description: t(\n \"timecampus.home.quickActions.reports.description\",\n \"Generate reports\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.approvals.label\",\n \"Approvals\",\n ),\n icon: CheckCircle,\n route: \"/time-approval\",\n description: t(\n \"timecampus.home.quickActions.approvals.description\",\n \"Review timesheets\",\n ),\n },\n ].map(({ label, icon: Icon, description, route }) => (\n <button\n key={label}\n onClick={() => navigate(route)}\n className=\"flex min-h-[2.75rem] flex-col items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-center transition-colors hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border\"\n >\n <div className=\"rounded-full bg-action-primary-bg/10 p-3\">\n <Icon className=\"h-5 w-5 text-primary\" />\n </div>\n <span className=\"text-sm font-medium text-text-primary\">\n {label}\n </span>\n <span className=\"text-xs text-text-secondary\">\n {description}\n </span>\n </button>\n ))}\n </div>\n </GlassCard>\n </>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;AA8BA,IAAa,UAAqB;CAChC,IAAM,IAAI,EAAM,GACV,IAAW,EAAsB,GAEjC,EAAE,MAAM,GAAW,SAAS,MAChC,EAA0B,GACtB,EAAE,MAAM,GAAa,SAAS,MAClC,EAAwB,EACtB,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,EACxC,CAAC,GAEG,IAAQ,GAAW,gBACnB,IAAgB,GAAa,aAAa,SAAS,CAAC,GAKpD,IACJ,CAAC,KAAgB,CAAC,MAAmB,GAAO,gBAAgB,OAAO,GAE/D,IACJ,kBAAC,GAAD;EACE,SAAS;GACP,OAAO,EAAE,sCAAsC,aAAa;GAC5D,gBAAgB,EAAS,aAAa;GACtC,MAAM,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA;EACnC;EACA,SAAS,CACP;GACE,OAAO,EACL,mDACA,eACF;GACA,gBAAgB,EAAS,WAAW;GACpC,MAAM,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;EACzC,GACA;GACE,OAAO,EAAE,8CAA8C,SAAS;GAChE,gBAAgB,EAAS,UAAU;GACnC,MAAM,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA;EACxC,CACF;CACD,CAAA,GAGG,UACJ,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,kBAAC,GAAD,EAAkB,WAAU,SAAU,CAAA,GACtC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;KACZ,UAAA,kBAAC,GAAD,EAAA,UACG,EAAE,yBAAyB,WAAW,EAC3B,CAAA;IACZ,CAAA,GACJ,kBAAC,KAAD;KAAG,WAAU;KACV,UAAA,EACC,+BACA,iDACF;IACC,CAAA,CACA;GACJ,CAAA,GAAA,CACE;EACF,CAAA,CAAA;;CAYP,OATI,KAAgB,IAEhB,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACG,EAAa,GACd,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;EAAI,CAAA,CACxC;MAKP,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACG,EAAa;GAKb,IACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KACE,cAAa;KACb,OAAO,EACL,wCACA,uBACF;KACA,aAAa,EACX,8CACA,iNACF;KACA,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,aAAa;MACrC,WAAU;MAHZ,UAAA,CAKE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,GAC1B,EACC,yCACA,wBACF,CACM;;IAEX,CAAA,GACD,kBAAC,KAAD;KAAG,WAAU;KACV,UAAA,EACC,2CACA,gLACF;IACC,CAAA,CACA;GAEL,CAAA,IAAA,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MACE,UAAA;MACA,OAAO,EAAE,+BAA+B,OAAO;MAC/C,OAAO,EAAY,GAAO,cAAc,CAAC;MACzC,MAAM,kBAAC,GAAD,EAAO,WAAU,UAAW,CAAA;MAClC,OAAO;OACL,OAAO;OACP,OAAO,EAAE,qCAAqC,cAAc;MAC9D;KACD,CAAA;KACD,kBAAC,GAAD;MACE,OAAO,EAAE,kCAAkC,UAAU;MACrD,OAAO,EAAY,GAAO,iBAAiB,CAAC;MAC5C,MAAM,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;MACvC,aAAa,GAAG,GAAO,gBAAgB,EAAE,GAAG,EAAE,iCAAiC,SAAS;KACzF,CAAA;KACD,kBAAC,GAAD;MACE,OAAO,EAAE,sCAAsC,eAAe;MAC9D,OAAO,GAAO,gBAAgB;MAC9B,MAAM,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;MACvC,aAAa,EACX,0CACA,mBACF;KACD,CAAA;KACD,kBAAC,GAAD;MACE,OAAO,EAAE,sCAAsC,SAAS;MACxD,OAAO,GAAO,gBAAgB;MAC9B,MAAM,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA;MACtC,aAAa,EACX,iDACA,oBACF;KACD,CAAA;IACE;;GAUN,CAAC,KACA,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CAEE,kBAAC,GAAD;KACE,WAAU;KACV,WAAU;KAFZ,UAAA,CAIE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;OAAI,WAAU;OACX,UAAA,EACC,uCACA,qBACF;MACE,CAAA,GACJ,kBAAC,KAAD;OAAG,WAAU;OACV,UAAA,EACC,6CACA,gCACF;MACC,CAAA,CACA,EAAA,CAAA,GACL,kBAAC,UAAD;OACE,eAAe,EAAS,eAAe;OACvC,WAAU;OAFZ,UAAA;QAIG,EAAE,yCAAyC,UAAU;QAAG;QACzD,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;OAC3B;MACL,CAAA,CAAA;KACJ,CAAA,GAAA,IACC,kBAAC,GAAD;MAAiB,SAAQ;MAAO,OAAO;KAAI,CAAA,IAE3C,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACG,EAAc,KAAK,MAClB,kBAAC,OAAD;OAEE,WAAU;OAFZ,UAAA,CAIE,kBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,EAAM,SAAS,QACd,EACE,2CACA,YACF;QACD,CAAA,GACH,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,EAAM,eACL,EACE,+CACA,gBACF;QACD,CAAA,CACA;OACL,CAAA,GAAA,kBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,GAAa,EAAM,YAAY,KAAK,IAAI;QACxC,CAAA,GACH,kBAAC,QAAD;SACE,WAAW,EACT,iFACA,EAAM,YACF,4CACA,+CACN;SANF,UAAA,CAQG,EAAM,aACL,kBAAC,QAAD,EAAM,WAAU,iFAAkF,CAAA,GAEnG,EAAM,YACH,EACE,gDACA,SACF,IACA,EACE,kDACA,WACF,CACA;QACH,CAAA,CAAA;OACF,CAAA,CAAA;MA7CE,GAAA,EAAM,EA6CR,CACN,GACA,EAAc,WAAW,KACxB,kBAAC,KAAD;OAAG,WAAU;OACV,UAAA,EACC,uCACA,qBACF;MACC,CAAA,CAEF;KAEE,CAAA,CAAA;IAGX,CAAA,GAAA,kBAAC,GAAD;KAAe,WAAU;KAAzB,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC,MAAD;OAAI,WAAU;OACX,UAAA,EAAE,iCAAiC,eAAe;MACjD,CAAA,GACJ,kBAAC,KAAD;OAAG,WAAU;OACV,UAAA,EACC,uCACA,wBACF;MACC,CAAA,CACA;KACL,CAAA,GAAA,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,EAAE,sCAAsC,aAAa;QACrD,CAAA,GACH,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,EAAY,GAAO,cAAc,CAAC;QAClC,CAAA,CACA,EAAA,CAAA,GACL,kBAAC,GAAD,EAAO,WAAU,8BAA+B,CAAA,CAC7C;;OACL,kBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,EACC,yCACA,gBACF;QACC,CAAA,GACH,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,EAAY,GAAO,iBAAiB,CAAC;QACrC,CAAA,CACA,EAAA,CAAA,GACL,kBAAC,GAAD,EAAY,WAAU,8BAA+B,CAAA,CAClD;;OACL,kBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,EACC,wCACA,eACF;QACC,CAAA,GACH,kBAAC,KAAD;SAAG,WAAU;SACV,UAAA,GAAO,gBAAgB;QACvB,CAAA,CACA,EAAA,CAAA,GACL,kBAAC,GAAD,EAAO,WAAU,8BAA+B,CAAA,CAC7C;;MACF;KACQ,CAAA,CAAA;IACZ,CAAA,CAAA;GAGL,CAAA,GAAA,kBAAC,GAAD;IAAW,WAAU;IAAQ,WAAU;IAAvC,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;MACX,UAAA,EAAE,sCAAsC,eAAe;KACtD,CAAA,GACJ,kBAAC,KAAD;MAAG,WAAU;MACV,UAAA,EACC,4CACA,0BACF;KACC,CAAA,CACA;IACL,CAAA,GAAA,kBAAC,OAAD;KAAK,WAAU;KACZ,UAAA;MACC;OACE,OAAO,EACL,iDACA,aACF;OACA,MAAM;OACN,OAAO;OACP,aAAa,EACX,uDACA,iBACF;MACF;MACA;OACE,OAAO,EACL,mDACA,eACF;OACA,MAAM;OACN,OAAO;OACP,aAAa,EACX,yDACA,iBACF;MACF;MACA;OACE,OAAO,EACL,kDACA,cACF;OACA,MAAM;OACN,OAAO;OACP,aAAa,EACX,wDACA,kBACF;MACF;MACA;OACE,OAAO,EACL,mDACA,eACF;OACA,MAAM;OACN,OAAO;OACP,aAAa,EACX,yDACA,iBACF;MACF;MACA;OACE,OAAO,EACL,8CACA,SACF;OACA,MAAM;OACN,OAAO;OACP,aAAa,EACX,oDACA,kBACF;MACF;MACA;OACE,OAAO,EACL,gDACA,WACF;OACA,MAAM;OACN,OAAO;OACP,aAAa,EACX,sDACA,mBACF;MACF;KACF,CAAC,CAAC,KAAK,EAAE,UAAO,MAAM,GAAM,gBAAa,eACvC,kBAAC,UAAD;MAEE,eAAe,EAAS,CAAK;MAC7B,WAAU;MAHZ,UAAA;OAKE,kBAAC,OAAD;QAAK,WAAU;QACb,UAAA,kBAAC,GAAD,EAAM,WAAU,uBAAwB,CAAA;OACrC,CAAA;OACL,kBAAC,QAAD;QAAM,WAAU;QACb,UAAA;OACG,CAAA;OACN,kBAAC,QAAD;QAAM,WAAU;QACb,UAAA;OACG,CAAA;MACA;KAbD,GAAA,CAaC,CACT;IACE,CAAA,CACI;GACX,CAAA,CAAA,EAAA,CAAA;EAED;;AAET"}
|