@tomismeta/paperclip-aperture 0.3.0 → 0.3.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/README.md +1 -1
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +404 -252
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ and agents attention now? actually sees to th
|
|
|
80
80
|
|
|
81
81
|
Focus is meant to be more legible than a smart inbox.
|
|
82
82
|
|
|
83
|
-
The
|
|
83
|
+
The current `0.3.x` explainability slice keeps reasoning attached to the cards you are already acting on:
|
|
84
84
|
|
|
85
85
|
- `Why now` on the active card explains why the current item outranks the rest of the queue
|
|
86
86
|
- `Why next` on queued rows explains why something is staged behind the current top item
|
package/dist/manifest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const manifest = {
|
|
2
2
|
id: "tomismeta.paperclip-aperture",
|
|
3
3
|
apiVersion: 1,
|
|
4
|
-
version: "0.3.
|
|
4
|
+
version: "0.3.1",
|
|
5
5
|
displayName: "Paperclip Aperture",
|
|
6
6
|
description: "The live attention layer for Paperclip, powered by Aperture's deterministic attention engine.",
|
|
7
7
|
author: "@tomismeta",
|
package/dist/ui/index.js
CHANGED
|
@@ -408,12 +408,13 @@ function approvalRevisionFailureMessage(error) {
|
|
|
408
408
|
// src/ui/index.tsx
|
|
409
409
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
410
410
|
var ACCENT_COLOR = "#007ACC";
|
|
411
|
+
var ACCENT_BG = `${ACCENT_COLOR}14`;
|
|
412
|
+
var ACCENT_BORDER = `${ACCENT_COLOR}33`;
|
|
411
413
|
var ACCENT_BG_STYLE = { backgroundColor: ACCENT_COLOR };
|
|
412
414
|
function currentSurfaceBrand() {
|
|
413
415
|
return {
|
|
414
416
|
key: "focus",
|
|
415
417
|
wordmark: "Focus",
|
|
416
|
-
supportCopy: "Powered by Aperture",
|
|
417
418
|
headingEmptyState: "No focus state yet.",
|
|
418
419
|
loadingLabel: "Loading Focus\u2026"
|
|
419
420
|
};
|
|
@@ -429,6 +430,29 @@ function Accent({ children, className }) {
|
|
|
429
430
|
const ref = useAccentColor();
|
|
430
431
|
return /* @__PURE__ */ jsx("span", { ref, className, children });
|
|
431
432
|
}
|
|
433
|
+
function QuietMark({ size = "sm" }) {
|
|
434
|
+
const dimension = size === "md" ? 10 : 8;
|
|
435
|
+
return /* @__PURE__ */ jsx(
|
|
436
|
+
"span",
|
|
437
|
+
{
|
|
438
|
+
"aria-hidden": "true",
|
|
439
|
+
className: "inline-block shrink-0 rounded-full border",
|
|
440
|
+
style: { width: dimension, height: dimension, borderColor: ACCENT_BORDER }
|
|
441
|
+
}
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
function useWideLayout(minWidth = 1024) {
|
|
445
|
+
const [matches, setMatches] = useState(false);
|
|
446
|
+
useEffect(() => {
|
|
447
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
448
|
+
const query = window.matchMedia(`(min-width: ${minWidth}px)`);
|
|
449
|
+
const update = () => setMatches(query.matches);
|
|
450
|
+
update();
|
|
451
|
+
query.addEventListener("change", update);
|
|
452
|
+
return () => query.removeEventListener("change", update);
|
|
453
|
+
}, [minWidth]);
|
|
454
|
+
return matches;
|
|
455
|
+
}
|
|
432
456
|
function cn(...parts) {
|
|
433
457
|
return parts.filter(Boolean).join(" ");
|
|
434
458
|
}
|
|
@@ -501,7 +525,7 @@ function driverLabel(frame) {
|
|
|
501
525
|
function driverBadgeStyle() {
|
|
502
526
|
return {
|
|
503
527
|
className: "border-transparent",
|
|
504
|
-
style: { color: ACCENT_COLOR, backgroundColor:
|
|
528
|
+
style: { color: ACCENT_COLOR, backgroundColor: ACCENT_BG, borderColor: ACCENT_BORDER }
|
|
505
529
|
};
|
|
506
530
|
}
|
|
507
531
|
function requestDescriptor(frame) {
|
|
@@ -542,6 +566,15 @@ function supportingLine(frame, lane) {
|
|
|
542
566
|
if (owner && lane === "active" && entityTypeFromFrame(frame) === "issue") {
|
|
543
567
|
return issueNeedsActionFromLine(owner);
|
|
544
568
|
}
|
|
569
|
+
if (lane === "active") {
|
|
570
|
+
const recommendedMove = recommendedMoveValue(frame)?.trim();
|
|
571
|
+
const summary = frame.summary?.trim();
|
|
572
|
+
const judgment2 = judgmentLine(frame, lane).trim();
|
|
573
|
+
if (recommendedMove && summary && summary !== recommendedMove && summary !== judgment2) {
|
|
574
|
+
return summary;
|
|
575
|
+
}
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
545
578
|
const judgment = judgmentLine(frame, lane);
|
|
546
579
|
return judgment.trim().length > 0 ? judgment : null;
|
|
547
580
|
}
|
|
@@ -635,9 +668,11 @@ function isFrameUnreadInSnapshot(frame, snapshot) {
|
|
|
635
668
|
if (!seenAt) return true;
|
|
636
669
|
return frameUpdatedAt(frame, snapshot.updatedAt).localeCompare(seenAt) > 0;
|
|
637
670
|
}
|
|
638
|
-
function UnreadDot(
|
|
639
|
-
|
|
640
|
-
|
|
671
|
+
function UnreadDot(props) {
|
|
672
|
+
const tone = props.tone ?? "default";
|
|
673
|
+
if (!props.visible && !props.reserveSpace) return null;
|
|
674
|
+
const style = props.visible ? tone === "muted" ? { backgroundColor: ACCENT_BORDER } : ACCENT_BG_STYLE : { backgroundColor: "transparent" };
|
|
675
|
+
return /* @__PURE__ */ jsx("span", { className: "inline-block h-2 w-2 rounded-full shrink-0", style, "aria-label": props.visible ? "Unread attention item" : void 0 });
|
|
641
676
|
}
|
|
642
677
|
function ExternalLinkIcon() {
|
|
643
678
|
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 16 16", className: "h-3 w-3", fill: "none", stroke: "currentColor", strokeWidth: "1.5", "aria-hidden": "true", children: [
|
|
@@ -702,7 +737,7 @@ function StatusToast({ message }) {
|
|
|
702
737
|
"div",
|
|
703
738
|
{
|
|
704
739
|
className: cn(
|
|
705
|
-
"pointer-events-none fixed bottom-6
|
|
740
|
+
"pointer-events-none fixed bottom-6 left-1/2 z-50 -translate-x-1/2 transition-all duration-200",
|
|
706
741
|
message ? "translate-y-0 opacity-100" : "translate-y-2 opacity-0"
|
|
707
742
|
),
|
|
708
743
|
"aria-live": "polite",
|
|
@@ -919,21 +954,26 @@ function Badge(props) {
|
|
|
919
954
|
);
|
|
920
955
|
}
|
|
921
956
|
function ActionButton(props) {
|
|
922
|
-
const
|
|
957
|
+
const [hovered, setHovered] = useState(false);
|
|
958
|
+
const toneClass = props.tone === "primary" ? "bg-green-700 text-white hover:bg-green-600" : props.tone === "accent" ? "text-white" : props.tone === "danger" ? "bg-destructive text-white hover:bg-destructive/90 dark:bg-destructive/60" : "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50";
|
|
923
959
|
return /* @__PURE__ */ jsx(
|
|
924
960
|
"button",
|
|
925
961
|
{
|
|
926
962
|
type: "button",
|
|
927
963
|
onClick: props.onClick,
|
|
964
|
+
onMouseEnter: () => setHovered(true),
|
|
965
|
+
onMouseLeave: () => setHovered(false),
|
|
928
966
|
disabled: props.disabled,
|
|
929
967
|
className: cn(
|
|
930
968
|
"inline-flex h-8 items-center justify-center gap-2 rounded-md px-3 text-sm font-medium",
|
|
931
|
-
"transition-[color,background-color,border-color,box-shadow,opacity]",
|
|
969
|
+
"transition-[color,background-color,border-color,box-shadow,opacity,filter]",
|
|
932
970
|
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
933
971
|
"disabled:pointer-events-none disabled:opacity-50",
|
|
972
|
+
props.disabled && /…|\.\.\./.test(props.label) && "animate-pulse",
|
|
934
973
|
toneClass,
|
|
935
974
|
props.className
|
|
936
975
|
),
|
|
976
|
+
style: props.tone === "accent" ? { ...ACCENT_BG_STYLE, filter: hovered && !props.disabled ? "brightness(1.08)" : void 0 } : void 0,
|
|
937
977
|
children: props.label
|
|
938
978
|
}
|
|
939
979
|
);
|
|
@@ -946,8 +986,8 @@ function QueueMovementBadge({ movement }) {
|
|
|
946
986
|
className: "inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[11px] font-medium",
|
|
947
987
|
style: {
|
|
948
988
|
color: ACCENT_COLOR,
|
|
949
|
-
backgroundColor:
|
|
950
|
-
borderColor:
|
|
989
|
+
backgroundColor: ACCENT_BG,
|
|
990
|
+
borderColor: ACCENT_BORDER
|
|
951
991
|
},
|
|
952
992
|
children: [
|
|
953
993
|
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: movement === "up" ? "\u2191" : "\u2193" }),
|
|
@@ -992,21 +1032,24 @@ function FrameActions(props) {
|
|
|
992
1032
|
ActionButton,
|
|
993
1033
|
{
|
|
994
1034
|
label: isPending ? "Saving\u2026" : "Acknowledge",
|
|
995
|
-
tone: "
|
|
1035
|
+
tone: "accent",
|
|
996
1036
|
disabled: isPending,
|
|
997
1037
|
onClick: () => void props.onAcknowledge(props.frame)
|
|
998
1038
|
}
|
|
999
1039
|
) });
|
|
1000
1040
|
}
|
|
1041
|
+
function visibleContextItems(frame) {
|
|
1042
|
+
return (frame.context?.items ?? []).filter((item2) => item2.id !== ATTENTION_CONTEXT_IDS.recommendedMove);
|
|
1043
|
+
}
|
|
1001
1044
|
function ContextItems({ frame }) {
|
|
1002
|
-
const items = frame
|
|
1045
|
+
const items = visibleContextItems(frame);
|
|
1003
1046
|
if (items.length === 0) return null;
|
|
1004
1047
|
return /* @__PURE__ */ jsx("div", { className: "grid gap-2 md:grid-cols-2", children: items.map((item2) => /* @__PURE__ */ jsxs(
|
|
1005
1048
|
"div",
|
|
1006
1049
|
{
|
|
1007
1050
|
className: cn(
|
|
1008
1051
|
"border border-border bg-secondary/50 px-3 py-2",
|
|
1009
|
-
|
|
1052
|
+
item2.id === ATTENTION_CONTEXT_IDS.latestComment && "md:col-span-2"
|
|
1010
1053
|
),
|
|
1011
1054
|
children: [
|
|
1012
1055
|
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground", children: item2.label }),
|
|
@@ -1016,60 +1059,90 @@ function ContextItems({ frame }) {
|
|
|
1016
1059
|
item2.id
|
|
1017
1060
|
)) });
|
|
1018
1061
|
}
|
|
1019
|
-
function DetailCard(props) {
|
|
1020
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("border border-border bg-secondary/50 px-3 py-2", props.className), children: [
|
|
1021
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground", children: props.label }),
|
|
1022
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1", children: props.children })
|
|
1023
|
-
] });
|
|
1024
|
-
}
|
|
1025
1062
|
function ExplainabilityBadges(props) {
|
|
1026
1063
|
if (props.values.length === 0) return null;
|
|
1027
1064
|
return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: props.values.map((value) => /* @__PURE__ */ jsx(
|
|
1028
1065
|
Badge,
|
|
1029
1066
|
{
|
|
1030
1067
|
className: props.accent ? "border-transparent" : "border-border bg-background/70 text-foreground/80",
|
|
1031
|
-
style: props.accent ? { color: ACCENT_COLOR, backgroundColor:
|
|
1068
|
+
style: props.accent ? { color: ACCENT_COLOR, backgroundColor: ACCENT_BG, borderColor: ACCENT_BORDER } : void 0,
|
|
1032
1069
|
children: value
|
|
1033
1070
|
},
|
|
1034
1071
|
value
|
|
1035
1072
|
)) });
|
|
1036
1073
|
}
|
|
1037
|
-
function
|
|
1038
|
-
const explanation = explainFrame(props.frame, props.lane);
|
|
1039
|
-
const strength = explanation.signalStrength ? signalStrengthLabel(explanation.signalStrength) : null;
|
|
1040
|
-
return /* @__PURE__ */ jsxs("div", { className: "grid gap-3 lg:grid-cols-2", children: [
|
|
1041
|
-
/* @__PURE__ */ jsxs(DetailCard, { label: "Why now", className: "lg:col-span-2", children: [
|
|
1042
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed text-foreground/90", children: explanation.whyNow ?? judgmentLine(props.frame, props.lane) }),
|
|
1043
|
-
/* @__PURE__ */ jsx("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: explanation.laneReason })
|
|
1044
|
-
] }),
|
|
1045
|
-
strength ? /* @__PURE__ */ jsx(DetailCard, { label: "Confidence", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground/90", children: strength }) }) : null,
|
|
1046
|
-
explanation.continuity ? /* @__PURE__ */ jsx(DetailCard, { label: "Related activity", children: /* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed text-foreground/90", children: explanation.continuity }) }) : null,
|
|
1047
|
-
explanation.signals.length > 0 ? /* @__PURE__ */ jsx(DetailCard, { label: "Signals", className: explanation.relationLabels.length > 0 ? "lg:col-span-1" : "lg:col-span-2", children: /* @__PURE__ */ jsx(ExplainabilityBadges, { values: explanation.signals }) }) : null,
|
|
1048
|
-
explanation.relationLabels.length > 0 ? /* @__PURE__ */ jsx(DetailCard, { label: "Thread context", className: explanation.signals.length > 0 ? "lg:col-span-1" : "lg:col-span-2", children: /* @__PURE__ */ jsx(ExplainabilityBadges, { values: explanation.relationLabels, accent: true }) }) : null
|
|
1049
|
-
] });
|
|
1050
|
-
}
|
|
1051
|
-
function ExplainabilityStrip(props) {
|
|
1074
|
+
function InlineExplainability(props) {
|
|
1052
1075
|
const explanation = explainFrame(props.frame, props.lane);
|
|
1053
1076
|
const chips = [
|
|
1054
1077
|
...explanation.signalStrength ? [signalStrengthLabel(explanation.signalStrength)] : [],
|
|
1055
1078
|
...explanation.signals.slice(0, 2),
|
|
1056
1079
|
...explanation.relationLabels.slice(0, 1)
|
|
1057
1080
|
];
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1081
|
+
const label = props.lane === "queued" ? "Why next" : props.lane === "ambient" ? "Why ambient" : "Why now";
|
|
1082
|
+
const whyNow = explanation.whyNow ?? judgmentLine(props.frame, props.lane);
|
|
1083
|
+
const primaryLine = props.lane === "active" ? props.preferLaneReason ? explanation.laneReason : whyNow : whyNow;
|
|
1084
|
+
const secondaryLine = props.lane === "active" ? !props.preferLaneReason && whyNow !== explanation.laneReason ? explanation.laneReason : null : explanation.laneReason;
|
|
1085
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2 border-l-2 pl-4", style: { borderColor: ACCENT_COLOR }, children: [
|
|
1086
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: label }),
|
|
1087
|
+
/* @__PURE__ */ jsx("p", { className: "max-w-3xl text-sm leading-relaxed text-foreground/90", children: primaryLine }),
|
|
1088
|
+
secondaryLine ? /* @__PURE__ */ jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: secondaryLine }) : null,
|
|
1062
1089
|
chips.length > 0 ? /* @__PURE__ */ jsx(ExplainabilityBadges, { values: chips, accent: true }) : null
|
|
1063
1090
|
] });
|
|
1064
1091
|
}
|
|
1092
|
+
function ExplainabilityPanel(props) {
|
|
1093
|
+
const explanation = explainFrame(props.frame, props.lane);
|
|
1094
|
+
const strength = !props.detailOnly && explanation.signalStrength ? signalStrengthLabel(explanation.signalStrength) : null;
|
|
1095
|
+
const signalValues = props.detailOnly ? explanation.signals.slice(2) : explanation.signals;
|
|
1096
|
+
const relationValues = props.detailOnly ? explanation.relationLabels.slice(1) : explanation.relationLabels;
|
|
1097
|
+
const reasoningLabel = props.lane === "active" ? "Reasoning" : props.lane === "queued" ? "Why it sits here" : "Why it stays quiet";
|
|
1098
|
+
if (props.detailOnly && signalValues.length === 0 && relationValues.length === 0 && !explanation.continuity) {
|
|
1099
|
+
return null;
|
|
1100
|
+
}
|
|
1101
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1102
|
+
!props.detailOnly ? /* @__PURE__ */ jsxs("div", { className: "grid gap-4 lg:grid-cols-[minmax(0,1fr)_16rem]", children: [
|
|
1103
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1104
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: reasoningLabel }),
|
|
1105
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm leading-relaxed text-muted-foreground", children: explanation.laneReason })
|
|
1106
|
+
] }),
|
|
1107
|
+
strength ? /* @__PURE__ */ jsxs("div", { children: [
|
|
1108
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: "Confidence" }),
|
|
1109
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-foreground/90", children: strength })
|
|
1110
|
+
] }) : null
|
|
1111
|
+
] }) : null,
|
|
1112
|
+
signalValues.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1113
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: props.detailOnly ? "More signals" : "Signals" }),
|
|
1114
|
+
/* @__PURE__ */ jsx(ExplainabilityBadges, { values: signalValues })
|
|
1115
|
+
] }) : null,
|
|
1116
|
+
relationValues.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1117
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: props.detailOnly ? "More thread context" : "Thread context" }),
|
|
1118
|
+
/* @__PURE__ */ jsx(ExplainabilityBadges, { values: relationValues, accent: true })
|
|
1119
|
+
] }) : null,
|
|
1120
|
+
explanation.continuity ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1121
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: "Related activity" }),
|
|
1122
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: explanation.continuity })
|
|
1123
|
+
] }) : null
|
|
1124
|
+
] });
|
|
1125
|
+
}
|
|
1126
|
+
function ExplainabilityStrip(props) {
|
|
1127
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-2 border-t border-border/60 pt-3", children: /* @__PURE__ */ jsx(InlineExplainability, { frame: props.frame, lane: props.lane }) });
|
|
1128
|
+
}
|
|
1065
1129
|
function isIssueFrame(frame) {
|
|
1066
1130
|
return entityTypeFromFrame(frame) === "issue";
|
|
1067
1131
|
}
|
|
1068
1132
|
function IssueCommentComposer(props) {
|
|
1069
1133
|
const [open, setOpen] = useState(false);
|
|
1070
1134
|
const [body, setBody] = useState("");
|
|
1071
|
-
|
|
1135
|
+
const textareaRef = useRef(null);
|
|
1136
|
+
const issueFrame = isIssueFrame(props.frame);
|
|
1072
1137
|
const isPending = props.pendingId === props.frame.id;
|
|
1138
|
+
useEffect(() => {
|
|
1139
|
+
setOpen(false);
|
|
1140
|
+
setBody("");
|
|
1141
|
+
}, [props.frame.id]);
|
|
1142
|
+
useEffect(() => {
|
|
1143
|
+
if (open && issueFrame) textareaRef.current?.focus();
|
|
1144
|
+
}, [open, issueFrame]);
|
|
1145
|
+
if (!issueFrame) return null;
|
|
1073
1146
|
async function submit() {
|
|
1074
1147
|
const nextBody = body.trim();
|
|
1075
1148
|
if (!nextBody) return;
|
|
@@ -1096,30 +1169,42 @@ function IssueCommentComposer(props) {
|
|
|
1096
1169
|
{
|
|
1097
1170
|
label,
|
|
1098
1171
|
tone: triggerTone,
|
|
1099
|
-
className: "w-full",
|
|
1172
|
+
className: props.triggerFullWidth ? "w-full" : void 0,
|
|
1100
1173
|
disabled: isPending,
|
|
1101
1174
|
onClick: () => setOpen(true)
|
|
1102
1175
|
}
|
|
1103
1176
|
);
|
|
1104
1177
|
}
|
|
1105
|
-
return /* @__PURE__ */ jsxs("div", { className: "w-full space-y-2 border border-border bg-secondary/40 p-3", children: [
|
|
1178
|
+
return /* @__PURE__ */ jsxs("div", { className: "w-full space-y-2 rounded-md border border-border bg-secondary/40 p-3", children: [
|
|
1179
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: "Posts to the issue thread without leaving Focus." }),
|
|
1106
1180
|
/* @__PURE__ */ jsx(
|
|
1107
1181
|
"textarea",
|
|
1108
1182
|
{
|
|
1183
|
+
ref: textareaRef,
|
|
1109
1184
|
value: body,
|
|
1110
1185
|
onChange: (event) => setBody(event.target.value),
|
|
1186
|
+
onKeyDown: (event) => {
|
|
1187
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
1188
|
+
event.preventDefault();
|
|
1189
|
+
void submit();
|
|
1190
|
+
}
|
|
1191
|
+
if (event.key === "Escape") {
|
|
1192
|
+
event.preventDefault();
|
|
1193
|
+
setOpen(false);
|
|
1194
|
+
setBody("");
|
|
1195
|
+
}
|
|
1196
|
+
},
|
|
1111
1197
|
rows: 3,
|
|
1112
1198
|
placeholder: "Add a short operator note back to the issue\u2026",
|
|
1113
1199
|
className: "w-full resize-y rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground shadow-xs outline-none transition focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
|
|
1114
1200
|
}
|
|
1115
1201
|
),
|
|
1116
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
1202
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
1117
1203
|
/* @__PURE__ */ jsx(
|
|
1118
1204
|
ActionButton,
|
|
1119
1205
|
{
|
|
1120
1206
|
label: "Cancel",
|
|
1121
1207
|
tone: "secondary",
|
|
1122
|
-
className: "w-full",
|
|
1123
1208
|
disabled: isPending,
|
|
1124
1209
|
onClick: () => {
|
|
1125
1210
|
setOpen(false);
|
|
@@ -1131,8 +1216,7 @@ function IssueCommentComposer(props) {
|
|
|
1131
1216
|
ActionButton,
|
|
1132
1217
|
{
|
|
1133
1218
|
label: isPending ? "Posting\u2026" : "Post comment",
|
|
1134
|
-
tone: "
|
|
1135
|
-
className: "w-full",
|
|
1219
|
+
tone: "accent",
|
|
1136
1220
|
disabled: isPending || body.trim().length === 0,
|
|
1137
1221
|
onClick: () => void submit()
|
|
1138
1222
|
}
|
|
@@ -1145,8 +1229,9 @@ function NowDetails(props) {
|
|
|
1145
1229
|
const href = itemHref(frame, props.companyPrefix);
|
|
1146
1230
|
const budgetHref = isBudgetOverride(frame) ? costsHref(props.companyPrefix) : null;
|
|
1147
1231
|
const activityLink = activityHref(frame, props.companyPrefix);
|
|
1232
|
+
const hasContext = visibleContextItems(frame).length > 0;
|
|
1148
1233
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-3 border-t border-border pt-4", children: [
|
|
1149
|
-
/* @__PURE__ */ jsx(ExplainabilityPanel, { frame, lane: "active" }),
|
|
1234
|
+
/* @__PURE__ */ jsx(ExplainabilityPanel, { frame, lane: "active", detailOnly: true }),
|
|
1150
1235
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
1151
1236
|
/* @__PURE__ */ jsx("span", { children: requestDescriptor(frame) }),
|
|
1152
1237
|
/* @__PURE__ */ jsx("span", { children: impactLabel(frame) }),
|
|
@@ -1157,7 +1242,10 @@ function NowDetails(props) {
|
|
|
1157
1242
|
] }) : null,
|
|
1158
1243
|
budgetReason(frame) ? /* @__PURE__ */ jsx("span", { children: budgetReason(frame) }) : null
|
|
1159
1244
|
] }),
|
|
1160
|
-
/* @__PURE__ */
|
|
1245
|
+
hasContext ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1246
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: "Context" }),
|
|
1247
|
+
/* @__PURE__ */ jsx(ContextItems, { frame })
|
|
1248
|
+
] }) : null,
|
|
1161
1249
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
1162
1250
|
href ? /* @__PURE__ */ jsxs(
|
|
1163
1251
|
"a",
|
|
@@ -1203,41 +1291,41 @@ function NowDetails(props) {
|
|
|
1203
1291
|
] });
|
|
1204
1292
|
}
|
|
1205
1293
|
function QuietNow() {
|
|
1206
|
-
return /* @__PURE__ */
|
|
1294
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-20 items-center gap-3", children: [
|
|
1295
|
+
/* @__PURE__ */ jsx(QuietMark, { size: "md" }),
|
|
1296
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: "Nothing active right now." })
|
|
1297
|
+
] });
|
|
1207
1298
|
}
|
|
1208
1299
|
function NowActionRail(props) {
|
|
1209
1300
|
const actionMode = responseKind(props.frame, props.lane);
|
|
1210
1301
|
const isPending = props.pendingId === props.frame.id;
|
|
1211
1302
|
const commentEnabled = actionMode === "acknowledge" && isIssueFrame(props.frame);
|
|
1303
|
+
const [commentOpen, setCommentOpen] = useState(false);
|
|
1304
|
+
const [commentBody, setCommentBody] = useState("");
|
|
1305
|
+
const textareaRef = useRef(null);
|
|
1306
|
+
useEffect(() => {
|
|
1307
|
+
setCommentOpen(false);
|
|
1308
|
+
setCommentBody("");
|
|
1309
|
+
}, [props.frame.id]);
|
|
1310
|
+
useEffect(() => {
|
|
1311
|
+
if (commentOpen) textareaRef.current?.focus();
|
|
1312
|
+
}, [commentOpen]);
|
|
1313
|
+
async function submitComment() {
|
|
1314
|
+
const nextBody = commentBody.trim();
|
|
1315
|
+
if (!nextBody) return;
|
|
1316
|
+
await props.onComment(props.frame, nextBody);
|
|
1317
|
+
setCommentBody("");
|
|
1318
|
+
setCommentOpen(false);
|
|
1319
|
+
}
|
|
1212
1320
|
return /* @__PURE__ */ jsxs(
|
|
1213
|
-
"
|
|
1321
|
+
"div",
|
|
1214
1322
|
{
|
|
1215
|
-
className: "space-y-
|
|
1216
|
-
style: {
|
|
1323
|
+
className: "space-y-3 rounded-md border border-border/60 bg-secondary/20 px-3 py-3",
|
|
1324
|
+
style: props.wide ? { width: 320, flexShrink: 0, position: "sticky", top: 16, alignSelf: "flex-start" } : void 0,
|
|
1217
1325
|
children: [
|
|
1218
|
-
/* @__PURE__ */ jsx("div", { className: "text-
|
|
1219
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1220
|
-
|
|
1221
|
-
IssueCommentComposer,
|
|
1222
|
-
{
|
|
1223
|
-
frame: props.frame,
|
|
1224
|
-
pendingId: props.pendingId,
|
|
1225
|
-
onComment: props.onComment,
|
|
1226
|
-
triggerTone: "primary",
|
|
1227
|
-
triggerLabel: "Comment"
|
|
1228
|
-
}
|
|
1229
|
-
) : null,
|
|
1230
|
-
actionMode === "approval" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1231
|
-
isBudgetOverride(props.frame) ? /* @__PURE__ */ jsx(
|
|
1232
|
-
ActionButton,
|
|
1233
|
-
{
|
|
1234
|
-
label: "Request revision",
|
|
1235
|
-
tone: "secondary",
|
|
1236
|
-
disabled: isPending,
|
|
1237
|
-
className: "w-full",
|
|
1238
|
-
onClick: () => void props.onRequestRevision(props.frame)
|
|
1239
|
-
}
|
|
1240
|
-
) : null,
|
|
1326
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: "Actions" }),
|
|
1327
|
+
actionMode === "approval" ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1328
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
1241
1329
|
/* @__PURE__ */ jsx(
|
|
1242
1330
|
ActionButton,
|
|
1243
1331
|
{
|
|
@@ -1258,17 +1346,37 @@ function NowActionRail(props) {
|
|
|
1258
1346
|
onClick: () => void props.onReject(props.frame)
|
|
1259
1347
|
}
|
|
1260
1348
|
)
|
|
1261
|
-
] })
|
|
1349
|
+
] }),
|
|
1350
|
+
isBudgetOverride(props.frame) ? /* @__PURE__ */ jsx(
|
|
1262
1351
|
ActionButton,
|
|
1263
1352
|
{
|
|
1264
|
-
label:
|
|
1265
|
-
tone:
|
|
1353
|
+
label: "Request revision",
|
|
1354
|
+
tone: "secondary",
|
|
1266
1355
|
disabled: isPending,
|
|
1267
1356
|
className: "w-full",
|
|
1268
|
-
onClick: () => void props.
|
|
1357
|
+
onClick: () => void props.onRequestRevision(props.frame)
|
|
1269
1358
|
}
|
|
1270
1359
|
) : null
|
|
1271
|
-
] }),
|
|
1360
|
+
] }) : actionMode === "acknowledge" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1361
|
+
commentEnabled ? /* @__PURE__ */ jsx(
|
|
1362
|
+
ActionButton,
|
|
1363
|
+
{
|
|
1364
|
+
label: "Comment",
|
|
1365
|
+
tone: "accent",
|
|
1366
|
+
disabled: isPending,
|
|
1367
|
+
onClick: () => setCommentOpen(true)
|
|
1368
|
+
}
|
|
1369
|
+
) : null,
|
|
1370
|
+
/* @__PURE__ */ jsx(
|
|
1371
|
+
ActionButton,
|
|
1372
|
+
{
|
|
1373
|
+
label: isPending ? "Saving\u2026" : "Acknowledge",
|
|
1374
|
+
tone: "accent",
|
|
1375
|
+
disabled: isPending,
|
|
1376
|
+
onClick: () => void props.onAcknowledge(props.frame)
|
|
1377
|
+
}
|
|
1378
|
+
)
|
|
1379
|
+
] }) : null,
|
|
1272
1380
|
props.itemLink ? /* @__PURE__ */ jsxs(
|
|
1273
1381
|
"a",
|
|
1274
1382
|
{
|
|
@@ -1281,7 +1389,59 @@ function NowActionRail(props) {
|
|
|
1281
1389
|
/* @__PURE__ */ jsx(ExternalLinkIcon, {})
|
|
1282
1390
|
]
|
|
1283
1391
|
}
|
|
1284
|
-
) : null
|
|
1392
|
+
) : null,
|
|
1393
|
+
commentOpen ? /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-md border border-border bg-background/80 p-3", children: [
|
|
1394
|
+
/* @__PURE__ */ jsxs("div", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: [
|
|
1395
|
+
"Commenting on ",
|
|
1396
|
+
compactTitle(props.frame)
|
|
1397
|
+
] }),
|
|
1398
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "Posts to the issue thread without leaving Focus." }),
|
|
1399
|
+
/* @__PURE__ */ jsx(
|
|
1400
|
+
"textarea",
|
|
1401
|
+
{
|
|
1402
|
+
ref: textareaRef,
|
|
1403
|
+
value: commentBody,
|
|
1404
|
+
onChange: (event) => setCommentBody(event.target.value),
|
|
1405
|
+
onKeyDown: (event) => {
|
|
1406
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
1407
|
+
event.preventDefault();
|
|
1408
|
+
void submitComment();
|
|
1409
|
+
}
|
|
1410
|
+
if (event.key === "Escape") {
|
|
1411
|
+
event.preventDefault();
|
|
1412
|
+
setCommentOpen(false);
|
|
1413
|
+
setCommentBody("");
|
|
1414
|
+
}
|
|
1415
|
+
},
|
|
1416
|
+
rows: 4,
|
|
1417
|
+
placeholder: "Add a short operator note back to the issue\u2026",
|
|
1418
|
+
className: "w-full resize-y rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground shadow-xs outline-none transition focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
|
|
1419
|
+
}
|
|
1420
|
+
),
|
|
1421
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
1422
|
+
/* @__PURE__ */ jsx(
|
|
1423
|
+
ActionButton,
|
|
1424
|
+
{
|
|
1425
|
+
label: "Cancel",
|
|
1426
|
+
tone: "secondary",
|
|
1427
|
+
disabled: isPending,
|
|
1428
|
+
onClick: () => {
|
|
1429
|
+
setCommentOpen(false);
|
|
1430
|
+
setCommentBody("");
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
),
|
|
1434
|
+
/* @__PURE__ */ jsx(
|
|
1435
|
+
ActionButton,
|
|
1436
|
+
{
|
|
1437
|
+
label: isPending ? "Posting\u2026" : "Post comment",
|
|
1438
|
+
tone: "accent",
|
|
1439
|
+
disabled: isPending || commentBody.trim().length === 0,
|
|
1440
|
+
onClick: () => void submitComment()
|
|
1441
|
+
}
|
|
1442
|
+
)
|
|
1443
|
+
] })
|
|
1444
|
+
] }) : null
|
|
1285
1445
|
]
|
|
1286
1446
|
}
|
|
1287
1447
|
);
|
|
@@ -1289,6 +1449,7 @@ function NowActionRail(props) {
|
|
|
1289
1449
|
function NowPane(props) {
|
|
1290
1450
|
const frame = props.snapshot.active;
|
|
1291
1451
|
const [detailsOpen, setDetailsOpen] = useState(false);
|
|
1452
|
+
const wideLayout = useWideLayout(1120);
|
|
1292
1453
|
const activeFrameId = frame?.id ?? null;
|
|
1293
1454
|
const activeUnread = !!frame && (props.snapshot.review?.unread.active ?? 0) > 0;
|
|
1294
1455
|
const itemLink = frame ? itemHref(frame, props.companyPrefix) : null;
|
|
@@ -1298,100 +1459,111 @@ function NowPane(props) {
|
|
|
1298
1459
|
useEffect(() => {
|
|
1299
1460
|
setDetailsOpen(false);
|
|
1300
1461
|
}, [activeFrameId]);
|
|
1301
|
-
return /* @__PURE__ */ jsxs(
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1462
|
+
return /* @__PURE__ */ jsxs(
|
|
1463
|
+
"section",
|
|
1464
|
+
{
|
|
1465
|
+
className: "border border-border bg-card shadow-sm",
|
|
1466
|
+
style: frame ? { borderLeftWidth: 3, borderLeftColor: ACCENT_COLOR } : void 0,
|
|
1467
|
+
children: [
|
|
1468
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-b border-border bg-accent px-4 py-3 sm:px-6", children: [
|
|
1469
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1470
|
+
/* @__PURE__ */ jsx(Accent, { className: "text-sm leading-none", children: props.posture.glyph }),
|
|
1471
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
|
|
1472
|
+
/* @__PURE__ */ jsx(Accent, { className: "text-base leading-none font-semibold tracking-[0.04em]", children: props.brand.wordmark }),
|
|
1473
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] leading-none text-muted-foreground", children: props.posture.label })
|
|
1474
|
+
] })
|
|
1309
1475
|
] }),
|
|
1310
|
-
/* @__PURE__ */
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1476
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-xs tabular-nums text-muted-foreground", children: [
|
|
1477
|
+
/* @__PURE__ */ jsxs("span", { className: props.counts.active > 0 ? "font-semibold" : "", children: [
|
|
1478
|
+
"now ",
|
|
1479
|
+
props.counts.active > 0 ? /* @__PURE__ */ jsx(Accent, { children: props.counts.active }) : props.counts.active
|
|
1480
|
+
] }),
|
|
1481
|
+
/* @__PURE__ */ jsxs("span", { className: props.counts.queued > 0 ? "font-semibold" : "", children: [
|
|
1482
|
+
"next ",
|
|
1483
|
+
props.counts.queued > 0 ? /* @__PURE__ */ jsx(Accent, { children: props.counts.queued }) : props.counts.queued
|
|
1484
|
+
] }),
|
|
1485
|
+
/* @__PURE__ */ jsxs("span", { className: props.counts.ambient > 0 ? "font-semibold" : "", children: [
|
|
1486
|
+
"ambient ",
|
|
1487
|
+
props.counts.ambient > 0 ? /* @__PURE__ */ jsx(Accent, { children: props.counts.ambient }) : props.counts.ambient
|
|
1488
|
+
] })
|
|
1489
|
+
] })
|
|
1321
1490
|
] }),
|
|
1322
|
-
/* @__PURE__ */
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
] })
|
|
1326
|
-
] })
|
|
1327
|
-
] }),
|
|
1328
|
-
/* @__PURE__ */ jsx("div", { style: { height: "0.75rem" }, "aria-hidden": "true" }),
|
|
1329
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 pb-4 sm:px-6", children: !frame ? /* @__PURE__ */ jsx(QuietNow, {}) : /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1330
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start gap-6", children: [
|
|
1331
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-4", style: { flex: "1 1 40rem" }, children: [
|
|
1332
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1333
|
-
/* @__PURE__ */ jsx("span", { children: "Now" }),
|
|
1334
|
-
/* @__PURE__ */ jsx("span", { className: "normal-case tracking-normal", style: { opacity: 0.6 }, children: sourceLabel(frame) })
|
|
1335
|
-
] }),
|
|
1336
|
-
recommendedMove ? /* @__PURE__ */ jsx("div", { className: "max-w-4xl text-[2rem] font-semibold leading-tight text-foreground", children: recommendedMove }) : frame.summary ? /* @__PURE__ */ jsx("div", { className: "max-w-4xl text-[2rem] font-semibold leading-tight text-foreground", children: frame.summary }) : null,
|
|
1337
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[1.75rem] font-medium leading-snug text-foreground/90", children: [
|
|
1338
|
-
/* @__PURE__ */ jsx(UnreadDot, { visible: activeUnread }),
|
|
1339
|
-
/* @__PURE__ */ jsx("span", { children: renderTitle(frame) })
|
|
1340
|
-
] }),
|
|
1341
|
-
helperLine ? /* @__PURE__ */ jsx("p", { className: "max-w-3xl text-[0.95rem] leading-relaxed text-muted-foreground", children: helperLine }) : null,
|
|
1342
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1343
|
-
/* @__PURE__ */ jsx(Badge, { className: "border-border bg-secondary text-foreground/80", children: impactLabel(frame) }),
|
|
1344
|
-
driverLabel(frame) ? /* @__PURE__ */ jsx(Badge, { className: driverBadge.className, style: driverBadge.style, children: driverLabel(frame) }) : null
|
|
1345
|
-
] }),
|
|
1346
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-4 pt-1", children: /* @__PURE__ */ jsx(Accent, { children: /* @__PURE__ */ jsxs(
|
|
1347
|
-
"button",
|
|
1491
|
+
/* @__PURE__ */ jsx("div", { className: "px-5 py-5 sm:px-6", children: !frame ? /* @__PURE__ */ jsx(QuietNow, {}) : /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
|
|
1492
|
+
/* @__PURE__ */ jsxs(
|
|
1493
|
+
"div",
|
|
1348
1494
|
{
|
|
1349
|
-
|
|
1350
|
-
onClick: () => setDetailsOpen(!detailsOpen),
|
|
1351
|
-
"aria-expanded": detailsOpen,
|
|
1352
|
-
className: "flex items-center gap-1.5 text-xs font-medium transition-opacity hover:opacity-100",
|
|
1353
|
-
style: { color: "inherit" },
|
|
1495
|
+
className: wideLayout ? "flex items-start gap-6" : "space-y-4",
|
|
1354
1496
|
children: [
|
|
1497
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4", style: wideLayout ? { minWidth: 0, flex: 1 } : void 0, children: [
|
|
1498
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: [
|
|
1499
|
+
/* @__PURE__ */ jsx("span", { children: "Now" }),
|
|
1500
|
+
/* @__PURE__ */ jsx("span", { className: "normal-case tracking-normal text-muted-foreground/70", children: sourceLabel(frame) })
|
|
1501
|
+
] }),
|
|
1502
|
+
recommendedMove ? /* @__PURE__ */ jsx("div", { className: "max-w-4xl text-3xl font-semibold leading-tight text-foreground", children: recommendedMove }) : frame.summary ? /* @__PURE__ */ jsx("div", { className: "max-w-4xl text-3xl font-semibold leading-tight text-foreground", children: frame.summary }) : null,
|
|
1503
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xl font-medium leading-snug text-foreground/80", children: [
|
|
1504
|
+
/* @__PURE__ */ jsx(UnreadDot, { visible: activeUnread }),
|
|
1505
|
+
/* @__PURE__ */ jsx("span", { children: renderTitle(frame) })
|
|
1506
|
+
] }),
|
|
1507
|
+
helperLine ? /* @__PURE__ */ jsx("p", { className: "max-w-3xl text-sm leading-relaxed text-muted-foreground", children: helperLine }) : null,
|
|
1508
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1509
|
+
/* @__PURE__ */ jsx(Badge, { className: "border-border bg-secondary text-foreground/80", children: impactLabel(frame) }),
|
|
1510
|
+
driverLabel(frame) ? /* @__PURE__ */ jsx(Badge, { className: driverBadge.className, style: driverBadge.style, children: driverLabel(frame) }) : null
|
|
1511
|
+
] }),
|
|
1512
|
+
/* @__PURE__ */ jsx(InlineExplainability, { frame, lane: "active", preferLaneReason: !!helperLine }),
|
|
1513
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsx(Accent, { children: /* @__PURE__ */ jsxs(
|
|
1514
|
+
"button",
|
|
1515
|
+
{
|
|
1516
|
+
type: "button",
|
|
1517
|
+
onClick: () => setDetailsOpen(!detailsOpen),
|
|
1518
|
+
"aria-expanded": detailsOpen,
|
|
1519
|
+
className: "flex items-center gap-1.5 text-xs font-medium transition-opacity hover:opacity-100",
|
|
1520
|
+
style: { color: "inherit" },
|
|
1521
|
+
children: [
|
|
1522
|
+
/* @__PURE__ */ jsx(
|
|
1523
|
+
"svg",
|
|
1524
|
+
{
|
|
1525
|
+
viewBox: "0 0 16 16",
|
|
1526
|
+
className: cn("h-3 w-3 transition-transform", detailsOpen && "rotate-90"),
|
|
1527
|
+
fill: "currentColor",
|
|
1528
|
+
"aria-hidden": "true",
|
|
1529
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L9.94 8 6.22 4.28a.75.75 0 0 1 0-1.06Z" })
|
|
1530
|
+
}
|
|
1531
|
+
),
|
|
1532
|
+
detailsOpen ? "Hide context" : "Show context"
|
|
1533
|
+
]
|
|
1534
|
+
}
|
|
1535
|
+
) }) })
|
|
1536
|
+
] }),
|
|
1355
1537
|
/* @__PURE__ */ jsx(
|
|
1356
|
-
|
|
1538
|
+
NowActionRail,
|
|
1357
1539
|
{
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1540
|
+
frame,
|
|
1541
|
+
lane: "active",
|
|
1542
|
+
wide: wideLayout,
|
|
1543
|
+
pendingId: props.pendingId,
|
|
1544
|
+
itemLink,
|
|
1545
|
+
onApprove: props.onApprove,
|
|
1546
|
+
onReject: props.onReject,
|
|
1547
|
+
onRequestRevision: props.onRequestRevision,
|
|
1548
|
+
onAcknowledge: props.onAcknowledge,
|
|
1549
|
+
onComment: props.onComment
|
|
1363
1550
|
}
|
|
1364
|
-
)
|
|
1365
|
-
detailsOpen ? "Hide details" : "Show details"
|
|
1551
|
+
)
|
|
1366
1552
|
]
|
|
1367
1553
|
}
|
|
1368
|
-
)
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
onComment: props.onComment
|
|
1382
|
-
}
|
|
1383
|
-
)
|
|
1384
|
-
] }),
|
|
1385
|
-
detailsOpen ? /* @__PURE__ */ jsx(
|
|
1386
|
-
NowDetails,
|
|
1387
|
-
{
|
|
1388
|
-
frame,
|
|
1389
|
-
snapshotUpdatedAt: props.snapshot.updatedAt,
|
|
1390
|
-
companyPrefix: props.companyPrefix
|
|
1391
|
-
}
|
|
1392
|
-
) : null
|
|
1393
|
-
] }) })
|
|
1394
|
-
] });
|
|
1554
|
+
),
|
|
1555
|
+
detailsOpen ? /* @__PURE__ */ jsx(
|
|
1556
|
+
NowDetails,
|
|
1557
|
+
{
|
|
1558
|
+
frame,
|
|
1559
|
+
snapshotUpdatedAt: props.snapshot.updatedAt,
|
|
1560
|
+
companyPrefix: props.companyPrefix
|
|
1561
|
+
}
|
|
1562
|
+
) : null
|
|
1563
|
+
] }) })
|
|
1564
|
+
]
|
|
1565
|
+
}
|
|
1566
|
+
);
|
|
1395
1567
|
}
|
|
1396
1568
|
function NextRow(props) {
|
|
1397
1569
|
const { frame } = props;
|
|
@@ -1404,6 +1576,7 @@ function NextRow(props) {
|
|
|
1404
1576
|
const driverBadge = driverBadgeStyle();
|
|
1405
1577
|
const detailText = judgmentLine(frame, "queued");
|
|
1406
1578
|
const showDetailText = detailText.trim().length > 0 && detailText !== secondaryText && detailText !== GENERIC_QUEUED_JUDGMENT;
|
|
1579
|
+
const rankOpacity = Math.max(0.4, 1 - (props.rank - 1) * 0.14);
|
|
1407
1580
|
return /* @__PURE__ */ jsxs("div", { className: "border-b border-border/80 last:border-b-0", style: expanded ? { borderLeftWidth: 2, borderLeftColor: ACCENT_COLOR } : void 0, children: [
|
|
1408
1581
|
/* @__PURE__ */ jsxs(
|
|
1409
1582
|
"button",
|
|
@@ -1413,11 +1586,11 @@ function NextRow(props) {
|
|
|
1413
1586
|
"aria-expanded": expanded,
|
|
1414
1587
|
className: "flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50 sm:px-6",
|
|
1415
1588
|
children: [
|
|
1416
|
-
/* @__PURE__ */ jsx(Accent, { className: "w-5 shrink-0 text-xs font-medium tabular-nums", children: String(props.rank).padStart(2, "0") }),
|
|
1417
1589
|
/* @__PURE__ */ jsx(UnreadDot, { visible: unread }),
|
|
1590
|
+
/* @__PURE__ */ jsx("span", { className: "w-5 shrink-0", style: { opacity: rankOpacity }, children: /* @__PURE__ */ jsx(Accent, { className: "text-xs font-medium tabular-nums", children: String(props.rank).padStart(2, "0") }) }),
|
|
1418
1591
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1419
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
1420
|
-
secondaryText ? /* @__PURE__ */ jsx("div", { className: "
|
|
1592
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium leading-5 text-foreground", children: renderTitle(frame) }),
|
|
1593
|
+
secondaryText ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 max-w-3xl text-xs leading-5 text-muted-foreground", children: secondaryText }) : null
|
|
1421
1594
|
] }),
|
|
1422
1595
|
/* @__PURE__ */ jsx(QueueMovementBadge, { movement: props.movement }),
|
|
1423
1596
|
driver ? /* @__PURE__ */ jsx(Badge, { className: cn("shrink-0", driverBadge.className), style: driverBadge.style, children: driver }) : null,
|
|
@@ -1435,7 +1608,7 @@ function NextRow(props) {
|
|
|
1435
1608
|
]
|
|
1436
1609
|
}
|
|
1437
1610
|
),
|
|
1438
|
-
expanded ? /* @__PURE__ */ jsxs("div", { className: "space-y-3 px-4 pb-
|
|
1611
|
+
expanded ? /* @__PURE__ */ jsxs("div", { className: "space-y-3 px-4 pb-4 pl-12 sm:px-6 sm:pl-14", children: [
|
|
1439
1612
|
showDetailText ? /* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: detailText }) : null,
|
|
1440
1613
|
/* @__PURE__ */ jsx(ExplainabilityStrip, { frame, lane: "queued" }),
|
|
1441
1614
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted-foreground", children: [
|
|
@@ -1463,19 +1636,21 @@ function NextRow(props) {
|
|
|
1463
1636
|
}
|
|
1464
1637
|
) : null
|
|
1465
1638
|
] }),
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1639
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 pt-1", children: [
|
|
1640
|
+
/* @__PURE__ */ jsx(IssueCommentComposer, { frame, pendingId: props.pendingId, onComment: props.onComment }),
|
|
1641
|
+
/* @__PURE__ */ jsx(
|
|
1642
|
+
FrameActions,
|
|
1643
|
+
{
|
|
1644
|
+
frame,
|
|
1645
|
+
lane: "queued",
|
|
1646
|
+
pendingId: props.pendingId,
|
|
1647
|
+
onApprove: props.onApprove,
|
|
1648
|
+
onReject: props.onReject,
|
|
1649
|
+
onRequestRevision: props.onRequestRevision,
|
|
1650
|
+
onAcknowledge: props.onAcknowledge
|
|
1651
|
+
}
|
|
1652
|
+
)
|
|
1653
|
+
] })
|
|
1479
1654
|
] }) : null
|
|
1480
1655
|
] });
|
|
1481
1656
|
}
|
|
@@ -1504,65 +1679,23 @@ function NextLane(props) {
|
|
|
1504
1679
|
}
|
|
1505
1680
|
function AmbientRow(props) {
|
|
1506
1681
|
const { frame, snapshotUpdatedAt } = props;
|
|
1507
|
-
const [expanded, setExpanded] = useState(false);
|
|
1508
1682
|
const href = itemHref(frame, props.companyPrefix);
|
|
1509
1683
|
const unread = isFrameUnreadInSnapshot(frame, props.snapshot);
|
|
1510
|
-
const
|
|
1511
|
-
|
|
1512
|
-
/* @__PURE__ */
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
type: "button",
|
|
1516
|
-
onClick: () => setExpanded(!expanded),
|
|
1517
|
-
"aria-expanded": expanded,
|
|
1518
|
-
className: "flex w-full items-center gap-3 px-4 py-2.5 text-left transition-colors hover:bg-accent/50 sm:px-6",
|
|
1519
|
-
children: [
|
|
1520
|
-
/* @__PURE__ */ jsx(UnreadDot, { visible: unread }),
|
|
1521
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-sm text-muted-foreground/80", children: renderTitle(frame) }),
|
|
1522
|
-
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground", style: { opacity: 0.6 }, children: sourceLabel(frame) }),
|
|
1523
|
-
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground", style: { opacity: 0.55 }, children: formatRelativeTime(frameUpdatedAt(frame, snapshotUpdatedAt)) }),
|
|
1524
|
-
/* @__PURE__ */ jsx(
|
|
1525
|
-
"svg",
|
|
1526
|
-
{
|
|
1527
|
-
viewBox: "0 0 16 16",
|
|
1528
|
-
className: cn("h-3 w-3 shrink-0 text-muted-foreground transition-transform", expanded && "rotate-90"),
|
|
1529
|
-
fill: "currentColor",
|
|
1530
|
-
style: { opacity: 0.75 },
|
|
1531
|
-
"aria-hidden": "true",
|
|
1532
|
-
children: /* @__PURE__ */ jsx("path", { d: "M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L9.94 8 6.22 4.28a.75.75 0 0 1 0-1.06Z" })
|
|
1533
|
-
}
|
|
1534
|
-
)
|
|
1535
|
-
]
|
|
1536
|
-
}
|
|
1537
|
-
),
|
|
1538
|
-
expanded ? /* @__PURE__ */ jsxs("div", { className: "space-y-3 px-4 pb-3 sm:px-6", children: [
|
|
1539
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: frame.summary ?? judgmentLine(frame, "ambient") }),
|
|
1540
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1541
|
-
href ? /* @__PURE__ */ jsx(
|
|
1542
|
-
"a",
|
|
1543
|
-
{
|
|
1544
|
-
href,
|
|
1545
|
-
className: "text-xs font-medium underline underline-offset-2 text-muted-foreground hover:text-foreground",
|
|
1546
|
-
children: primaryLinkLabel(frame)
|
|
1547
|
-
}
|
|
1548
|
-
) : null,
|
|
1549
|
-
activityLink ? /* @__PURE__ */ jsx(
|
|
1550
|
-
"a",
|
|
1551
|
-
{
|
|
1552
|
-
href: activityLink,
|
|
1553
|
-
className: "text-xs font-medium underline underline-offset-2 text-muted-foreground hover:text-foreground",
|
|
1554
|
-
children: "Open activity"
|
|
1555
|
-
}
|
|
1556
|
-
) : null,
|
|
1557
|
-
/* @__PURE__ */ jsx("span", { className: "ml-auto text-xs uppercase tracking-[0.16em] text-muted-foreground/60", children: "Awareness only" })
|
|
1558
|
-
] })
|
|
1559
|
-
] }) : null
|
|
1684
|
+
const content = /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-2.5 sm:px-6", children: [
|
|
1685
|
+
/* @__PURE__ */ jsx(UnreadDot, { visible: unread, tone: "muted", reserveSpace: true }),
|
|
1686
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-[13px] text-muted-foreground", children: renderTitle(frame) }),
|
|
1687
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground/80", children: sourceLabel(frame) }),
|
|
1688
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground/70", children: formatRelativeTime(frameUpdatedAt(frame, snapshotUpdatedAt)) })
|
|
1560
1689
|
] });
|
|
1690
|
+
return /* @__PURE__ */ jsx("div", { style: { borderBottomWidth: 1, borderBottomColor: "var(--border)" }, className: "last:border-b-0", children: href ? /* @__PURE__ */ jsx("a", { href, className: "block transition-colors hover:bg-accent/40", children: content }) : content });
|
|
1561
1691
|
}
|
|
1562
1692
|
function AmbientLane(props) {
|
|
1563
|
-
return /* @__PURE__ */ jsxs("section", { style: { borderWidth: 1, borderColor: "var(--border)" }, className: "bg-card", "aria-label": "Ambient attention", children: [
|
|
1564
|
-
/* @__PURE__ */ jsx("div", { style: { borderBottomWidth: 1, borderBottomColor: "var(--border)" }, className: "px-4 py-2.5 sm:px-6", children: /* @__PURE__ */ jsx("h2", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground",
|
|
1565
|
-
props.rows.length === 0 ? /* @__PURE__ */
|
|
1693
|
+
return /* @__PURE__ */ jsxs("section", { style: { borderWidth: 1, borderColor: "var(--border)" }, className: "mt-2 bg-card", "aria-label": "Ambient attention", children: [
|
|
1694
|
+
/* @__PURE__ */ jsx("div", { style: { borderBottomWidth: 1, borderBottomColor: "var(--border)" }, className: "px-4 py-2.5 sm:px-6", children: /* @__PURE__ */ jsx("h2", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground/80", children: "Ambient" }) }),
|
|
1695
|
+
props.rows.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-4 text-sm text-muted-foreground sm:px-6", children: [
|
|
1696
|
+
/* @__PURE__ */ jsx(QuietMark, {}),
|
|
1697
|
+
/* @__PURE__ */ jsx("span", { children: "Nothing in peripheral view." })
|
|
1698
|
+
] }) : props.rows.map((row) => /* @__PURE__ */ jsx(
|
|
1566
1699
|
AmbientRow,
|
|
1567
1700
|
{
|
|
1568
1701
|
frame: row.frame,
|
|
@@ -1577,6 +1710,7 @@ function AmbientLane(props) {
|
|
|
1577
1710
|
function DashboardWidget(props) {
|
|
1578
1711
|
const companyId = props.context.companyId;
|
|
1579
1712
|
const brand = currentSurfaceBrand();
|
|
1713
|
+
const href = pluginPagePath(props.context.companyPrefix);
|
|
1580
1714
|
const model = useAttentionModel(companyId);
|
|
1581
1715
|
const data = model.snapshot;
|
|
1582
1716
|
const loading = model.loading;
|
|
@@ -1586,20 +1720,19 @@ function DashboardWidget(props) {
|
|
|
1586
1720
|
if (error) return /* @__PURE__ */ jsx(MessageCard, { title: "Plugin error", body: error.message });
|
|
1587
1721
|
if (!data) return /* @__PURE__ */ jsx(MessageCard, { title: brand.wordmark, body: brand.headingEmptyState });
|
|
1588
1722
|
const posture = postureForSnapshot(data);
|
|
1589
|
-
|
|
1723
|
+
const leadingText = data.active ? recommendedMoveValue(data.active) ?? data.active.title : null;
|
|
1724
|
+
const borderStyle = posture.label === "busy" ? { borderLeftWidth: 2, borderLeftColor: ACCENT_COLOR } : posture.label === "elevated" ? { borderLeftWidth: 2, borderLeftColor: ACCENT_BORDER } : void 0;
|
|
1725
|
+
return /* @__PURE__ */ jsxs("a", { href, className: "block border border-border bg-card px-4 py-3 shadow-sm transition-colors hover:bg-accent/40", style: borderStyle, children: [
|
|
1590
1726
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs", children: [
|
|
1591
1727
|
/* @__PURE__ */ jsx(Accent, { className: "pt-0.5 text-sm", children: posture.glyph }),
|
|
1592
|
-
/* @__PURE__ */
|
|
1593
|
-
/* @__PURE__ */
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
] }),
|
|
1601
|
-
/* @__PURE__ */ jsx("div", { className: "mt-0.5 text-[10px] leading-none text-muted-foreground/60", children: brand.supportCopy })
|
|
1602
|
-
] }),
|
|
1728
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
|
|
1729
|
+
/* @__PURE__ */ jsx(Accent, { className: "font-semibold tracking-[0.04em]", children: brand.wordmark }),
|
|
1730
|
+
/* @__PURE__ */ jsx(Accent, { className: "text-[11px]", children: posture.label }),
|
|
1731
|
+
unreadCount(data) > 0 ? /* @__PURE__ */ jsxs(Accent, { className: "text-[11px]", children: [
|
|
1732
|
+
"new ",
|
|
1733
|
+
unreadCount(data)
|
|
1734
|
+
] }) : null
|
|
1735
|
+
] }) }),
|
|
1603
1736
|
/* @__PURE__ */ jsxs("span", { className: "ml-auto tabular-nums text-muted-foreground", children: [
|
|
1604
1737
|
"now ",
|
|
1605
1738
|
data.counts.active,
|
|
@@ -1609,7 +1742,19 @@ function DashboardWidget(props) {
|
|
|
1609
1742
|
data.counts.ambient
|
|
1610
1743
|
] })
|
|
1611
1744
|
] }),
|
|
1612
|
-
|
|
1745
|
+
leadingText ? /* @__PURE__ */ jsx(
|
|
1746
|
+
"div",
|
|
1747
|
+
{
|
|
1748
|
+
className: "mt-2 text-sm font-medium leading-5 text-foreground",
|
|
1749
|
+
style: {
|
|
1750
|
+
display: "-webkit-box",
|
|
1751
|
+
WebkitLineClamp: 2,
|
|
1752
|
+
WebkitBoxOrient: "vertical",
|
|
1753
|
+
overflow: "hidden"
|
|
1754
|
+
},
|
|
1755
|
+
children: leadingText
|
|
1756
|
+
}
|
|
1757
|
+
) : /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm text-muted-foreground", children: "No active interruption right now." })
|
|
1613
1758
|
] });
|
|
1614
1759
|
}
|
|
1615
1760
|
function AttentionSidebarLink({ context }) {
|
|
@@ -1653,7 +1798,14 @@ function AttentionSidebarLink({ context }) {
|
|
|
1653
1798
|
}
|
|
1654
1799
|
) }),
|
|
1655
1800
|
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: brand.wordmark }),
|
|
1656
|
-
unread > 0 || actionable > 0 ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center justify-center rounded-full px-1.5 py-0.5 text-xs leading-none font-medium text-white", style: ACCENT_BG_STYLE, children: unread
|
|
1801
|
+
unread > 0 || actionable > 0 ? unread > 0 ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center justify-center rounded-full px-1.5 py-0.5 text-xs leading-none font-medium text-white", style: ACCENT_BG_STYLE, children: unread }) : /* @__PURE__ */ jsx(
|
|
1802
|
+
"span",
|
|
1803
|
+
{
|
|
1804
|
+
className: "inline-flex items-center justify-center rounded-full border px-1.5 py-0.5 text-xs leading-none font-medium",
|
|
1805
|
+
style: { color: ACCENT_COLOR, borderColor: ACCENT_BORDER, backgroundColor: "transparent" },
|
|
1806
|
+
children: actionable
|
|
1807
|
+
}
|
|
1808
|
+
) : null
|
|
1657
1809
|
]
|
|
1658
1810
|
}
|
|
1659
1811
|
);
|
|
@@ -1848,7 +2000,7 @@ function AttentionPage(props) {
|
|
|
1848
2000
|
}
|
|
1849
2001
|
);
|
|
1850
2002
|
}
|
|
1851
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-
|
|
2003
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1852
2004
|
/* @__PURE__ */ jsx(
|
|
1853
2005
|
NowPane,
|
|
1854
2006
|
{
|
package/package.json
CHANGED