@burdenoff/microfe-timecampus 2026.710.1 → 2026.710.2
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/index.js +2 -1
- package/dist/services/assistantApi.js +248 -0
- package/dist/services/assistantApi.js.map +1 -0
- package/dist/services/createSandboxAssistantTransport.js +120 -0
- package/dist/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/timecampus/components/DataTable.js +1 -0
- package/dist/timecampus/components/FilterBar.js +1 -0
- package/dist/timecampus/components/charts/BalanceWheel.js +38 -43
- package/dist/timecampus/components/charts/BalanceWheel.js.map +1 -1
- package/dist/timecampus/components/charts/BarsChart.js +24 -31
- package/dist/timecampus/components/charts/BarsChart.js.map +1 -1
- package/dist/timecampus/components/charts/DonutChart.js +36 -40
- package/dist/timecampus/components/charts/DonutChart.js.map +1 -1
- package/dist/timecampus/components/charts/RadialGauge.js +14 -17
- package/dist/timecampus/components/charts/RadialGauge.js.map +1 -1
- package/dist/timecampus/components/charts/Sparkline.js +2 -0
- package/dist/timecampus/components/charts/TrendChart.js +47 -57
- package/dist/timecampus/components/charts/TrendChart.js.map +1 -1
- package/dist/timecampus/index.d.ts +1 -0
- package/dist/timecampus/index.d.ts.map +1 -1
- package/dist/timecampus/index.js +1 -0
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +4 -4
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +4 -4
- package/dist/timecampus/providers/TimeCampusProvider.js +32 -32
- package/dist/timecampus/utils/helpers.js +2 -2
- package/dist/utils/pageContext.js +52 -0
- package/dist/utils/pageContext.js.map +1 -0
- package/package.json +1 -1
- package/dist/_virtual/_rolldown/runtime.js +0 -20
|
@@ -1,58 +1,55 @@
|
|
|
1
1
|
import { cn as e } from "../../utils/helpers.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { RadialBar as
|
|
5
|
-
import { RadialBarChart as i } from "../../../node_modules/recharts/es6/chart/RadialBarChart.js";
|
|
6
|
-
import { chartTokens as a, toneColor as o, usePrefersReducedMotion as s } from "./chartTheme.js";
|
|
7
|
-
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
2
|
+
import { chartTokens as t, toneColor as n, usePrefersReducedMotion as r } from "./chartTheme.js";
|
|
3
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
4
|
+
import { PolarAngleAxis as o, RadialBar as s, RadialBarChart as c, ResponsiveContainer as l } from "recharts";
|
|
8
5
|
//#region src/timecampus/components/charts/RadialGauge.tsx
|
|
9
6
|
var u = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
10
7
|
function d({ value: d, min: f = 0, max: p = 100, label: m, sublabel: h, thresholds: g, higherIsBetter: _ = !0, tone: v, color: y, height: b = 200, format: x = (e) => Math.round(e).toString(), ariaLabel: S, className: C }) {
|
|
11
|
-
let w =
|
|
8
|
+
let w = r(), T = p - f || 1, E = u(d, f, p), D = g?.warning ?? (_ ? f + T * .8 : f + T * .5), O = g?.danger ?? (_ ? f + T * .5 : f + T * .8), k = y ?? n(v ?? (_ ? d >= D ? "success" : d >= O ? "warning" : "danger" : d <= D ? "success" : d <= O ? "warning" : "danger")), A = [{
|
|
12
9
|
name: m ?? "value",
|
|
13
10
|
value: E
|
|
14
11
|
}];
|
|
15
|
-
return /* @__PURE__ */
|
|
12
|
+
return /* @__PURE__ */ a("figure", {
|
|
16
13
|
role: "img",
|
|
17
14
|
"aria-label": S ?? `${m ? `${m}: ` : ""}${x(d)}`,
|
|
18
15
|
className: e("relative w-full", C),
|
|
19
16
|
style: { height: b },
|
|
20
|
-
children: [/* @__PURE__ */
|
|
17
|
+
children: [/* @__PURE__ */ i(l, {
|
|
21
18
|
width: "100%",
|
|
22
19
|
height: "100%",
|
|
23
|
-
children: /* @__PURE__ */
|
|
20
|
+
children: /* @__PURE__ */ a(c, {
|
|
24
21
|
data: A,
|
|
25
22
|
innerRadius: "72%",
|
|
26
23
|
outerRadius: "100%",
|
|
27
24
|
barSize: 14,
|
|
28
25
|
startAngle: 225,
|
|
29
26
|
endAngle: -45,
|
|
30
|
-
children: [/* @__PURE__ */
|
|
27
|
+
children: [/* @__PURE__ */ i(o, {
|
|
31
28
|
type: "number",
|
|
32
29
|
domain: [f, p],
|
|
33
30
|
angleAxisId: 0,
|
|
34
31
|
tick: !1
|
|
35
|
-
}), /* @__PURE__ */
|
|
32
|
+
}), /* @__PURE__ */ i(s, {
|
|
36
33
|
dataKey: "value",
|
|
37
34
|
angleAxisId: 0,
|
|
38
|
-
background: { fill:
|
|
35
|
+
background: { fill: t.track },
|
|
39
36
|
cornerRadius: 999,
|
|
40
37
|
fill: k,
|
|
41
38
|
isAnimationActive: !w
|
|
42
39
|
})]
|
|
43
40
|
})
|
|
44
|
-
}), /* @__PURE__ */
|
|
41
|
+
}), /* @__PURE__ */ a("div", {
|
|
45
42
|
className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center",
|
|
46
43
|
children: [
|
|
47
|
-
/* @__PURE__ */
|
|
44
|
+
/* @__PURE__ */ i("span", {
|
|
48
45
|
className: "text-3xl font-bold leading-none text-text-primary",
|
|
49
46
|
children: x(d)
|
|
50
47
|
}),
|
|
51
|
-
m ? /* @__PURE__ */
|
|
48
|
+
m ? /* @__PURE__ */ i("span", {
|
|
52
49
|
className: "mt-1 text-sm font-medium text-text-secondary",
|
|
53
50
|
children: m
|
|
54
51
|
}) : null,
|
|
55
|
-
h ? /* @__PURE__ */
|
|
52
|
+
h ? /* @__PURE__ */ i("span", {
|
|
56
53
|
className: "text-xs text-text-muted",
|
|
57
54
|
children: h
|
|
58
55
|
}) : null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadialGauge.js","names":[],"sources":["../../../../src/timecampus/components/charts/RadialGauge.tsx"],"sourcesContent":["import {\n PolarAngleAxis,\n RadialBar,\n RadialBarChart,\n ResponsiveContainer,\n} from \"recharts\";\nimport { cn } from \"../../utils/helpers\";\nimport {\n chartTokens,\n toneColor,\n usePrefersReducedMotion,\n type MeterTone,\n type ValueFormatter,\n} from \"./chartTheme\";\n\nexport interface RadialGaugeProps {\n /** The measured value. */\n value: number;\n /** Scale minimum. Default 0. */\n min?: number;\n /** Scale maximum. Default 100. */\n max?: number;\n /** Big centre caption (e.g. \"Compliance\"). */\n label?: string;\n /** Small caption under the value. */\n sublabel?: string;\n /**\n * Severity thresholds in value units. With `higherIsBetter` (default) pass\n * `warning > danger` (e.g. `{ warning: 80, danger: 50 }` → ≥80 good, 50–79\n * warning, <50 danger). Defaults derive from the range.\n */\n thresholds?: { warning: number; danger: number };\n /** Whether a higher value is better (compliance/health) or worse (risk). Default true. */\n higherIsBetter?: boolean;\n /** Force a tone, bypassing threshold logic. */\n tone?: MeterTone;\n /** Force an explicit colour, bypassing tone + thresholds. */\n color?: string;\n /** Pixel height. Default 200. */\n height?: number;\n /** Formats the centre value. Default rounds to an integer. */\n format?: ValueFormatter;\n /** Accessible name. Default derived from label + value. */\n ariaLabel?: string;\n className?: string;\n}\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(max, Math.max(min, value));\n\n/**\n * RadialGauge — a single value on a 270° arc (compliance score, asset health,\n * risk). The arc colour follows severity thresholds (good → warning → danger)\n * using reserved status tokens, over a muted track. Center shows the value and\n * label; respects `prefers-reduced-motion`.\n */\nexport function RadialGauge({\n value,\n min = 0,\n max = 100,\n label,\n sublabel,\n thresholds,\n higherIsBetter = true,\n tone,\n color,\n height = 200,\n format = (v) => Math.round(v).toString(),\n ariaLabel,\n className,\n}: RadialGaugeProps) {\n const reducedMotion = usePrefersReducedMotion();\n const range = max - min || 1;\n const clamped = clamp(value, min, max);\n\n const warning =\n thresholds?.warning ??\n (higherIsBetter ? min + range * 0.8 : min + range * 0.5);\n const danger =\n thresholds?.danger ??\n (higherIsBetter ? min + range * 0.5 : min + range * 0.8);\n\n const resolvedTone: MeterTone =\n tone ??\n (higherIsBetter\n ? value >= warning\n ? \"success\"\n : value >= danger\n ? \"warning\"\n : \"danger\"\n : value <= warning\n ? \"success\"\n : value <= danger\n ? \"warning\"\n : \"danger\");\n\n const arcColor = color ?? toneColor(resolvedTone);\n const data = [{ name: label ?? \"value\", value: clamped }];\n const accessibleName =\n ariaLabel ?? `${label ? `${label}: ` : \"\"}${format(value)}`;\n\n return (\n <figure\n role=\"img\"\n aria-label={accessibleName}\n className={cn(\"relative w-full\", className)}\n style={{ height }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RadialBarChart\n data={data}\n innerRadius=\"72%\"\n outerRadius=\"100%\"\n barSize={14}\n startAngle={225}\n endAngle={-45}\n >\n <PolarAngleAxis\n type=\"number\"\n domain={[min, max]}\n angleAxisId={0}\n tick={false}\n />\n <RadialBar\n dataKey=\"value\"\n angleAxisId={0}\n background={{ fill: chartTokens.track }}\n cornerRadius={999}\n fill={arcColor}\n isAnimationActive={!reducedMotion}\n />\n </RadialBarChart>\n </ResponsiveContainer>\n\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center\">\n <span className=\"text-3xl font-bold leading-none text-text-primary\">\n {format(value)}\n </span>\n {label ? (\n <span className=\"mt-1 text-sm font-medium text-text-secondary\">\n {label}\n </span>\n ) : null}\n {sublabel ? (\n <span className=\"text-xs text-text-muted\">{sublabel}</span>\n ) : null}\n </div>\n </figure>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"RadialGauge.js","names":[],"sources":["../../../../src/timecampus/components/charts/RadialGauge.tsx"],"sourcesContent":["import {\n PolarAngleAxis,\n RadialBar,\n RadialBarChart,\n ResponsiveContainer,\n} from \"recharts\";\nimport { cn } from \"../../utils/helpers\";\nimport {\n chartTokens,\n toneColor,\n usePrefersReducedMotion,\n type MeterTone,\n type ValueFormatter,\n} from \"./chartTheme\";\n\nexport interface RadialGaugeProps {\n /** The measured value. */\n value: number;\n /** Scale minimum. Default 0. */\n min?: number;\n /** Scale maximum. Default 100. */\n max?: number;\n /** Big centre caption (e.g. \"Compliance\"). */\n label?: string;\n /** Small caption under the value. */\n sublabel?: string;\n /**\n * Severity thresholds in value units. With `higherIsBetter` (default) pass\n * `warning > danger` (e.g. `{ warning: 80, danger: 50 }` → ≥80 good, 50–79\n * warning, <50 danger). Defaults derive from the range.\n */\n thresholds?: { warning: number; danger: number };\n /** Whether a higher value is better (compliance/health) or worse (risk). Default true. */\n higherIsBetter?: boolean;\n /** Force a tone, bypassing threshold logic. */\n tone?: MeterTone;\n /** Force an explicit colour, bypassing tone + thresholds. */\n color?: string;\n /** Pixel height. Default 200. */\n height?: number;\n /** Formats the centre value. Default rounds to an integer. */\n format?: ValueFormatter;\n /** Accessible name. Default derived from label + value. */\n ariaLabel?: string;\n className?: string;\n}\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(max, Math.max(min, value));\n\n/**\n * RadialGauge — a single value on a 270° arc (compliance score, asset health,\n * risk). The arc colour follows severity thresholds (good → warning → danger)\n * using reserved status tokens, over a muted track. Center shows the value and\n * label; respects `prefers-reduced-motion`.\n */\nexport function RadialGauge({\n value,\n min = 0,\n max = 100,\n label,\n sublabel,\n thresholds,\n higherIsBetter = true,\n tone,\n color,\n height = 200,\n format = (v) => Math.round(v).toString(),\n ariaLabel,\n className,\n}: RadialGaugeProps) {\n const reducedMotion = usePrefersReducedMotion();\n const range = max - min || 1;\n const clamped = clamp(value, min, max);\n\n const warning =\n thresholds?.warning ??\n (higherIsBetter ? min + range * 0.8 : min + range * 0.5);\n const danger =\n thresholds?.danger ??\n (higherIsBetter ? min + range * 0.5 : min + range * 0.8);\n\n const resolvedTone: MeterTone =\n tone ??\n (higherIsBetter\n ? value >= warning\n ? \"success\"\n : value >= danger\n ? \"warning\"\n : \"danger\"\n : value <= warning\n ? \"success\"\n : value <= danger\n ? \"warning\"\n : \"danger\");\n\n const arcColor = color ?? toneColor(resolvedTone);\n const data = [{ name: label ?? \"value\", value: clamped }];\n const accessibleName =\n ariaLabel ?? `${label ? `${label}: ` : \"\"}${format(value)}`;\n\n return (\n <figure\n role=\"img\"\n aria-label={accessibleName}\n className={cn(\"relative w-full\", className)}\n style={{ height }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RadialBarChart\n data={data}\n innerRadius=\"72%\"\n outerRadius=\"100%\"\n barSize={14}\n startAngle={225}\n endAngle={-45}\n >\n <PolarAngleAxis\n type=\"number\"\n domain={[min, max]}\n angleAxisId={0}\n tick={false}\n />\n <RadialBar\n dataKey=\"value\"\n angleAxisId={0}\n background={{ fill: chartTokens.track }}\n cornerRadius={999}\n fill={arcColor}\n isAnimationActive={!reducedMotion}\n />\n </RadialBarChart>\n </ResponsiveContainer>\n\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center\">\n <span className=\"text-3xl font-bold leading-none text-text-primary\">\n {format(value)}\n </span>\n {label ? (\n <span className=\"mt-1 text-sm font-medium text-text-secondary\">\n {label}\n </span>\n ) : null}\n {sublabel ? (\n <span className=\"text-xs text-text-muted\">{sublabel}</span>\n ) : null}\n </div>\n </figure>\n );\n}\n"],"mappings":";;;;;AA+CA,IAAM,KAAS,GAAe,GAAa,MACzC,KAAK,IAAI,GAAK,KAAK,IAAI,GAAK,EAAM,CAAC;AAQrC,SAAgB,EAAY,EAC1B,UACA,SAAM,GACN,SAAM,KACN,UACA,aACA,eACA,oBAAiB,IACjB,SACA,UACA,YAAS,KACT,aAAU,MAAM,KAAK,MAAM,EAAE,CAAC,UAAU,EACxC,cACA,gBACmB;CACnB,IAAM,IAAgB,GAAyB,EACzC,IAAQ,IAAM,KAAO,GACrB,IAAU,EAAM,GAAO,GAAK,EAAI,EAEhC,IACJ,GAAY,YACX,IAAiB,IAAM,IAAQ,KAAM,IAAM,IAAQ,KAChD,IACJ,GAAY,WACX,IAAiB,IAAM,IAAQ,KAAM,IAAM,IAAQ,KAgBhD,IAAW,KAAS,EAbxB,MACC,IACG,KAAS,IACP,YACA,KAAS,IACP,YACA,WACJ,KAAS,IACP,YACA,KAAS,IACP,YACA,UAEuC,EAC3C,IAAO,CAAC;EAAE,MAAM,KAAS;EAAS,OAAO;EAAS,CAAC;AAIzD,QACE,kBAAC,UAAD;EACE,MAAK;EACL,cALF,KAAa,GAAG,IAAQ,GAAG,EAAM,MAAM,KAAK,EAAO,EAAM;EAMvD,WAAW,EAAG,mBAAmB,EAAU;EAC3C,OAAO,EAAE,WAAQ;YAJnB,CAME,kBAAC,GAAD;GAAqB,OAAM;GAAO,QAAO;aACvC,kBAAC,GAAD;IACQ;IACN,aAAY;IACZ,aAAY;IACZ,SAAS;IACT,YAAY;IACZ,UAAU;cANZ,CAQE,kBAAC,GAAD;KACE,MAAK;KACL,QAAQ,CAAC,GAAK,EAAI;KAClB,aAAa;KACb,MAAM;KACN,CAAA,EACF,kBAAC,GAAD;KACE,SAAQ;KACR,aAAa;KACb,YAAY,EAAE,MAAM,EAAY,OAAO;KACvC,cAAc;KACd,MAAM;KACN,mBAAmB,CAAC;KACpB,CAAA,CACa;;GACG,CAAA,EAEtB,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,QAAD;KAAM,WAAU;eACb,EAAO,EAAM;KACT,CAAA;IACN,IACC,kBAAC,QAAD;KAAM,WAAU;eACb;KACI,CAAA,GACL;IACH,IACC,kBAAC,QAAD;KAAM,WAAU;eAA2B;KAAgB,CAAA,GACzD;IACA;KACC"}
|
|
@@ -1,32 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { CartesianGrid as
|
|
6
|
-
import { Line as a } from "../../../node_modules/recharts/es6/cartesian/Line.js";
|
|
7
|
-
import { Area as o } from "../../../node_modules/recharts/es6/cartesian/Area.js";
|
|
8
|
-
import { XAxis as s } from "../../../node_modules/recharts/es6/cartesian/XAxis.js";
|
|
9
|
-
import { YAxis as c } from "../../../node_modules/recharts/es6/cartesian/YAxis.js";
|
|
10
|
-
import { LineChart as l } from "../../../node_modules/recharts/es6/chart/LineChart.js";
|
|
11
|
-
import { AreaChart as u } from "../../../node_modules/recharts/es6/chart/AreaChart.js";
|
|
12
|
-
import { chartTokens as d, defaultSeriesColor as f, formatNumber as p, usePrefersReducedMotion as m } from "./chartTheme.js";
|
|
13
|
-
import { ChartDataTable as h, ChartEmpty as g, ChartFigure as _, ChartLegend as v, ChartTooltip as y } from "./ChartParts.js";
|
|
14
|
-
import { useId as b } from "react";
|
|
15
|
-
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
1
|
+
import { chartTokens as e, defaultSeriesColor as t, formatNumber as n, usePrefersReducedMotion as r } from "./chartTheme.js";
|
|
2
|
+
import { ChartDataTable as i, ChartEmpty as a, ChartFigure as o, ChartLegend as s, ChartTooltip as c } from "./ChartParts.js";
|
|
3
|
+
import { useId as l } from "react";
|
|
4
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
5
|
+
import { Area as f, AreaChart as p, CartesianGrid as m, Legend as h, Line as g, LineChart as _, ReferenceDot as v, ResponsiveContainer as y, Tooltip as b, XAxis as x, YAxis as S } from "recharts";
|
|
16
6
|
//#region src/timecampus/components/charts/TrendChart.tsx
|
|
17
|
-
function C({ data: C, xKey: w, series: T, type: E = "area", height: D = 260, valueFormat: O =
|
|
18
|
-
let I =
|
|
7
|
+
function C({ data: C, xKey: w, series: T, type: E = "area", height: D = 260, valueFormat: O = n, xTickFormat: k, showGrid: A = !0, showLegend: j, showEndDots: M = !0, emptyLabel: N, ariaLabel: P, className: F }) {
|
|
8
|
+
let I = l(), L = r(), R = T.map((e, n) => ({
|
|
19
9
|
...e,
|
|
20
10
|
label: e.label ?? e.key,
|
|
21
|
-
color: e.color ??
|
|
11
|
+
color: e.color ?? t(n, T.length)
|
|
22
12
|
})), z = P ?? `Trend of ${R.map((e) => e.label).join(", ")}`;
|
|
23
|
-
if (C.length === 0) return /* @__PURE__ */
|
|
13
|
+
if (C.length === 0) return /* @__PURE__ */ u(a, {
|
|
24
14
|
height: D,
|
|
25
15
|
label: N,
|
|
26
16
|
className: F
|
|
27
17
|
});
|
|
28
18
|
let B = j ?? R.length > 1, V = {
|
|
29
|
-
fill:
|
|
19
|
+
fill: e.textMuted,
|
|
30
20
|
fontSize: 12
|
|
31
21
|
}, H = (e) => {
|
|
32
22
|
for (let t = C.length - 1; t >= 0; --t) {
|
|
@@ -35,11 +25,11 @@ function C({ data: C, xKey: w, series: T, type: E = "area", height: D = 260, val
|
|
|
35
25
|
}
|
|
36
26
|
return -1;
|
|
37
27
|
};
|
|
38
|
-
return /* @__PURE__ */
|
|
28
|
+
return /* @__PURE__ */ u(o, {
|
|
39
29
|
ariaLabel: z,
|
|
40
30
|
height: D,
|
|
41
31
|
className: F,
|
|
42
|
-
a11y: /* @__PURE__ */
|
|
32
|
+
a11y: /* @__PURE__ */ u(i, {
|
|
43
33
|
caption: z,
|
|
44
34
|
xLabel: w,
|
|
45
35
|
xKey: w,
|
|
@@ -47,10 +37,10 @@ function C({ data: C, xKey: w, series: T, type: E = "area", height: D = 260, val
|
|
|
47
37
|
series: R,
|
|
48
38
|
valueFormat: O
|
|
49
39
|
}),
|
|
50
|
-
children: /* @__PURE__ */
|
|
40
|
+
children: /* @__PURE__ */ u(y, {
|
|
51
41
|
width: "100%",
|
|
52
42
|
height: "100%",
|
|
53
|
-
children: /* @__PURE__ */
|
|
43
|
+
children: /* @__PURE__ */ d(E === "area" ? p : _, {
|
|
54
44
|
data: C,
|
|
55
45
|
margin: {
|
|
56
46
|
top: 12,
|
|
@@ -59,28 +49,28 @@ function C({ data: C, xKey: w, series: T, type: E = "area", height: D = 260, val
|
|
|
59
49
|
left: 4
|
|
60
50
|
},
|
|
61
51
|
children: [
|
|
62
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ u("defs", { children: R.map((e, t) => /* @__PURE__ */ d("linearGradient", {
|
|
63
53
|
id: `${I}-${t}`,
|
|
64
54
|
x1: "0",
|
|
65
55
|
y1: "0",
|
|
66
56
|
x2: "0",
|
|
67
57
|
y2: "1",
|
|
68
|
-
children: [/* @__PURE__ */
|
|
58
|
+
children: [/* @__PURE__ */ u("stop", {
|
|
69
59
|
offset: "0%",
|
|
70
60
|
stopColor: e.color,
|
|
71
61
|
stopOpacity: .24
|
|
72
|
-
}), /* @__PURE__ */
|
|
62
|
+
}), /* @__PURE__ */ u("stop", {
|
|
73
63
|
offset: "95%",
|
|
74
64
|
stopColor: e.color,
|
|
75
65
|
stopOpacity: .02
|
|
76
66
|
})]
|
|
77
67
|
}, e.key)) }),
|
|
78
|
-
A ? /* @__PURE__ */
|
|
68
|
+
A ? /* @__PURE__ */ u(m, {
|
|
79
69
|
vertical: !1,
|
|
80
|
-
stroke:
|
|
70
|
+
stroke: e.grid,
|
|
81
71
|
strokeWidth: 1
|
|
82
72
|
}) : null,
|
|
83
|
-
/* @__PURE__ */ x
|
|
73
|
+
/* @__PURE__ */ u(x, {
|
|
84
74
|
dataKey: w,
|
|
85
75
|
tickLine: !1,
|
|
86
76
|
axisLine: !1,
|
|
@@ -89,66 +79,66 @@ function C({ data: C, xKey: w, series: T, type: E = "area", height: D = 260, val
|
|
|
89
79
|
minTickGap: 16,
|
|
90
80
|
tickFormatter: k ? (e) => k(e) : void 0
|
|
91
81
|
}),
|
|
92
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ u(S, {
|
|
93
83
|
tickLine: !1,
|
|
94
84
|
axisLine: !1,
|
|
95
85
|
tick: V,
|
|
96
86
|
width: 48,
|
|
97
87
|
tickFormatter: (e) => O(Number(e))
|
|
98
88
|
}),
|
|
99
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ u(b, {
|
|
100
90
|
cursor: {
|
|
101
|
-
stroke:
|
|
91
|
+
stroke: e.axis,
|
|
102
92
|
strokeWidth: 1
|
|
103
93
|
},
|
|
104
|
-
content: /* @__PURE__ */
|
|
94
|
+
content: /* @__PURE__ */ u(c, {
|
|
105
95
|
valueFormat: O,
|
|
106
96
|
labelFormat: k,
|
|
107
97
|
hideLabel: !1
|
|
108
98
|
})
|
|
109
99
|
}),
|
|
110
|
-
B ? /* @__PURE__ */
|
|
111
|
-
R.map((
|
|
100
|
+
B ? /* @__PURE__ */ u(h, { content: /* @__PURE__ */ u(s, {}) }) : null,
|
|
101
|
+
R.map((t, n) => E === "area" ? /* @__PURE__ */ u(f, {
|
|
112
102
|
type: "monotone",
|
|
113
|
-
dataKey:
|
|
114
|
-
name:
|
|
115
|
-
stroke:
|
|
103
|
+
dataKey: t.key,
|
|
104
|
+
name: t.label,
|
|
105
|
+
stroke: t.color,
|
|
116
106
|
strokeWidth: 2,
|
|
117
|
-
fill: `url(#${I}-${
|
|
107
|
+
fill: `url(#${I}-${n})`,
|
|
118
108
|
isAnimationActive: !L,
|
|
119
109
|
dot: !1,
|
|
120
110
|
activeDot: {
|
|
121
111
|
r: 4,
|
|
122
112
|
strokeWidth: 2,
|
|
123
|
-
stroke:
|
|
124
|
-
fill:
|
|
113
|
+
stroke: e.surface,
|
|
114
|
+
fill: t.color
|
|
125
115
|
}
|
|
126
|
-
},
|
|
116
|
+
}, t.key) : /* @__PURE__ */ u(g, {
|
|
127
117
|
type: "monotone",
|
|
128
|
-
dataKey:
|
|
129
|
-
name:
|
|
130
|
-
stroke:
|
|
118
|
+
dataKey: t.key,
|
|
119
|
+
name: t.label,
|
|
120
|
+
stroke: t.color,
|
|
131
121
|
strokeWidth: 2,
|
|
132
122
|
isAnimationActive: !L,
|
|
133
123
|
dot: !1,
|
|
134
124
|
activeDot: {
|
|
135
125
|
r: 4,
|
|
136
126
|
strokeWidth: 2,
|
|
137
|
-
stroke:
|
|
138
|
-
fill:
|
|
127
|
+
stroke: e.surface,
|
|
128
|
+
fill: t.color
|
|
139
129
|
}
|
|
140
|
-
},
|
|
141
|
-
M ? R.map((
|
|
142
|
-
let
|
|
143
|
-
return
|
|
144
|
-
x: C[
|
|
145
|
-
y: C[
|
|
130
|
+
}, t.key)),
|
|
131
|
+
M ? R.map((t) => {
|
|
132
|
+
let n = H(t.key);
|
|
133
|
+
return n < 0 ? null : /* @__PURE__ */ u(v, {
|
|
134
|
+
x: C[n][w],
|
|
135
|
+
y: C[n][t.key],
|
|
146
136
|
r: 4,
|
|
147
|
-
fill:
|
|
148
|
-
stroke:
|
|
137
|
+
fill: t.color,
|
|
138
|
+
stroke: e.surface,
|
|
149
139
|
strokeWidth: 2,
|
|
150
140
|
isFront: !0
|
|
151
|
-
}, `end-${
|
|
141
|
+
}, `end-${t.key}`);
|
|
152
142
|
}) : null
|
|
153
143
|
]
|
|
154
144
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrendChart.js","names":[],"sources":["../../../../src/timecampus/components/charts/TrendChart.tsx"],"sourcesContent":["import { useId } from \"react\";\nimport {\n Area,\n AreaChart,\n CartesianGrid,\n Legend,\n Line,\n LineChart,\n ReferenceDot,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport {\n chartTokens,\n defaultSeriesColor,\n formatNumber,\n usePrefersReducedMotion,\n type ChartDatum,\n type ChartSeries,\n type ValueFormatter,\n} from \"./chartTheme\";\nimport {\n ChartDataTable,\n ChartEmpty,\n ChartFigure,\n ChartLegend,\n ChartTooltip,\n} from \"./ChartParts\";\n\nexport interface TrendChartProps {\n /** Rows of `{ [xKey]: label, [series.key]: number }`. */\n data: ChartDatum[];\n /** Field holding the x-axis category/time value. */\n xKey: string;\n /** One or more numeric series. Single series reads on-brand. */\n series: ChartSeries[];\n /** Line, or gradient-filled area. Default `area`. */\n type?: \"line\" | \"area\";\n /** Pixel height of the plot. Default 260. */\n height?: number;\n /** Formats y values in the axis and tooltip. Default grouped integer. */\n valueFormat?: ValueFormatter;\n /** Formats x tick + tooltip header. */\n xTickFormat?: (value: string | number) => string;\n /** Show the horizontal grid. Default true. */\n showGrid?: boolean;\n /** Force the legend on/off. Default: on when there are ≥ 2 series. */\n showLegend?: boolean;\n /** Emphasise each series' final point with a ringed dot. Default true. */\n showEndDots?: boolean;\n /** Message shown when `data` is empty — never fabricate a shape. */\n emptyLabel?: string;\n /** Accessible name for the figure. Default derived from the series labels. */\n ariaLabel?: string;\n className?: string;\n}\n\n/**\n * TrendChart — value-over-time as a line or gradient area (asset value,\n * emissions, depreciation). Theme-aware tokens, a hairline grid, a crosshair\n * tooltip, emphasised endpoints, a legend for multi-series, an empty state and\n * a screen-reader data table. Respects `prefers-reduced-motion`.\n */\nexport function TrendChart({\n data,\n xKey,\n series,\n type = \"area\",\n height = 260,\n valueFormat = formatNumber,\n xTickFormat,\n showGrid = true,\n showLegend,\n showEndDots = true,\n emptyLabel,\n ariaLabel,\n className,\n}: TrendChartProps) {\n const gradientBase = useId();\n const reducedMotion = usePrefersReducedMotion();\n\n const resolved = series.map((s, index) => ({\n ...s,\n label: s.label ?? s.key,\n color: s.color ?? defaultSeriesColor(index, series.length),\n }));\n const label =\n ariaLabel ?? `Trend of ${resolved.map((s) => s.label).join(\", \")}`;\n\n if (data.length === 0) {\n return (\n <ChartEmpty height={height} label={emptyLabel} className={className} />\n );\n }\n\n const withLegend = showLegend ?? resolved.length > 1;\n const axisTick = { fill: chartTokens.textMuted, fontSize: 12 };\n\n const lastFiniteIndex = (key: string): number => {\n for (let i = data.length - 1; i >= 0; i -= 1) {\n const value = data[i][key];\n if (typeof value === \"number\" && Number.isFinite(value)) return i;\n }\n return -1;\n };\n\n const Chart = type === \"area\" ? AreaChart : LineChart;\n\n return (\n <ChartFigure\n ariaLabel={label}\n height={height}\n className={className}\n a11y={\n <ChartDataTable\n caption={label}\n xLabel={xKey}\n xKey={xKey}\n data={data}\n series={resolved}\n valueFormat={valueFormat}\n />\n }\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <Chart data={data} margin={{ top: 12, right: 16, bottom: 4, left: 4 }}>\n <defs>\n {resolved.map((s, index) => (\n <linearGradient\n key={s.key}\n id={`${gradientBase}-${index}`}\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\"\n >\n <stop offset=\"0%\" stopColor={s.color} stopOpacity={0.24} />\n <stop offset=\"95%\" stopColor={s.color} stopOpacity={0.02} />\n </linearGradient>\n ))}\n </defs>\n\n {showGrid ? (\n <CartesianGrid\n vertical={false}\n stroke={chartTokens.grid}\n strokeWidth={1}\n />\n ) : null}\n\n <XAxis\n dataKey={xKey}\n tickLine={false}\n axisLine={false}\n tick={axisTick}\n tickMargin={8}\n minTickGap={16}\n tickFormatter={\n xTickFormat\n ? (value) => xTickFormat(value as string | number)\n : undefined\n }\n />\n <YAxis\n tickLine={false}\n axisLine={false}\n tick={axisTick}\n width={48}\n tickFormatter={(value) => valueFormat(Number(value))}\n />\n\n <Tooltip\n cursor={{ stroke: chartTokens.axis, strokeWidth: 1 }}\n content={\n <ChartTooltip\n valueFormat={valueFormat}\n labelFormat={xTickFormat}\n hideLabel={false}\n />\n }\n />\n\n {withLegend ? <Legend content={<ChartLegend />} /> : null}\n\n {resolved.map((s, index) =>\n type === \"area\" ? (\n <Area\n key={s.key}\n type=\"monotone\"\n dataKey={s.key}\n name={s.label}\n stroke={s.color}\n strokeWidth={2}\n fill={`url(#${gradientBase}-${index})`}\n isAnimationActive={!reducedMotion}\n dot={false}\n activeDot={{\n r: 4,\n strokeWidth: 2,\n stroke: chartTokens.surface,\n fill: s.color,\n }}\n />\n ) : (\n <Line\n key={s.key}\n type=\"monotone\"\n dataKey={s.key}\n name={s.label}\n stroke={s.color}\n strokeWidth={2}\n isAnimationActive={!reducedMotion}\n dot={false}\n activeDot={{\n r: 4,\n strokeWidth: 2,\n stroke: chartTokens.surface,\n fill: s.color,\n }}\n />\n ),\n )}\n\n {showEndDots\n ? resolved.map((s) => {\n const index = lastFiniteIndex(s.key);\n if (index < 0) return null;\n return (\n <ReferenceDot\n key={`end-${s.key}`}\n x={data[index][xKey] as string | number}\n y={data[index][s.key] as number}\n r={4}\n fill={s.color}\n stroke={chartTokens.surface}\n strokeWidth={2}\n isFront\n />\n );\n })\n : null}\n </Chart>\n </ResponsiveContainer>\n </ChartFigure>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"TrendChart.js","names":[],"sources":["../../../../src/timecampus/components/charts/TrendChart.tsx"],"sourcesContent":["import { useId } from \"react\";\nimport {\n Area,\n AreaChart,\n CartesianGrid,\n Legend,\n Line,\n LineChart,\n ReferenceDot,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport {\n chartTokens,\n defaultSeriesColor,\n formatNumber,\n usePrefersReducedMotion,\n type ChartDatum,\n type ChartSeries,\n type ValueFormatter,\n} from \"./chartTheme\";\nimport {\n ChartDataTable,\n ChartEmpty,\n ChartFigure,\n ChartLegend,\n ChartTooltip,\n} from \"./ChartParts\";\n\nexport interface TrendChartProps {\n /** Rows of `{ [xKey]: label, [series.key]: number }`. */\n data: ChartDatum[];\n /** Field holding the x-axis category/time value. */\n xKey: string;\n /** One or more numeric series. Single series reads on-brand. */\n series: ChartSeries[];\n /** Line, or gradient-filled area. Default `area`. */\n type?: \"line\" | \"area\";\n /** Pixel height of the plot. Default 260. */\n height?: number;\n /** Formats y values in the axis and tooltip. Default grouped integer. */\n valueFormat?: ValueFormatter;\n /** Formats x tick + tooltip header. */\n xTickFormat?: (value: string | number) => string;\n /** Show the horizontal grid. Default true. */\n showGrid?: boolean;\n /** Force the legend on/off. Default: on when there are ≥ 2 series. */\n showLegend?: boolean;\n /** Emphasise each series' final point with a ringed dot. Default true. */\n showEndDots?: boolean;\n /** Message shown when `data` is empty — never fabricate a shape. */\n emptyLabel?: string;\n /** Accessible name for the figure. Default derived from the series labels. */\n ariaLabel?: string;\n className?: string;\n}\n\n/**\n * TrendChart — value-over-time as a line or gradient area (asset value,\n * emissions, depreciation). Theme-aware tokens, a hairline grid, a crosshair\n * tooltip, emphasised endpoints, a legend for multi-series, an empty state and\n * a screen-reader data table. Respects `prefers-reduced-motion`.\n */\nexport function TrendChart({\n data,\n xKey,\n series,\n type = \"area\",\n height = 260,\n valueFormat = formatNumber,\n xTickFormat,\n showGrid = true,\n showLegend,\n showEndDots = true,\n emptyLabel,\n ariaLabel,\n className,\n}: TrendChartProps) {\n const gradientBase = useId();\n const reducedMotion = usePrefersReducedMotion();\n\n const resolved = series.map((s, index) => ({\n ...s,\n label: s.label ?? s.key,\n color: s.color ?? defaultSeriesColor(index, series.length),\n }));\n const label =\n ariaLabel ?? `Trend of ${resolved.map((s) => s.label).join(\", \")}`;\n\n if (data.length === 0) {\n return (\n <ChartEmpty height={height} label={emptyLabel} className={className} />\n );\n }\n\n const withLegend = showLegend ?? resolved.length > 1;\n const axisTick = { fill: chartTokens.textMuted, fontSize: 12 };\n\n const lastFiniteIndex = (key: string): number => {\n for (let i = data.length - 1; i >= 0; i -= 1) {\n const value = data[i][key];\n if (typeof value === \"number\" && Number.isFinite(value)) return i;\n }\n return -1;\n };\n\n const Chart = type === \"area\" ? AreaChart : LineChart;\n\n return (\n <ChartFigure\n ariaLabel={label}\n height={height}\n className={className}\n a11y={\n <ChartDataTable\n caption={label}\n xLabel={xKey}\n xKey={xKey}\n data={data}\n series={resolved}\n valueFormat={valueFormat}\n />\n }\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <Chart data={data} margin={{ top: 12, right: 16, bottom: 4, left: 4 }}>\n <defs>\n {resolved.map((s, index) => (\n <linearGradient\n key={s.key}\n id={`${gradientBase}-${index}`}\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\"\n >\n <stop offset=\"0%\" stopColor={s.color} stopOpacity={0.24} />\n <stop offset=\"95%\" stopColor={s.color} stopOpacity={0.02} />\n </linearGradient>\n ))}\n </defs>\n\n {showGrid ? (\n <CartesianGrid\n vertical={false}\n stroke={chartTokens.grid}\n strokeWidth={1}\n />\n ) : null}\n\n <XAxis\n dataKey={xKey}\n tickLine={false}\n axisLine={false}\n tick={axisTick}\n tickMargin={8}\n minTickGap={16}\n tickFormatter={\n xTickFormat\n ? (value) => xTickFormat(value as string | number)\n : undefined\n }\n />\n <YAxis\n tickLine={false}\n axisLine={false}\n tick={axisTick}\n width={48}\n tickFormatter={(value) => valueFormat(Number(value))}\n />\n\n <Tooltip\n cursor={{ stroke: chartTokens.axis, strokeWidth: 1 }}\n content={\n <ChartTooltip\n valueFormat={valueFormat}\n labelFormat={xTickFormat}\n hideLabel={false}\n />\n }\n />\n\n {withLegend ? <Legend content={<ChartLegend />} /> : null}\n\n {resolved.map((s, index) =>\n type === \"area\" ? (\n <Area\n key={s.key}\n type=\"monotone\"\n dataKey={s.key}\n name={s.label}\n stroke={s.color}\n strokeWidth={2}\n fill={`url(#${gradientBase}-${index})`}\n isAnimationActive={!reducedMotion}\n dot={false}\n activeDot={{\n r: 4,\n strokeWidth: 2,\n stroke: chartTokens.surface,\n fill: s.color,\n }}\n />\n ) : (\n <Line\n key={s.key}\n type=\"monotone\"\n dataKey={s.key}\n name={s.label}\n stroke={s.color}\n strokeWidth={2}\n isAnimationActive={!reducedMotion}\n dot={false}\n activeDot={{\n r: 4,\n strokeWidth: 2,\n stroke: chartTokens.surface,\n fill: s.color,\n }}\n />\n ),\n )}\n\n {showEndDots\n ? resolved.map((s) => {\n const index = lastFiniteIndex(s.key);\n if (index < 0) return null;\n return (\n <ReferenceDot\n key={`end-${s.key}`}\n x={data[index][xKey] as string | number}\n y={data[index][s.key] as number}\n r={4}\n fill={s.color}\n stroke={chartTokens.surface}\n strokeWidth={2}\n isFront\n />\n );\n })\n : null}\n </Chart>\n </ResponsiveContainer>\n </ChartFigure>\n );\n}\n"],"mappings":";;;;;;AAiEA,SAAgB,EAAW,EACzB,SACA,SACA,WACA,UAAO,QACP,YAAS,KACT,iBAAc,GACd,gBACA,cAAW,IACX,eACA,iBAAc,IACd,eACA,cACA,gBACkB;CAClB,IAAM,IAAe,GAAO,EACtB,IAAgB,GAAyB,EAEzC,IAAW,EAAO,KAAK,GAAG,OAAW;EACzC,GAAG;EACH,OAAO,EAAE,SAAS,EAAE;EACpB,OAAO,EAAE,SAAS,EAAmB,GAAO,EAAO,OAAO;EAC3D,EAAE,EACG,IACJ,KAAa,YAAY,EAAS,KAAK,MAAM,EAAE,MAAM,CAAC,KAAK,KAAK;AAElE,KAAI,EAAK,WAAW,EAClB,QACE,kBAAC,GAAD;EAAoB;EAAQ,OAAO;EAAuB;EAAa,CAAA;CAI3E,IAAM,IAAa,KAAc,EAAS,SAAS,GAC7C,IAAW;EAAE,MAAM,EAAY;EAAW,UAAU;EAAI,EAExD,KAAmB,MAAwB;AAC/C,OAAK,IAAI,IAAI,EAAK,SAAS,GAAG,KAAK,GAAG,KAAQ;GAC5C,IAAM,IAAQ,EAAK,GAAG;AACtB,OAAI,OAAO,KAAU,YAAY,OAAO,SAAS,EAAM,CAAE,QAAO;;AAElE,SAAO;;AAKT,QACE,kBAAC,GAAD;EACE,WAAW;EACH;EACG;EACX,MACE,kBAAC,GAAD;GACE,SAAS;GACT,QAAQ;GACF;GACA;GACN,QAAQ;GACK;GACb,CAAA;YAGJ,kBAAC,GAAD;GAAqB,OAAM;GAAO,QAAO;aACvC,kBAnBQ,MAAS,SAAS,IAAY,GAmBtC;IAAa;IAAM,QAAQ;KAAE,KAAK;KAAI,OAAO;KAAI,QAAQ;KAAG,MAAM;KAAG;cAArE;KACE,kBAAC,QAAD,EAAA,UACG,EAAS,KAAK,GAAG,MAChB,kBAAC,kBAAD;MAEE,IAAI,GAAG,EAAa,GAAG;MACvB,IAAG;MACH,IAAG;MACH,IAAG;MACH,IAAG;gBANL,CAQE,kBAAC,QAAD;OAAM,QAAO;OAAK,WAAW,EAAE;OAAO,aAAa;OAAQ,CAAA,EAC3D,kBAAC,QAAD;OAAM,QAAO;OAAM,WAAW,EAAE;OAAO,aAAa;OAAQ,CAAA,CAC7C;QATV,EAAE,IASQ,CACjB,EACG,CAAA;KAEN,IACC,kBAAC,GAAD;MACE,UAAU;MACV,QAAQ,EAAY;MACpB,aAAa;MACb,CAAA,GACA;KAEJ,kBAAC,GAAD;MACE,SAAS;MACT,UAAU;MACV,UAAU;MACV,MAAM;MACN,YAAY;MACZ,YAAY;MACZ,eACE,KACK,MAAU,EAAY,EAAyB,GAChD,KAAA;MAEN,CAAA;KACF,kBAAC,GAAD;MACE,UAAU;MACV,UAAU;MACV,MAAM;MACN,OAAO;MACP,gBAAgB,MAAU,EAAY,OAAO,EAAM,CAAC;MACpD,CAAA;KAEF,kBAAC,GAAD;MACE,QAAQ;OAAE,QAAQ,EAAY;OAAM,aAAa;OAAG;MACpD,SACE,kBAAC,GAAD;OACe;OACb,aAAa;OACb,WAAW;OACX,CAAA;MAEJ,CAAA;KAED,IAAa,kBAAC,GAAD,EAAQ,SAAS,kBAAC,GAAD,EAAe,CAAA,EAAI,CAAA,GAAG;KAEpD,EAAS,KAAK,GAAG,MAChB,MAAS,SACP,kBAAC,GAAD;MAEE,MAAK;MACL,SAAS,EAAE;MACX,MAAM,EAAE;MACR,QAAQ,EAAE;MACV,aAAa;MACb,MAAM,QAAQ,EAAa,GAAG,EAAM;MACpC,mBAAmB,CAAC;MACpB,KAAK;MACL,WAAW;OACT,GAAG;OACH,aAAa;OACb,QAAQ,EAAY;OACpB,MAAM,EAAE;OACT;MACD,EAfK,EAAE,IAeP,GAEF,kBAAC,GAAD;MAEE,MAAK;MACL,SAAS,EAAE;MACX,MAAM,EAAE;MACR,QAAQ,EAAE;MACV,aAAa;MACb,mBAAmB,CAAC;MACpB,KAAK;MACL,WAAW;OACT,GAAG;OACH,aAAa;OACb,QAAQ,EAAY;OACpB,MAAM,EAAE;OACT;MACD,EAdK,EAAE,IAcP,CAEL;KAEA,IACG,EAAS,KAAK,MAAM;MAClB,IAAM,IAAQ,EAAgB,EAAE,IAAI;AAEpC,aADI,IAAQ,IAAU,OAEpB,kBAAC,GAAD;OAEE,GAAG,EAAK,GAAO;OACf,GAAG,EAAK,GAAO,EAAE;OACjB,GAAG;OACH,MAAM,EAAE;OACR,QAAQ,EAAY;OACpB,aAAa;OACb,SAAA;OACA,EARK,OAAO,EAAE,MAQd;OAEJ,GACF;KACE;;GACY,CAAA;EACV,CAAA"}
|
|
@@ -6,5 +6,6 @@ export { TimeCampusRoot } from './TimeCampusRoot';
|
|
|
6
6
|
export type { TimeCampusRootProps, NavItem, FooterItem } from './types';
|
|
7
7
|
export { useTimeCampus, useTimeCampusNavigate, } from './providers/TimeCampusProvider';
|
|
8
8
|
export { useTimeCampusStore } from './store/timecampusStore';
|
|
9
|
+
export * from '../services/createSandboxAssistantTransport';
|
|
9
10
|
export * from '../generated/wspace-operations';
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/timecampus/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD,YAAY,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGxE,OAAO,EACL,aAAa,EACb,qBAAqB,GACtB,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/timecampus/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD,YAAY,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGxE,OAAO,EACL,aAAa,EACb,qBAAqB,GACtB,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAO7D,cAAc,6CAA6C,CAAC;AAG5D,cAAc,gCAAgC,CAAC"}
|
package/dist/timecampus/index.js
CHANGED
|
@@ -18,9 +18,9 @@ import { Check as pe, DollarSign as me, ExternalLink as he, MessageSquare as ge,
|
|
|
18
18
|
import { gql as f } from "@apollo/client";
|
|
19
19
|
import { useApolloClient as Ce } from "@apollo/client/react";
|
|
20
20
|
import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
21
|
+
import { useRegisterPageConversationContext as g } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
21
22
|
import { uploadBlobToFiles as we } from "@burdenoff/fe-libs/storage";
|
|
22
|
-
import { ContextConversationWidget as
|
|
23
|
-
import { useRegisterPageConversationContext as _ } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
23
|
+
import { ContextConversationWidget as _ } from "@burdenoff/fe-libs/shared";
|
|
24
24
|
//#region src/timecampus/pages/expense-tracking/ExpenseTrackingPage.tsx
|
|
25
25
|
var v = 25, y = [
|
|
26
26
|
"Travel",
|
|
@@ -42,11 +42,11 @@ var v = 25, y = [
|
|
|
42
42
|
}
|
|
43
43
|
`, De = 604800;
|
|
44
44
|
function Oe({ expense: e }) {
|
|
45
|
-
return
|
|
45
|
+
return g({
|
|
46
46
|
entityType: "TIMECAMPUS_EXPENSE",
|
|
47
47
|
entityId: e.id,
|
|
48
48
|
contextTitle: `Expense · ${e.description ?? e.id}`
|
|
49
|
-
}), /* @__PURE__ */ m(
|
|
49
|
+
}), /* @__PURE__ */ m(_, { widgetKey: "expense-review" });
|
|
50
50
|
}
|
|
51
51
|
function x() {
|
|
52
52
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -16,16 +16,16 @@ import { useState as d } from "react";
|
|
|
16
16
|
import { CheckCircle as f, Clock as p, MessageSquare as de, MessagesSquare as m, Undo2 as h, X as fe, XCircle as g } from "lucide-react";
|
|
17
17
|
import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
18
18
|
import { GlassCard as b } from "@burdenoff/fe-libs/ui";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
19
|
+
import { useRegisterPageConversationContext as x } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
20
|
+
import { ContextConversationWidget as S } from "@burdenoff/fe-libs/shared";
|
|
21
21
|
//#region src/timecampus/pages/time-approval/TimeApprovalPage.tsx
|
|
22
22
|
var C = 25;
|
|
23
23
|
function w({ request: e }) {
|
|
24
|
-
return
|
|
24
|
+
return x({
|
|
25
25
|
entityType: "TIMECAMPUS_APPROVAL_REQUEST",
|
|
26
26
|
entityId: e.id,
|
|
27
27
|
contextTitle: `Approval · ${e.period ?? e.id}`
|
|
28
|
-
}), /* @__PURE__ */ v(
|
|
28
|
+
}), /* @__PURE__ */ v(S, { widgetKey: "approval-review" });
|
|
29
29
|
}
|
|
30
30
|
var T = "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary";
|
|
31
31
|
function E() {
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { createContext as e, useCallback as t, useContext as n, useMemo as r } from "react";
|
|
2
|
+
import { MemoryRouter as i, useNavigate as a } from "react-router-dom";
|
|
3
|
+
import { ApolloClient as o, HttpLink as s, InMemoryCache as c, from as l } from "@apollo/client";
|
|
4
|
+
import { onError as u } from "@apollo/client/link/error";
|
|
5
|
+
import { CombinedGraphQLErrors as d } from "@apollo/client/errors";
|
|
6
6
|
import { setContext as f } from "@apollo/client/link/context";
|
|
7
7
|
import { ApolloProvider as p } from "@apollo/client/react";
|
|
8
8
|
import { jsx as m } from "react/jsx-runtime";
|
|
9
9
|
//#region src/timecampus/providers/TimeCampusProvider.tsx
|
|
10
|
-
var h =
|
|
11
|
-
let e =
|
|
10
|
+
var h = e(null), g = () => {
|
|
11
|
+
let e = n(h);
|
|
12
12
|
if (!e) throw Error("useTimeCampus must be used within TimeCampusProvider");
|
|
13
13
|
return e;
|
|
14
14
|
}, _ = () => {
|
|
15
|
-
let { navigate: e, basePath:
|
|
16
|
-
return
|
|
17
|
-
let i =
|
|
15
|
+
let { navigate: e, basePath: n } = g(), r = a();
|
|
16
|
+
return t((t) => {
|
|
17
|
+
let i = n && n !== "/" ? `${n}${t}` : t;
|
|
18
18
|
e ? e(i) : r(i);
|
|
19
19
|
}, [
|
|
20
20
|
e,
|
|
21
|
-
|
|
21
|
+
n,
|
|
22
22
|
r
|
|
23
23
|
]);
|
|
24
|
-
}, v = ({ children:
|
|
25
|
-
let w =
|
|
26
|
-
link:
|
|
27
|
-
|
|
28
|
-
if (
|
|
29
|
-
let
|
|
30
|
-
if (
|
|
24
|
+
}, v = ({ children: e, basePath: t, navigate: n, currentUser: a, workspaceId: g, tenantId: _, apiGatewayUrl: v, authToken: y, workspaceToken: b, registerNavItems: x, registerFooterItems: S, onAuthError: C }) => {
|
|
25
|
+
let w = r(() => new o({
|
|
26
|
+
link: l([
|
|
27
|
+
u(({ error: e }) => {
|
|
28
|
+
if (d.is(e)) for (let t of e.errors) {
|
|
29
|
+
let e = t.extensions?.code;
|
|
30
|
+
if (e === "UNAUTHENTICATED" || e === "FORBIDDEN") {
|
|
31
31
|
console.warn("[TimeCampus] Auth error detected — notifying host shell"), C?.();
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
else if (
|
|
36
|
-
let
|
|
37
|
-
(
|
|
35
|
+
else if (e) {
|
|
36
|
+
let t = e.message ?? "";
|
|
37
|
+
(t.includes("401") || t.includes("403") || t.includes("Unauthorized")) && (console.warn("[TimeCampus] Auth network error — notifying host shell"), C?.());
|
|
38
38
|
}
|
|
39
39
|
}),
|
|
40
40
|
f((e, { headers: t }) => ({ headers: {
|
|
@@ -43,12 +43,12 @@ var h = t(null), g = () => {
|
|
|
43
43
|
...b ? { "X-Workspace-Authorization": `Bearer ${b}` } : {},
|
|
44
44
|
...g ? { "x-workspace-id": g } : {},
|
|
45
45
|
..._ ? { "x-tenant-id": _ } : {},
|
|
46
|
-
...
|
|
47
|
-
...
|
|
46
|
+
...a?.id ? { "x-actor-id": a.id } : {},
|
|
47
|
+
...a?.id ? { "x-actor-type": "user" } : {}
|
|
48
48
|
} })),
|
|
49
|
-
new
|
|
49
|
+
new s({ uri: v ? v.endsWith("/graphql") ? v : `${v}/workspaces/graphql` : "/workspaces/graphql" })
|
|
50
50
|
]),
|
|
51
|
-
cache: new
|
|
51
|
+
cache: new c(),
|
|
52
52
|
defaultOptions: {
|
|
53
53
|
watchQuery: {
|
|
54
54
|
fetchPolicy: "cache-and-network",
|
|
@@ -61,14 +61,14 @@ var h = t(null), g = () => {
|
|
|
61
61
|
v,
|
|
62
62
|
y,
|
|
63
63
|
b,
|
|
64
|
-
|
|
64
|
+
a?.id,
|
|
65
65
|
C,
|
|
66
66
|
_,
|
|
67
67
|
g
|
|
68
68
|
]), T = {
|
|
69
|
-
basePath:
|
|
70
|
-
navigate:
|
|
71
|
-
currentUser:
|
|
69
|
+
basePath: t,
|
|
70
|
+
navigate: n,
|
|
71
|
+
currentUser: a,
|
|
72
72
|
workspaceId: g,
|
|
73
73
|
tenantId: _,
|
|
74
74
|
apiGatewayUrl: v,
|
|
@@ -77,13 +77,13 @@ var h = t(null), g = () => {
|
|
|
77
77
|
registerNavItems: x,
|
|
78
78
|
registerFooterItems: S,
|
|
79
79
|
onAuthError: C
|
|
80
|
-
}, E = !!
|
|
80
|
+
}, E = !!t, D = /* @__PURE__ */ m(h.Provider, {
|
|
81
81
|
value: T,
|
|
82
|
-
children:
|
|
82
|
+
children: e
|
|
83
83
|
});
|
|
84
84
|
return E ? D : /* @__PURE__ */ m(p, {
|
|
85
85
|
client: w,
|
|
86
|
-
children: /* @__PURE__ */ m(
|
|
86
|
+
children: /* @__PURE__ */ m(i, { children: D })
|
|
87
87
|
});
|
|
88
88
|
};
|
|
89
89
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "
|
|
2
|
-
import { twMerge as t } from "
|
|
1
|
+
import { clsx as e } from "clsx";
|
|
2
|
+
import { twMerge as t } from "tailwind-merge";
|
|
3
3
|
//#region src/timecampus/utils/helpers.ts
|
|
4
4
|
function n(...n) {
|
|
5
5
|
return t(e(n));
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/utils/pageContext.ts
|
|
2
|
+
function e() {
|
|
3
|
+
let e = window.location.href, t = window.location.pathname.split("/").filter(Boolean).slice(0, 3).join("/") || "home", r = n(window.location.pathname, window.location.search);
|
|
4
|
+
return {
|
|
5
|
+
currentUrl: e,
|
|
6
|
+
currentPage: t,
|
|
7
|
+
entityType: r.entityType,
|
|
8
|
+
entityId: r.entityId,
|
|
9
|
+
platform: "timecampus",
|
|
10
|
+
version: "0.0.0-dev",
|
|
11
|
+
viewportSize: `${window.innerWidth}x${window.innerHeight}`,
|
|
12
|
+
userAgent: navigator.userAgent,
|
|
13
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function t(e, t) {
|
|
17
|
+
return t.match(e);
|
|
18
|
+
}
|
|
19
|
+
function n(e, n) {
|
|
20
|
+
let r = new URLSearchParams(n);
|
|
21
|
+
for (let [n, r] of [
|
|
22
|
+
[/^\/?timecampus\/time\/projects\/([^/]+)$/, "TIMECAMPUS_PROJECT"],
|
|
23
|
+
[/^\/?timecampus\/time\/tasks\/([^/]+)$/, "TIMECAMPUS_TASK"],
|
|
24
|
+
[/^\/?timecampus\/meetings\/([^/]+)$/, "TIMECAMPUS_MEETING"],
|
|
25
|
+
[/^\/?timecampus\/pomodoro\/sessions\/([^/]+)$/, "TIMECAMPUS_POMODORO_SESSION"],
|
|
26
|
+
[/^\/?timecampus\/lifetime\/goals\/([^/]+)$/, "TIMECAMPUS_LIFE_GOAL"],
|
|
27
|
+
[/^\/?timecampus\/resource-planning\/plans\/([^/]+)$/, "TIMECAMPUS_RESOURCE_PLAN"]
|
|
28
|
+
]) {
|
|
29
|
+
let i = t(n, e);
|
|
30
|
+
if (i) return {
|
|
31
|
+
entityType: r,
|
|
32
|
+
entityId: i[1],
|
|
33
|
+
metadata: { routePattern: n.source }
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
let i = r.get("tab") ?? (() => {
|
|
37
|
+
let t = e.split("/").filter(Boolean);
|
|
38
|
+
return t.length > 2 ? t[t.length - 1] : void 0;
|
|
39
|
+
})();
|
|
40
|
+
return {
|
|
41
|
+
activeTab: i ?? void 0,
|
|
42
|
+
metadata: {
|
|
43
|
+
...i ? { activeTab: i } : {},
|
|
44
|
+
...r.get("projectId") ? { projectId: r.get("projectId") } : {},
|
|
45
|
+
...r.get("date") ? { date: r.get("date") } : {}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { e as gatherPageContext };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=pageContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageContext.js","names":[],"sources":["../../src/utils/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering — captures the user's current browser context\n * to be sent alongside every assistant prompt for better AI awareness.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n currentUrl: string;\n currentPage: string;\n entityType?: string;\n entityId?: string;\n platform: string;\n version: string;\n viewportSize: string;\n userAgent: string;\n timestamp: string;\n}\n\nexport function gatherPageContext(): PageContext {\n const url = window.location.href;\n const pathSegments = window.location.pathname.split(\"/\").filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join(\"/\") || \"home\";\n const entity = resolveTimeCampusConversationContext(\n window.location.pathname,\n window.location.search,\n );\n\n return {\n currentUrl: url,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n platform: \"timecampus\",\n version: import.meta.env.VITE_APP_VERSION ?? \"0.0.0-dev\",\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction matchPath(pattern: RegExp, pathname: string): RegExpMatchArray | null {\n return pathname.match(pattern);\n}\n\nexport function resolveTimeCampusConversationContext(\n pathname: string,\n search: string,\n): ConversationContextShape {\n const params = new URLSearchParams(search);\n\n const directMatches: Array<[RegExp, string]> = [\n [/^\\/?timecampus\\/time\\/projects\\/([^/]+)$/, \"TIMECAMPUS_PROJECT\"],\n [/^\\/?timecampus\\/time\\/tasks\\/([^/]+)$/, \"TIMECAMPUS_TASK\"],\n [/^\\/?timecampus\\/meetings\\/([^/]+)$/, \"TIMECAMPUS_MEETING\"],\n [\n /^\\/?timecampus\\/pomodoro\\/sessions\\/([^/]+)$/,\n \"TIMECAMPUS_POMODORO_SESSION\",\n ],\n [/^\\/?timecampus\\/lifetime\\/goals\\/([^/]+)$/, \"TIMECAMPUS_LIFE_GOAL\"],\n [\n /^\\/?timecampus\\/resource-planning\\/plans\\/([^/]+)$/,\n \"TIMECAMPUS_RESOURCE_PLAN\",\n ],\n ];\n\n for (const [pattern, entityType] of directMatches) {\n const match = matchPath(pattern, pathname);\n if (match) {\n return {\n entityType,\n entityId: match[1],\n metadata: { routePattern: pattern.source },\n };\n }\n }\n\n const activeTab =\n params.get(\"tab\") ??\n (() => {\n const segments = pathname.split(\"/\").filter(Boolean);\n return segments.length > 2 ? segments[segments.length - 1] : undefined;\n })();\n\n return {\n activeTab: activeTab ?? undefined,\n metadata: {\n ...(activeTab ? { activeTab } : {}),\n ...(params.get(\"projectId\")\n ? { projectId: params.get(\"projectId\") }\n : {}),\n ...(params.get(\"date\") ? { date: params.get(\"date\") } : {}),\n },\n };\n}\n"],"mappings":";AAwBA,SAAgB,IAAiC;CAC/C,IAAM,IAAM,OAAO,SAAS,MAEtB,IADe,OAAO,SAAS,SAAS,MAAM,IAAI,CAAC,OAAO,QAAQ,CACvC,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,IAAI,QACpD,IAAS,EACb,OAAO,SAAS,UAChB,OAAO,SAAS,OACjB;AAED,QAAO;EACL,YAAY;EACZ;EACA,YAAY,EAAO;EACnB,UAAU,EAAO;EACjB,UAAU;EACV,SAA6C;EAC7C,cAAc,GAAG,OAAO,WAAW,GAAG,OAAO;EAC7C,WAAW,UAAU;EACrB,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC;;AAGH,SAAS,EAAU,GAAiB,GAA2C;AAC7E,QAAO,EAAS,MAAM,EAAQ;;AAGhC,SAAgB,EACd,GACA,GAC0B;CAC1B,IAAM,IAAS,IAAI,gBAAgB,EAAO;AAiB1C,MAAK,IAAM,CAAC,GAAS,MAf0B;EAC7C,CAAC,4CAA4C,qBAAqB;EAClE,CAAC,yCAAyC,kBAAkB;EAC5D,CAAC,sCAAsC,qBAAqB;EAC5D,CACE,gDACA,8BACD;EACD,CAAC,6CAA6C,uBAAuB;EACrE,CACE,sDACA,2BACD;EACF,EAEkD;EACjD,IAAM,IAAQ,EAAU,GAAS,EAAS;AAC1C,MAAI,EACF,QAAO;GACL;GACA,UAAU,EAAM;GAChB,UAAU,EAAE,cAAc,EAAQ,QAAQ;GAC3C;;CAIL,IAAM,IACJ,EAAO,IAAI,MAAM,WACV;EACL,IAAM,IAAW,EAAS,MAAM,IAAI,CAAC,OAAO,QAAQ;AACpD,SAAO,EAAS,SAAS,IAAI,EAAS,EAAS,SAAS,KAAK,KAAA;KAC3D;AAEN,QAAO;EACL,WAAW,KAAa,KAAA;EACxB,UAAU;GACR,GAAI,IAAY,EAAE,cAAW,GAAG,EAAE;GAClC,GAAI,EAAO,IAAI,YAAY,GACvB,EAAE,WAAW,EAAO,IAAI,YAAY,EAAE,GACtC,EAAE;GACN,GAAI,EAAO,IAAI,OAAO,GAAG,EAAE,MAAM,EAAO,IAAI,OAAO,EAAE,GAAG,EAAE;GAC3D;EACF"}
|
package/package.json
CHANGED