@liiift-studio/sanity-visitor-insights 0.69.0 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +140 -115
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +140 -115
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/src/studio/CrossSourceTimeline.tsx +15 -11
- package/src/studio/Figure.tsx +43 -20
- package/src/studio/VisitorInsightsTool.tsx +15 -5
- package/src/studio/palette.test.ts +36 -1
- package/src/studio/palette.ts +36 -0
- package/src/studio/panels.test.tsx +19 -4
- package/src/studio/panels.tsx +11 -32
package/dist/index.js
CHANGED
|
@@ -290,6 +290,15 @@ function withAlpha(hex, alpha) {
|
|
|
290
290
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
291
291
|
}
|
|
292
292
|
var COMPARISON = "#8368D4";
|
|
293
|
+
var COMPARISON_TEXT = `var(--vi-comparison, ${COMPARISON})`;
|
|
294
|
+
var COMPARISON_ON_LIGHT = "#6A4FC4";
|
|
295
|
+
var COMPARISON_ON_DARK = "#A594E8";
|
|
296
|
+
var COMPARISON_STYLE = `
|
|
297
|
+
:root { --vi-comparison: ${COMPARISON}; }
|
|
298
|
+
@supports (color: light-dark(#000, #fff)) {
|
|
299
|
+
:root { --vi-comparison: light-dark(${COMPARISON_ON_LIGHT}, ${COMPARISON_ON_DARK}); }
|
|
300
|
+
}
|
|
301
|
+
`.trim();
|
|
293
302
|
var MARKS = {
|
|
294
303
|
"chart.line": { key: "vercel", alpha: 1, role: "data", note: "A source series in the timeline" },
|
|
295
304
|
"chart.lossyLine": { key: "ga4Pageviews", alpha: 1, role: "data", note: "The lossier source, dashed" },
|
|
@@ -455,11 +464,11 @@ function deltaStyle() {
|
|
|
455
464
|
fontFamily: "inherit",
|
|
456
465
|
fontSize: "0.8em",
|
|
457
466
|
fontWeight: 500,
|
|
458
|
-
color:
|
|
467
|
+
color: COMPARISON_TEXT,
|
|
459
468
|
whiteSpace: "nowrap"
|
|
460
469
|
};
|
|
461
470
|
}
|
|
462
|
-
var baselineStyle = { color:
|
|
471
|
+
var baselineStyle = { color: COMPARISON_TEXT, fontWeight: 400 };
|
|
463
472
|
var HOVER_GUTTER = 14;
|
|
464
473
|
var HOVER_CARD_MAX = 260;
|
|
465
474
|
function HoverCard({
|
|
@@ -701,7 +710,7 @@ function FunnelChart({ stages, measurement }) {
|
|
|
701
710
|
const active = activeKey === stage.key;
|
|
702
711
|
const delta = previous ? previous.value - stage.value : 0;
|
|
703
712
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: funnelItem, children: [
|
|
704
|
-
previous && gapLabel(delta, measurement, entry) !== "" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: funnelGapStyle(measurement === "sequence"), children: [
|
|
713
|
+
previous && gapLabel(delta, measurement, entry) !== "" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: funnelGapStyle(measurement === "sequence" && delta > 0 && entry > 0), children: [
|
|
705
714
|
measurement === "sequence" && delta > 0 && entry > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "aria-hidden": "true", style: { ...barTrack, height: 6, flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
706
715
|
"div",
|
|
707
716
|
{
|
|
@@ -1002,6 +1011,7 @@ function SurvivalLines({
|
|
|
1002
1011
|
minDenominator = MIN_RATE_DENOMINATOR
|
|
1003
1012
|
}) {
|
|
1004
1013
|
const [active, setActive] = import_react2.default.useState(null);
|
|
1014
|
+
const [steppedByKey, setSteppedByKey] = import_react2.default.useState(false);
|
|
1005
1015
|
if (segments.length < 2 || stepLabels.length < 2) return null;
|
|
1006
1016
|
const width = 320;
|
|
1007
1017
|
const height = 132;
|
|
@@ -1112,18 +1122,23 @@ function SurvivalLines({
|
|
|
1112
1122
|
"button",
|
|
1113
1123
|
{
|
|
1114
1124
|
type: "button",
|
|
1115
|
-
style: survivalTick(i === active),
|
|
1125
|
+
style: survivalTick(i === active, i, stepLabels.length),
|
|
1116
1126
|
"aria-pressed": i === active,
|
|
1117
|
-
onMouseEnter: () =>
|
|
1127
|
+
onMouseEnter: () => {
|
|
1128
|
+
setSteppedByKey(false);
|
|
1129
|
+
setActive(i);
|
|
1130
|
+
},
|
|
1118
1131
|
onMouseLeave: () => setActive(null),
|
|
1119
|
-
onFocus: () =>
|
|
1132
|
+
onFocus: () => {
|
|
1133
|
+
setSteppedByKey(true);
|
|
1134
|
+
setActive(i);
|
|
1135
|
+
},
|
|
1120
1136
|
onBlur: () => setActive(null),
|
|
1121
|
-
onClick: () => setActive(i === active ? null : i),
|
|
1122
1137
|
children: label
|
|
1123
1138
|
},
|
|
1124
1139
|
label
|
|
1125
1140
|
)) }),
|
|
1126
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: survivalLegend, "aria-live": "polite", children: lines.map(({ segment, shares, colour }) => {
|
|
1141
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: survivalLegend, "aria-live": steppedByKey ? "polite" : "off", children: lines.map(({ segment, shares, colour }) => {
|
|
1127
1142
|
const share = active === null ? null : shares[active];
|
|
1128
1143
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_sanity_ui_compat.Text, { size: 0, children: [
|
|
1129
1144
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...hoverSwatch, background: colour, display: "inline-block", marginRight: 6 } }),
|
|
@@ -1457,13 +1472,18 @@ var shiftNow = {
|
|
|
1457
1472
|
var survivalLegend = { display: "flex", gap: 14, flexWrap: "wrap" };
|
|
1458
1473
|
var survivalFrame = { paddingLeft: 34, position: "relative" };
|
|
1459
1474
|
var survivalAxis = {
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1475
|
+
position: "relative",
|
|
1476
|
+
// Reserves the row's height, since the ticks inside it are positioned.
|
|
1477
|
+
height: 30,
|
|
1478
|
+
marginLeft: 34
|
|
1464
1479
|
};
|
|
1465
|
-
function survivalTick(activeTick) {
|
|
1480
|
+
function survivalTick(activeTick, index, count) {
|
|
1481
|
+
const at = count > 1 ? index / (count - 1) * 100 : 50;
|
|
1466
1482
|
return {
|
|
1483
|
+
position: "absolute",
|
|
1484
|
+
left: `${at}%`,
|
|
1485
|
+
// The ends align to the plot edge; everything between is centred on its vertex.
|
|
1486
|
+
transform: index === 0 ? "none" : index === count - 1 ? "translateX(-100%)" : "translateX(-50%)",
|
|
1467
1487
|
appearance: "none",
|
|
1468
1488
|
background: "transparent",
|
|
1469
1489
|
border: "none",
|
|
@@ -1473,11 +1493,10 @@ function survivalTick(activeTick) {
|
|
|
1473
1493
|
font: "inherit",
|
|
1474
1494
|
fontSize: "0.72em",
|
|
1475
1495
|
fontWeight: activeTick ? 600 : 400,
|
|
1476
|
-
padding: "6px
|
|
1496
|
+
padding: "6px 4px",
|
|
1477
1497
|
minHeight: 24,
|
|
1478
1498
|
cursor: "pointer",
|
|
1479
|
-
|
|
1480
|
-
flex: "1 1 0"
|
|
1499
|
+
whiteSpace: "nowrap"
|
|
1481
1500
|
};
|
|
1482
1501
|
}
|
|
1483
1502
|
function survivalYLabel(level) {
|
|
@@ -2206,7 +2225,7 @@ function CrossSourceTimeline({ series, markers = [], currency, onBrush }) {
|
|
|
2206
2225
|
}
|
|
2207
2226
|
)
|
|
2208
2227
|
] }),
|
|
2209
|
-
series.some((row) => row.comparison) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2228
|
+
series.some((row) => (row.comparison?.length ?? 0) > 1) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2210
2229
|
LegendKey,
|
|
2211
2230
|
{
|
|
2212
2231
|
swatch: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: legendDash(mark("chart.ghost")) }),
|
|
@@ -2216,7 +2235,7 @@ function CrossSourceTimeline({ series, markers = [], currency, onBrush }) {
|
|
|
2216
2235
|
markers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2217
2236
|
LegendKey,
|
|
2218
2237
|
{
|
|
2219
|
-
swatch: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style:
|
|
2238
|
+
swatch: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: legendMarker }),
|
|
2220
2239
|
label: "Dashed rules with a dot mark campaign sends"
|
|
2221
2240
|
}
|
|
2222
2241
|
),
|
|
@@ -2251,14 +2270,15 @@ function legendBlock(fill, edge) {
|
|
|
2251
2270
|
borderTop: `1.5px dashed ${edge}`
|
|
2252
2271
|
};
|
|
2253
2272
|
}
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2273
|
+
var legendMarker = {
|
|
2274
|
+
display: "inline-block",
|
|
2275
|
+
position: "relative",
|
|
2276
|
+
width: 0,
|
|
2277
|
+
height: 12,
|
|
2278
|
+
borderLeft: "1px dashed currentColor",
|
|
2279
|
+
opacity: 0.7,
|
|
2280
|
+
boxShadow: "-2px -6px 0 0 currentColor, -1px -6px 0 0 currentColor"
|
|
2281
|
+
};
|
|
2262
2282
|
function shortfallKey(series) {
|
|
2263
2283
|
const row = series.find((r) => r.shortfall);
|
|
2264
2284
|
return colorFor(row?.shortfall?.source ?? "GA4", row?.unit ?? "count", row?.shortfall?.color);
|
|
@@ -2394,7 +2414,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2394
2414
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: metricOr(data.vercelPageviews, OLDER_ROUTE), label: "Pageviews" }),
|
|
2395
2415
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Delta, { current: metricSortValue(data.vercelPageviews), previous: metricSortValue(previous?.vercelPageviews) })
|
|
2396
2416
|
] }),
|
|
2397
|
-
data.vercelPageviews?.status
|
|
2417
|
+
data.vercelPageviews?.status !== "unavailable" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "Pageviews, from Vercel\u2019s own counter." })
|
|
2398
2418
|
] }) }),
|
|
2399
2419
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Card, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 3, children: [
|
|
2400
2420
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Label, { size: 1, muted: true, children: "Mailing list, total" }),
|
|
@@ -2413,7 +2433,7 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2413
2433
|
] });
|
|
2414
2434
|
})()
|
|
2415
2435
|
] }),
|
|
2416
|
-
data.audience?.status
|
|
2436
|
+
data.audience?.status !== "unavailable" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "Everyone subscribed today, not just this period. Mailchimp\u2019s own count, so it is not consent-gated or blockable." })
|
|
2417
2437
|
] }) })
|
|
2418
2438
|
] }),
|
|
2419
2439
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: cardGrid, children: [
|
|
@@ -2448,12 +2468,12 @@ function OverviewPanel({ data, previous, onBrush }) {
|
|
|
2448
2468
|
unavailable: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetricFigure, { metric: visitorsPerOrder(data), label: "Visitors per order" })
|
|
2449
2469
|
}
|
|
2450
2470
|
),
|
|
2451
|
-
data.vercelVisitors?.status
|
|
2471
|
+
data.vercelVisitors?.status !== "unavailable" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 0, muted: true, children: "Vercel\u2019s visitor count. A ceiling \u2014 some are bots or the same person twice." })
|
|
2452
2472
|
] }) })
|
|
2453
2473
|
] }),
|
|
2454
2474
|
(data.crossSource?.length ?? 0) >= 3 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_sanity_ui_compat3.Stack, { space: 3, children: [
|
|
2455
2475
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionTitle, { title: "Everything, on one time axis" }),
|
|
2456
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "Each row has its own scale
|
|
2476
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sanity_ui_compat3.Text, { size: 1, muted: true, children: "Each row has its own scale, so the rows cannot be compared by height \u2014 only by shape." }),
|
|
2457
2477
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2458
2478
|
CrossSourceTimeline,
|
|
2459
2479
|
{
|
|
@@ -2760,7 +2780,6 @@ function Verdict({ data, previous }) {
|
|
|
2760
2780
|
say("Revenue", data.revenue, previous?.revenue, "money");
|
|
2761
2781
|
say("Orders", data.orders, previous?.orders, "count");
|
|
2762
2782
|
say("Traffic", data.vercelPageviews, previous?.vercelPageviews, "count");
|
|
2763
|
-
const sends = data.campaigns?.length ?? 0;
|
|
2764
2783
|
const shortfall = data.shortfallRatio;
|
|
2765
2784
|
const seeing = shortfall !== null && shortfall !== void 0 ? `GA4 is seeing ${formatPercent(1 - shortfall, 0)} of your traffic` : null;
|
|
2766
2785
|
const broken = shortfall === null || shortfall === void 0 ? data.capture?.discrepancy ? "measurement disagrees between sources" : null : shortfall > 0.6 ? `${seeing} \u2014 treat its figures as broken` : shortfall > 0.35 ? `${seeing} \u2014 its figures are undercounts, not what happened` : data.capture?.discrepancy ? "measurement disagrees between sources" : null;
|
|
@@ -3602,12 +3621,15 @@ function basisButton(selected) {
|
|
|
3602
3621
|
background: selected ? withAlpha(COMPARISON, 0.12) : "transparent",
|
|
3603
3622
|
border: `1px ${selected ? "solid" : "dashed"} ${selected ? COMPARISON : "var(--card-border-color, rgba(128,128,128,0.3))"}`,
|
|
3604
3623
|
borderRadius: 999,
|
|
3605
|
-
color: selected ?
|
|
3624
|
+
color: selected ? COMPARISON_TEXT : "inherit",
|
|
3606
3625
|
opacity: selected ? 1 : 0.7,
|
|
3607
3626
|
font: "inherit",
|
|
3608
3627
|
fontSize: "0.85em",
|
|
3609
3628
|
fontWeight: selected ? 600 : 400,
|
|
3610
3629
|
padding: "5px 12px",
|
|
3630
|
+
// Pinned rather than left to emerge from padding and root font size, which is how a target
|
|
3631
|
+
// silently drops under the 24px minimum when someone adjusts either.
|
|
3632
|
+
minHeight: 24,
|
|
3611
3633
|
cursor: "pointer",
|
|
3612
3634
|
whiteSpace: "nowrap"
|
|
3613
3635
|
};
|
|
@@ -3846,7 +3868,7 @@ function ReadyReport({
|
|
|
3846
3868
|
"These figures are the last ones that loaded. Refreshing them failed: ",
|
|
3847
3869
|
revalidationError
|
|
3848
3870
|
] }) }),
|
|
3849
|
-
envelope.comparison && COMPARED_TABS.includes(tabId) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.Text, { size: 0, style: { color:
|
|
3871
|
+
envelope.comparison && COMPARED_TABS.includes(tabId) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.Text, { size: 0, style: { color: COMPARISON_TEXT }, children: [
|
|
3850
3872
|
"Changes are against ",
|
|
3851
3873
|
envelope.comparison.range.start,
|
|
3852
3874
|
" to ",
|
|
@@ -3889,8 +3911,8 @@ function BasisSelector({
|
|
|
3889
3911
|
value,
|
|
3890
3912
|
onChange
|
|
3891
3913
|
}) {
|
|
3892
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: controlRow, role: "
|
|
3893
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sanity_ui_compat4.Text, { size: 0, style: { color:
|
|
3914
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: controlRow, role: "group", "aria-label": "Comparison basis", children: [
|
|
3915
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sanity_ui_compat4.Text, { size: 0, style: { color: COMPARISON_TEXT }, children: "Compared with" }),
|
|
3894
3916
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3895
3917
|
"button",
|
|
3896
3918
|
{
|
|
@@ -4037,90 +4059,93 @@ function VisitorInsightsTool(props) {
|
|
|
4037
4059
|
// Named for assistive technology even though the name is not printed: a Studio user with
|
|
4038
4060
|
// several tabs open hears which site's figures these are, without the heading repeating
|
|
4039
4061
|
// what the Studio navigation already says.
|
|
4040
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.
|
|
4041
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.
|
|
4042
|
-
|
|
4043
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.
|
|
4044
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4062
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.Container, { width: 4, padding: 4, as: "section", "aria-label": siteLabel ? `Visitor insights for ${siteLabel}` : "Visitor insights", children: [
|
|
4063
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: COMPARISON_STYLE }),
|
|
4064
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.Stack, { space: 5, children: [
|
|
4065
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.Flex, { align: "flex-start", justify: "space-between", gap: 4, wrap: "wrap", children: [
|
|
4066
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sanity_ui_compat4.Heading, { size: 2, children: "Visitor insights" }),
|
|
4067
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.Stack, { space: 2, children: [
|
|
4068
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RangeSelector, { value: range, custom, onChange: setRange, onCustomChange: setCustom }),
|
|
4069
|
+
COMPARED_TABS.includes(activePanel) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BasisSelector, { value: compare, onChange: setCompare })
|
|
4070
|
+
] })
|
|
4071
|
+
] }),
|
|
4072
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PanelTabs, { value: activePanel, onChange: setActivePanel }),
|
|
4073
|
+
range === "custom" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: contextRow, children: [
|
|
4074
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_sanity_ui_compat4.Text, { size: 0, muted: true, children: [
|
|
4075
|
+
"Showing ",
|
|
4076
|
+
custom.start,
|
|
4077
|
+
" to ",
|
|
4078
|
+
custom.end,
|
|
4079
|
+
" (",
|
|
4080
|
+
daysBetween(custom.start, custom.end),
|
|
4081
|
+
" days).",
|
|
4082
|
+
daysBetween(custom.start, custom.end) < 14 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: " Short windows lose GA4\u2019s low-count rows, so the source and typeface lists will be shorter than reality." })
|
|
4083
|
+
] }),
|
|
4084
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4085
|
+
"button",
|
|
4086
|
+
{
|
|
4087
|
+
type: "button",
|
|
4088
|
+
style: inlineClear,
|
|
4089
|
+
"aria-label": "Shift the window back by its own length",
|
|
4090
|
+
onClick: () => {
|
|
4091
|
+
const span = daysBetween(custom.start, custom.end);
|
|
4092
|
+
setCustom({ start: shiftDays(custom.start, -span), end: shiftDays(custom.end, -span) });
|
|
4093
|
+
},
|
|
4094
|
+
children: "\u2190 earlier"
|
|
4095
|
+
}
|
|
4096
|
+
),
|
|
4097
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4098
|
+
"button",
|
|
4099
|
+
{
|
|
4100
|
+
type: "button",
|
|
4101
|
+
"aria-label": "Shift the window forward by its own length",
|
|
4102
|
+
disabled: atPresent,
|
|
4103
|
+
style: atPresent ? { ...inlineClear, opacity: 0.35, cursor: "not-allowed" } : inlineClear,
|
|
4104
|
+
title: atPresent ? "This window already ends today" : void 0,
|
|
4105
|
+
onClick: () => {
|
|
4106
|
+
const span = daysBetween(custom.start, custom.end);
|
|
4107
|
+
const today = isoDaysAgo(0);
|
|
4108
|
+
const room = daysBetween(custom.end, today) - 1;
|
|
4109
|
+
const allowed = Math.min(span, room);
|
|
4110
|
+
if (allowed <= 0) return;
|
|
4111
|
+
setCustom({ start: shiftDays(custom.start, allowed), end: shiftDays(custom.end, allowed) });
|
|
4112
|
+
},
|
|
4113
|
+
children: "later \u2192"
|
|
4114
|
+
}
|
|
4115
|
+
),
|
|
4116
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", style: inlineClear, onClick: () => setRange(rangeBeforeBrush), children: [
|
|
4117
|
+
"Back to the ",
|
|
4118
|
+
RANGES.find((r) => r.key === rangeBeforeBrush)?.label.toLowerCase() ?? "week"
|
|
4119
|
+
] })
|
|
4059
4120
|
] }),
|
|
4060
4121
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4061
|
-
|
|
4062
|
-
{
|
|
4063
|
-
type: "button",
|
|
4064
|
-
style: inlineClear,
|
|
4065
|
-
"aria-label": "Shift the window back by its own length",
|
|
4066
|
-
onClick: () => {
|
|
4067
|
-
const span = daysBetween(custom.start, custom.end);
|
|
4068
|
-
setCustom({ start: shiftDays(custom.start, -span), end: shiftDays(custom.end, -span) });
|
|
4069
|
-
},
|
|
4070
|
-
children: "\u2190 earlier"
|
|
4071
|
-
}
|
|
4072
|
-
),
|
|
4073
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4074
|
-
"button",
|
|
4122
|
+
import_sanity_ui_compat4.Box,
|
|
4075
4123
|
{
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
] })
|
|
4096
|
-
] }),
|
|
4097
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4098
|
-
import_sanity_ui_compat4.Box,
|
|
4099
|
-
{
|
|
4100
|
-
role: "tabpanel",
|
|
4101
|
-
id: `panel-${activePanel}`,
|
|
4102
|
-
"aria-labelledby": `tab-${activePanel}`,
|
|
4103
|
-
tabIndex: 0,
|
|
4104
|
-
style: { position: "relative" },
|
|
4105
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sanity_ui_compat4.Stack, { space: 4, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PanelBoundary, { resetKey: `${activePanel}|${range}|${custom.start}|${custom.end}`, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4106
|
-
ReportPanel,
|
|
4107
|
-
{
|
|
4108
|
-
tabId: active?.id ?? "overview",
|
|
4109
|
-
report: active?.report ?? "measurement-health",
|
|
4110
|
-
apiBaseUrl,
|
|
4111
|
-
range,
|
|
4112
|
-
custom,
|
|
4113
|
-
compare,
|
|
4114
|
-
onBrush: (start, end) => {
|
|
4115
|
-
if (range !== "custom") setRangeBeforeBrush(range);
|
|
4116
|
-
setCustom({ start, end });
|
|
4117
|
-
setRange("custom");
|
|
4124
|
+
role: "tabpanel",
|
|
4125
|
+
id: `panel-${activePanel}`,
|
|
4126
|
+
"aria-labelledby": `tab-${activePanel}`,
|
|
4127
|
+
tabIndex: 0,
|
|
4128
|
+
style: { position: "relative" },
|
|
4129
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sanity_ui_compat4.Stack, { space: 4, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PanelBoundary, { resetKey: `${activePanel}|${range}|${custom.start}|${custom.end}`, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4130
|
+
ReportPanel,
|
|
4131
|
+
{
|
|
4132
|
+
tabId: active?.id ?? "overview",
|
|
4133
|
+
report: active?.report ?? "measurement-health",
|
|
4134
|
+
apiBaseUrl,
|
|
4135
|
+
range,
|
|
4136
|
+
custom,
|
|
4137
|
+
compare,
|
|
4138
|
+
onBrush: (start, end) => {
|
|
4139
|
+
if (range !== "custom") setRangeBeforeBrush(range);
|
|
4140
|
+
setCustom({ start, end });
|
|
4141
|
+
setRange("custom");
|
|
4142
|
+
}
|
|
4118
4143
|
}
|
|
4119
|
-
}
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
)
|
|
4123
|
-
] })
|
|
4144
|
+
) }) })
|
|
4145
|
+
}
|
|
4146
|
+
)
|
|
4147
|
+
] })
|
|
4148
|
+
] })
|
|
4124
4149
|
);
|
|
4125
4150
|
}
|
|
4126
4151
|
|