@arbidocs/blocks 0.3.142 → 0.3.143
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/{chunk-ETIYX2MO.js → chunk-7ICEOZCE.js} +505 -5
- package/dist/chunk-7ICEOZCE.js.map +1 -0
- package/dist/{chunk-6MFI2HPX.cjs → chunk-YNGRSAGP.cjs} +510 -2
- package/dist/chunk-YNGRSAGP.cjs.map +1 -0
- package/dist/{index-BzrF2JbQ.d.cts → index-CNjUY3Zm.d.cts} +85 -2
- package/dist/{index-BzrF2JbQ.d.ts → index-CNjUY3Zm.d.ts} +85 -2
- package/dist/index.cjs +231 -133
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +69 -3
- package/dist/index.js.map +1 -1
- package/dist/site/index.cjs +85 -53
- package/dist/site/index.d.cts +1 -1
- package/dist/site/index.d.ts +1 -1
- package/dist/site/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-6MFI2HPX.cjs.map +0 -1
- package/dist/chunk-ETIYX2MO.js.map +0 -1
|
@@ -587,6 +587,506 @@ function tid(...parts) {
|
|
|
587
587
|
(p) => String(p).trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "")
|
|
588
588
|
).join("-");
|
|
589
589
|
}
|
|
590
|
+
|
|
591
|
+
// src/timeline/span.ts
|
|
592
|
+
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
593
|
+
var MONTH_NAMES = [
|
|
594
|
+
"January",
|
|
595
|
+
"February",
|
|
596
|
+
"March",
|
|
597
|
+
"April",
|
|
598
|
+
"May",
|
|
599
|
+
"June",
|
|
600
|
+
"July",
|
|
601
|
+
"August",
|
|
602
|
+
"September",
|
|
603
|
+
"October",
|
|
604
|
+
"November",
|
|
605
|
+
"December"
|
|
606
|
+
];
|
|
607
|
+
var WEEKDAY_NAMES = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
608
|
+
var DAY_MS = 864e5;
|
|
609
|
+
function monthLabel(d) {
|
|
610
|
+
return `${MONTH_NAMES[d.getUTCMonth()]} ${d.getUTCFullYear()}`;
|
|
611
|
+
}
|
|
612
|
+
function utcDay(d) {
|
|
613
|
+
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
|
|
614
|
+
}
|
|
615
|
+
function dayKey(d) {
|
|
616
|
+
return d.toISOString().slice(0, 10);
|
|
617
|
+
}
|
|
618
|
+
function parseIso2(iso) {
|
|
619
|
+
if (!iso) return null;
|
|
620
|
+
const d = new Date(iso);
|
|
621
|
+
return isNaN(d.getTime()) ? null : d;
|
|
622
|
+
}
|
|
623
|
+
function isMidnight(d) {
|
|
624
|
+
return d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0;
|
|
625
|
+
}
|
|
626
|
+
function isEndOfDay(d) {
|
|
627
|
+
return d.getUTCHours() === 23 && d.getUTCMinutes() === 59;
|
|
628
|
+
}
|
|
629
|
+
function lastDayOfMonth(d) {
|
|
630
|
+
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0)).getUTCDate();
|
|
631
|
+
}
|
|
632
|
+
function day(d) {
|
|
633
|
+
return `${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]} ${d.getUTCFullYear()}`;
|
|
634
|
+
}
|
|
635
|
+
function formatSpan(startIso, endIso) {
|
|
636
|
+
if (!startIso) return "";
|
|
637
|
+
const start = new Date(startIso);
|
|
638
|
+
const end = endIso ? new Date(endIso) : start;
|
|
639
|
+
if (startIso === endIso) {
|
|
640
|
+
const hh = String(start.getUTCHours()).padStart(2, "0");
|
|
641
|
+
const mm = String(start.getUTCMinutes()).padStart(2, "0");
|
|
642
|
+
return `${day(start)}, ${hh}:${mm} UTC`;
|
|
643
|
+
}
|
|
644
|
+
if (isMidnight(start) && isEndOfDay(end)) {
|
|
645
|
+
const sameDay = start.getUTCFullYear() === end.getUTCFullYear() && start.getUTCMonth() === end.getUTCMonth() && start.getUTCDate() === end.getUTCDate();
|
|
646
|
+
if (sameDay) return day(start);
|
|
647
|
+
const firstOfMonth = start.getUTCDate() === 1;
|
|
648
|
+
const endsMonth = end.getUTCDate() === lastDayOfMonth(end);
|
|
649
|
+
const sameMonth = start.getUTCFullYear() === end.getUTCFullYear() && start.getUTCMonth() === end.getUTCMonth();
|
|
650
|
+
if (firstOfMonth && endsMonth && sameMonth) {
|
|
651
|
+
return `${MONTHS[start.getUTCMonth()]} ${start.getUTCFullYear()}`;
|
|
652
|
+
}
|
|
653
|
+
const wholeYear = firstOfMonth && endsMonth && start.getUTCMonth() === 0 && end.getUTCMonth() === 11 && start.getUTCFullYear() === end.getUTCFullYear();
|
|
654
|
+
if (wholeYear) return String(start.getUTCFullYear());
|
|
655
|
+
return `${day(start)} \u2013 ${day(end)}`;
|
|
656
|
+
}
|
|
657
|
+
return `${day(start)} \u2013 ${day(end)}`;
|
|
658
|
+
}
|
|
659
|
+
var DEFAULT_MAX_LANES = 3;
|
|
660
|
+
var MAX_WEEKS = 520;
|
|
661
|
+
function isPrecise(item) {
|
|
662
|
+
if (!item.start || !item.end) return false;
|
|
663
|
+
return item.start.slice(0, 10) === item.end.slice(0, 10);
|
|
664
|
+
}
|
|
665
|
+
function TimelineCalendar({
|
|
666
|
+
items,
|
|
667
|
+
onSelect,
|
|
668
|
+
maxLanes = DEFAULT_MAX_LANES,
|
|
669
|
+
emptyState,
|
|
670
|
+
className,
|
|
671
|
+
testId = "timeline-calendar"
|
|
672
|
+
}) {
|
|
673
|
+
const dated = react.useMemo(() => items.filter((i) => i.start), [items]);
|
|
674
|
+
const weeks = react.useMemo(() => {
|
|
675
|
+
if (dated.length === 0) return [];
|
|
676
|
+
const times = dated.flatMap((i) => [
|
|
677
|
+
new Date(i.start).getTime(),
|
|
678
|
+
new Date(i.end ?? i.start).getTime()
|
|
679
|
+
]);
|
|
680
|
+
const first = utcDay(new Date(Math.min(...times)));
|
|
681
|
+
const last = utcDay(new Date(Math.max(...times)));
|
|
682
|
+
const gridStart = new Date(first);
|
|
683
|
+
gridStart.setUTCDate(first.getUTCDate() - (first.getUTCDay() + 6) % 7);
|
|
684
|
+
const out = [];
|
|
685
|
+
const cursor = new Date(gridStart);
|
|
686
|
+
while (cursor <= last && out.length < MAX_WEEKS) {
|
|
687
|
+
out.push(
|
|
688
|
+
Array.from({ length: 7 }, (_, d) => {
|
|
689
|
+
const day2 = new Date(cursor);
|
|
690
|
+
day2.setUTCDate(cursor.getUTCDate() + d);
|
|
691
|
+
return day2;
|
|
692
|
+
})
|
|
693
|
+
);
|
|
694
|
+
cursor.setUTCDate(cursor.getUTCDate() + 7);
|
|
695
|
+
}
|
|
696
|
+
return out;
|
|
697
|
+
}, [dated]);
|
|
698
|
+
const segmentsByWeek = react.useMemo(() => {
|
|
699
|
+
return weeks.map((week) => {
|
|
700
|
+
const weekStart = week[0];
|
|
701
|
+
const weekEnd = week[6];
|
|
702
|
+
const overlapping = dated.map((item) => ({
|
|
703
|
+
item,
|
|
704
|
+
start: utcDay(new Date(item.start)),
|
|
705
|
+
end: utcDay(new Date(item.end ?? item.start))
|
|
706
|
+
})).filter(({ start, end }) => start <= weekEnd && end >= weekStart).sort((a, b) => {
|
|
707
|
+
const lenA = b.end.getTime() - b.start.getTime();
|
|
708
|
+
const lenB = a.end.getTime() - a.start.getTime();
|
|
709
|
+
return lenA - lenB || a.start.getTime() - b.start.getTime();
|
|
710
|
+
});
|
|
711
|
+
const laneEnds = [];
|
|
712
|
+
const segments = [];
|
|
713
|
+
let overflow = 0;
|
|
714
|
+
for (const { item, start, end } of overlapping) {
|
|
715
|
+
const from = start < weekStart ? weekStart : start;
|
|
716
|
+
const to = end > weekEnd ? weekEnd : end;
|
|
717
|
+
const startCol = Math.round((from.getTime() - weekStart.getTime()) / DAY_MS);
|
|
718
|
+
const endCol = Math.round((to.getTime() - weekStart.getTime()) / DAY_MS);
|
|
719
|
+
let lane = laneEnds.findIndex((last) => last < startCol);
|
|
720
|
+
if (lane === -1) lane = laneEnds.length;
|
|
721
|
+
if (lane >= maxLanes) {
|
|
722
|
+
overflow += 1;
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
laneEnds[lane] = endCol;
|
|
726
|
+
segments.push({
|
|
727
|
+
item,
|
|
728
|
+
startCol,
|
|
729
|
+
span: endCol - startCol + 1,
|
|
730
|
+
isStart: start >= weekStart,
|
|
731
|
+
isEnd: end <= weekEnd,
|
|
732
|
+
lane
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
return { segments, overflow };
|
|
736
|
+
});
|
|
737
|
+
}, [weeks, dated, maxLanes]);
|
|
738
|
+
if (weeks.length === 0 && emptyState) {
|
|
739
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: emptyState });
|
|
740
|
+
}
|
|
741
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-col h-full", className), "data-testid": testId, children: [
|
|
742
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 border-b border-border bg-background", children: WEEKDAY_NAMES.map((d) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1 text-[11px] text-muted-foreground text-center", children: d }, d)) }),
|
|
743
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", "data-testid": `${testId}-scroll`, children: weeks.map((week, wi) => {
|
|
744
|
+
const { segments, overflow } = segmentsByWeek[wi];
|
|
745
|
+
const monthStartDay = week.find((d) => d.getUTCDate() === 1);
|
|
746
|
+
const marker = monthStartDay ?? (wi === 0 ? week[0] : void 0);
|
|
747
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
748
|
+
marker && // Sticky, so the month you are LOOKING at names itself: it
|
|
749
|
+
// pins to the top of the scroller while you are inside it and
|
|
750
|
+
// is pushed up by the next one. No scroll listener needed.
|
|
751
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
752
|
+
"div",
|
|
753
|
+
{
|
|
754
|
+
className: "sticky top-0 z-10 px-3 py-1 text-xs font-medium text-foreground bg-background/95 backdrop-blur border-y border-border/60",
|
|
755
|
+
"data-testid": `${testId}-month-${marker.getUTCFullYear()}-${String(
|
|
756
|
+
marker.getUTCMonth() + 1
|
|
757
|
+
).padStart(2, "0")}`,
|
|
758
|
+
children: monthLabel(marker)
|
|
759
|
+
}
|
|
760
|
+
),
|
|
761
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border/40", children: [
|
|
762
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 bg-background", children: week.map((day2) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
763
|
+
"div",
|
|
764
|
+
{
|
|
765
|
+
"data-testid": `${testId}-day-${dayKey(day2)}`,
|
|
766
|
+
className: ui.cn(
|
|
767
|
+
"px-1 pt-1 text-[11px] border-r border-border/40",
|
|
768
|
+
day2.getUTCDate() === 1 ? "text-foreground font-medium" : "text-muted-foreground/60"
|
|
769
|
+
),
|
|
770
|
+
children: day2.getUTCDate()
|
|
771
|
+
},
|
|
772
|
+
dayKey(day2)
|
|
773
|
+
)) }),
|
|
774
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
775
|
+
"div",
|
|
776
|
+
{
|
|
777
|
+
className: "grid grid-cols-7 gap-y-0.5 px-0.5 pb-1 bg-muted/40",
|
|
778
|
+
style: { gridAutoRows: "minmax(18px, auto)", minHeight: 62 },
|
|
779
|
+
children: [
|
|
780
|
+
segments.map((seg) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
781
|
+
"button",
|
|
782
|
+
{
|
|
783
|
+
type: "button",
|
|
784
|
+
onClick: () => onSelect?.(seg.item),
|
|
785
|
+
title: `${formatSpan(seg.item.start, seg.item.end)} \u2014 ${seg.item.label}`,
|
|
786
|
+
"data-testid": `${testId}-entry-${seg.item.id}`,
|
|
787
|
+
style: {
|
|
788
|
+
gridColumn: `${seg.startCol + 1} / span ${seg.span}`,
|
|
789
|
+
gridRow: seg.lane + 1
|
|
790
|
+
},
|
|
791
|
+
className: ui.cn(
|
|
792
|
+
"text-left text-[10px] leading-[13px] py-[2px] px-1 min-h-[18px] whitespace-normal break-words line-clamp-3",
|
|
793
|
+
isPrecise(seg.item) ? "bg-primary/20 text-foreground" : "bg-muted text-muted-foreground",
|
|
794
|
+
seg.isStart && "rounded-l",
|
|
795
|
+
seg.isEnd && "rounded-r"
|
|
796
|
+
),
|
|
797
|
+
children: seg.isStart ? seg.item.label : " "
|
|
798
|
+
},
|
|
799
|
+
`${seg.item.id}-${seg.startCol}`
|
|
800
|
+
)),
|
|
801
|
+
overflow > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
802
|
+
"span",
|
|
803
|
+
{
|
|
804
|
+
className: "text-[10px] text-muted-foreground px-1",
|
|
805
|
+
style: { gridColumn: "1 / span 7", gridRow: maxLanes + 1 },
|
|
806
|
+
children: [
|
|
807
|
+
"+",
|
|
808
|
+
overflow,
|
|
809
|
+
" more"
|
|
810
|
+
]
|
|
811
|
+
}
|
|
812
|
+
)
|
|
813
|
+
]
|
|
814
|
+
}
|
|
815
|
+
)
|
|
816
|
+
] })
|
|
817
|
+
] }, dayKey(week[0]));
|
|
818
|
+
}) })
|
|
819
|
+
] });
|
|
820
|
+
}
|
|
821
|
+
var BAR_PALETTE = [
|
|
822
|
+
{
|
|
823
|
+
gradient: "linear-gradient(90deg, #6366f1, #818cf8)",
|
|
824
|
+
shadow: "0 2px 6px rgba(99,102,241,.35)"
|
|
825
|
+
},
|
|
826
|
+
{
|
|
827
|
+
gradient: "linear-gradient(90deg, #8b5cf6, #a78bfa)",
|
|
828
|
+
shadow: "0 2px 6px rgba(139,92,246,.35)"
|
|
829
|
+
},
|
|
830
|
+
{ gradient: "linear-gradient(90deg, #ef4444, #f87171)", shadow: "0 2px 6px rgba(239,68,68,.35)" },
|
|
831
|
+
{
|
|
832
|
+
gradient: "linear-gradient(90deg, #f59e0b, #fbbf24)",
|
|
833
|
+
shadow: "0 2px 6px rgba(245,158,11,.35)"
|
|
834
|
+
},
|
|
835
|
+
{ gradient: "linear-gradient(90deg, #22c55e, #4ade80)", shadow: "0 2px 6px rgba(34,197,94,.35)" },
|
|
836
|
+
{ gradient: "linear-gradient(90deg, #06b6d4, #22d3ee)", shadow: "0 2px 6px rgba(6,182,212,.35)" }
|
|
837
|
+
];
|
|
838
|
+
var WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
839
|
+
function formatAxisDate(d) {
|
|
840
|
+
return d.toLocaleDateString("en-US", { month: "short", year: "numeric" });
|
|
841
|
+
}
|
|
842
|
+
function formatBarLabel(start, end) {
|
|
843
|
+
const fmt = (d) => d.toLocaleDateString("en-US", { month: "short", year: "2-digit" });
|
|
844
|
+
if (start.getTime() === end.getTime()) return fmt(start);
|
|
845
|
+
return `${fmt(start)} \u2013 ${fmt(end)}`;
|
|
846
|
+
}
|
|
847
|
+
function TimelineGantt({
|
|
848
|
+
items,
|
|
849
|
+
onSelect,
|
|
850
|
+
renderDetail,
|
|
851
|
+
labelWidth = 240,
|
|
852
|
+
emptyMessage = "Nothing dated yet.",
|
|
853
|
+
className,
|
|
854
|
+
testId = "timeline-gantt"
|
|
855
|
+
}) {
|
|
856
|
+
const [activeIndex, setActiveIndex] = react.useState(null);
|
|
857
|
+
const rows = items.filter((i) => parseIso2(i.start) !== null).slice().sort((a, b) => parseIso2(a.start).getTime() - parseIso2(b.start).getTime());
|
|
858
|
+
if (rows.length === 0) {
|
|
859
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
860
|
+
"div",
|
|
861
|
+
{
|
|
862
|
+
"data-testid": `${testId}-empty-state`,
|
|
863
|
+
className: ui.cn(
|
|
864
|
+
"flex flex-col items-center justify-center py-16 text-muted-foreground",
|
|
865
|
+
className
|
|
866
|
+
),
|
|
867
|
+
children: [
|
|
868
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "w-12 h-12 mb-3 opacity-30" }),
|
|
869
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: emptyMessage })
|
|
870
|
+
]
|
|
871
|
+
}
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
const allDates = rows.flatMap((i) => {
|
|
875
|
+
const s = parseIso2(i.start);
|
|
876
|
+
return [s, parseIso2(i.end ?? null) ?? s];
|
|
877
|
+
});
|
|
878
|
+
const minTime = Math.min(...allDates.map((d) => d.getTime()));
|
|
879
|
+
const maxTime = Math.max(...allDates.map((d) => d.getTime()));
|
|
880
|
+
const pad = Math.max((maxTime - minTime) * 0.04, WEEK_MS);
|
|
881
|
+
const axisMin = new Date(minTime - pad);
|
|
882
|
+
const axisMax = new Date(maxTime + pad);
|
|
883
|
+
const axisRange = axisMax.getTime() - axisMin.getTime();
|
|
884
|
+
const toPercent = (d) => Math.min(100, Math.max(0, (d.getTime() - axisMin.getTime()) / axisRange * 100));
|
|
885
|
+
const ticks = Array.from(
|
|
886
|
+
{ length: 5 },
|
|
887
|
+
(_, i) => new Date(axisMin.getTime() + axisRange * i / 4)
|
|
888
|
+
);
|
|
889
|
+
const today = /* @__PURE__ */ new Date();
|
|
890
|
+
const todayPct = toPercent(today);
|
|
891
|
+
const showToday = today > axisMin && today < axisMax;
|
|
892
|
+
const activeItem = activeIndex !== null ? rows[activeIndex] : null;
|
|
893
|
+
const detail = activeItem ? renderDetail?.(activeItem) : null;
|
|
894
|
+
const select = (index) => {
|
|
895
|
+
setActiveIndex(index);
|
|
896
|
+
onSelect?.(index === null ? null : rows[index]);
|
|
897
|
+
};
|
|
898
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex h-full min-h-0", className), children: [
|
|
899
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0 p-5 overflow-x-auto", children: [
|
|
900
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex mb-1", children: [
|
|
901
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
902
|
+
"div",
|
|
903
|
+
{
|
|
904
|
+
style: { width: labelWidth, flexShrink: 0 },
|
|
905
|
+
className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground pb-1",
|
|
906
|
+
children: "Event"
|
|
907
|
+
}
|
|
908
|
+
),
|
|
909
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 relative h-6 border-b border-border", children: ticks.map((tick, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
910
|
+
"span",
|
|
911
|
+
{
|
|
912
|
+
style: { left: `${toPercent(tick)}%` },
|
|
913
|
+
className: "absolute bottom-1 text-[10px] text-muted-foreground -translate-x-1/2 whitespace-nowrap select-none",
|
|
914
|
+
children: formatAxisDate(tick)
|
|
915
|
+
},
|
|
916
|
+
i
|
|
917
|
+
)) })
|
|
918
|
+
] }),
|
|
919
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative mt-2", children: [
|
|
920
|
+
showToday && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
921
|
+
"div",
|
|
922
|
+
{
|
|
923
|
+
className: "absolute top-0 bottom-0 pointer-events-none z-10",
|
|
924
|
+
style: {
|
|
925
|
+
left: `calc(${labelWidth}px + (100% - ${labelWidth}px) * ${todayPct / 100})`
|
|
926
|
+
},
|
|
927
|
+
children: [
|
|
928
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border-l-2 border-dashed border-muted-foreground/50" }),
|
|
929
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-5 -translate-x-1/2 text-[9px] text-muted-foreground bg-background border rounded px-1", children: "today" })
|
|
930
|
+
]
|
|
931
|
+
}
|
|
932
|
+
),
|
|
933
|
+
rows.map((item, i) => {
|
|
934
|
+
const startDate = parseIso2(item.start);
|
|
935
|
+
const endDate = parseIso2(item.end ?? null) ?? startDate;
|
|
936
|
+
const leftPct = toPercent(startDate);
|
|
937
|
+
const widthPct = Math.max(1, toPercent(endDate) - toPercent(startDate));
|
|
938
|
+
const color = BAR_PALETTE[i % BAR_PALETTE.length];
|
|
939
|
+
const isActive = activeIndex === i;
|
|
940
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center mb-2", children: [
|
|
941
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
942
|
+
"div",
|
|
943
|
+
{
|
|
944
|
+
style: { width: labelWidth, flexShrink: 0 },
|
|
945
|
+
className: "text-xs font-medium text-muted-foreground pr-3 break-words leading-snug",
|
|
946
|
+
children: item.label
|
|
947
|
+
}
|
|
948
|
+
),
|
|
949
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 h-7 bg-muted/30 border border-border rounded-md relative overflow-visible", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
950
|
+
"button",
|
|
951
|
+
{
|
|
952
|
+
"data-testid": `${testId}-bar-${i}`,
|
|
953
|
+
"aria-label": item.label,
|
|
954
|
+
"aria-pressed": isActive,
|
|
955
|
+
style: {
|
|
956
|
+
left: `${leftPct}%`,
|
|
957
|
+
width: `${widthPct}%`,
|
|
958
|
+
background: color.gradient,
|
|
959
|
+
boxShadow: isActive ? "0 0 0 2px white, 0 0 0 4px #6366f1" : color.shadow
|
|
960
|
+
},
|
|
961
|
+
className: "absolute top-0.5 h-6 rounded text-white text-[9px] font-semibold px-2 overflow-hidden whitespace-nowrap cursor-pointer transition-[filter] hover:brightness-110 focus:outline-none",
|
|
962
|
+
onClick: () => select(isActive ? null : i),
|
|
963
|
+
children: formatBarLabel(startDate, endDate)
|
|
964
|
+
}
|
|
965
|
+
) })
|
|
966
|
+
] }, item.id);
|
|
967
|
+
})
|
|
968
|
+
] })
|
|
969
|
+
] }),
|
|
970
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
971
|
+
"div",
|
|
972
|
+
{
|
|
973
|
+
"data-testid": `${testId}-side-panel`,
|
|
974
|
+
className: ui.cn(
|
|
975
|
+
"border-l bg-muted/20 flex flex-col shrink-0 overflow-hidden transition-all duration-300",
|
|
976
|
+
activeItem ? "w-60 open" : "w-0"
|
|
977
|
+
),
|
|
978
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
979
|
+
"div",
|
|
980
|
+
{
|
|
981
|
+
className: ui.cn(
|
|
982
|
+
"w-60 p-4 flex flex-col gap-3 transition-opacity duration-200",
|
|
983
|
+
activeItem ? "opacity-100" : "opacity-0"
|
|
984
|
+
),
|
|
985
|
+
children: activeItem && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
986
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
987
|
+
"button",
|
|
988
|
+
{
|
|
989
|
+
"data-testid": `${testId}-panel-close`,
|
|
990
|
+
className: "w-6 h-6 rounded flex items-center justify-center text-muted-foreground hover:bg-muted",
|
|
991
|
+
onClick: () => select(null),
|
|
992
|
+
"aria-label": "Close panel",
|
|
993
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5" })
|
|
994
|
+
}
|
|
995
|
+
) }),
|
|
996
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
997
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
998
|
+
"div",
|
|
999
|
+
{
|
|
1000
|
+
"data-testid": `${testId}-panel-title`,
|
|
1001
|
+
className: "text-sm font-semibold text-foreground leading-snug",
|
|
1002
|
+
children: activeItem.label
|
|
1003
|
+
}
|
|
1004
|
+
),
|
|
1005
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 mt-1 text-xs text-muted-foreground", children: [
|
|
1006
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "w-3 h-3 shrink-0" }),
|
|
1007
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatSpan(activeItem.start, activeItem.end) || "Date unknown" })
|
|
1008
|
+
] })
|
|
1009
|
+
] }),
|
|
1010
|
+
activeItem.description && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1011
|
+
/* @__PURE__ */ jsxRuntime.jsx("hr", { className: "border-border" }),
|
|
1012
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1013
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground mb-1", children: "Summary" }),
|
|
1014
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1015
|
+
"p",
|
|
1016
|
+
{
|
|
1017
|
+
"data-testid": `${testId}-panel-desc`,
|
|
1018
|
+
className: "text-xs text-muted-foreground leading-relaxed",
|
|
1019
|
+
children: activeItem.description
|
|
1020
|
+
}
|
|
1021
|
+
)
|
|
1022
|
+
] })
|
|
1023
|
+
] }),
|
|
1024
|
+
detail && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1025
|
+
/* @__PURE__ */ jsxRuntime.jsx("hr", { className: "border-border" }),
|
|
1026
|
+
detail
|
|
1027
|
+
] })
|
|
1028
|
+
] })
|
|
1029
|
+
}
|
|
1030
|
+
)
|
|
1031
|
+
}
|
|
1032
|
+
)
|
|
1033
|
+
] });
|
|
1034
|
+
}
|
|
1035
|
+
var TOGGLE = [
|
|
1036
|
+
{ mode: "calendar", label: "Calendar", Icon: lucideReact.CalendarDays },
|
|
1037
|
+
{ mode: "gantt", label: "Gantt", Icon: lucideReact.GanttChartSquare }
|
|
1038
|
+
];
|
|
1039
|
+
function Timeline({
|
|
1040
|
+
items,
|
|
1041
|
+
view,
|
|
1042
|
+
defaultView = "calendar",
|
|
1043
|
+
onSelect,
|
|
1044
|
+
renderDetail,
|
|
1045
|
+
emptyMessage,
|
|
1046
|
+
className,
|
|
1047
|
+
testId = "timeline"
|
|
1048
|
+
}) {
|
|
1049
|
+
const [picked, setPicked] = react.useState(defaultView);
|
|
1050
|
+
const mode = view ?? picked;
|
|
1051
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-col h-full min-h-0", className), "data-testid": testId, children: [
|
|
1052
|
+
!view && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 p-2 border-b border-border", children: TOGGLE.map(({ mode: m, label, Icon }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1053
|
+
"button",
|
|
1054
|
+
{
|
|
1055
|
+
type: "button",
|
|
1056
|
+
onClick: () => setPicked(m),
|
|
1057
|
+
"aria-pressed": mode === m,
|
|
1058
|
+
"data-testid": `${testId}-view-${m}`,
|
|
1059
|
+
className: ui.cn(
|
|
1060
|
+
"flex items-center gap-1.5 rounded px-2 py-1 text-xs",
|
|
1061
|
+
mode === m ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground"
|
|
1062
|
+
),
|
|
1063
|
+
children: [
|
|
1064
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-3.5 h-3.5" }),
|
|
1065
|
+
label
|
|
1066
|
+
]
|
|
1067
|
+
},
|
|
1068
|
+
m
|
|
1069
|
+
)) }),
|
|
1070
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: mode === "calendar" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1071
|
+
TimelineCalendar,
|
|
1072
|
+
{
|
|
1073
|
+
items,
|
|
1074
|
+
onSelect,
|
|
1075
|
+
testId: `${testId}-calendar`,
|
|
1076
|
+
emptyState: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center p-8 text-sm text-muted-foreground", children: emptyMessage ?? "Nothing dated yet." })
|
|
1077
|
+
}
|
|
1078
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1079
|
+
TimelineGantt,
|
|
1080
|
+
{
|
|
1081
|
+
items,
|
|
1082
|
+
onSelect: (item) => item && onSelect?.(item),
|
|
1083
|
+
renderDetail,
|
|
1084
|
+
emptyMessage,
|
|
1085
|
+
testId: `${testId}-gantt`
|
|
1086
|
+
}
|
|
1087
|
+
) })
|
|
1088
|
+
] });
|
|
1089
|
+
}
|
|
590
1090
|
function SectionHeading({
|
|
591
1091
|
eyebrow,
|
|
592
1092
|
title,
|
|
@@ -1527,6 +2027,9 @@ exports.TeamGrid = TeamGrid;
|
|
|
1527
2027
|
exports.Testimonial = Testimonial;
|
|
1528
2028
|
exports.TestimonialGrid = TestimonialGrid;
|
|
1529
2029
|
exports.ThemeEditor = ThemeEditor;
|
|
2030
|
+
exports.Timeline = Timeline;
|
|
2031
|
+
exports.TimelineCalendar = TimelineCalendar;
|
|
2032
|
+
exports.TimelineGantt = TimelineGantt;
|
|
1530
2033
|
exports.VideoEmbed = VideoEmbed;
|
|
1531
2034
|
exports.applyFontVars = applyFontVars;
|
|
1532
2035
|
exports.applyStoredTheme = applyStoredTheme;
|
|
@@ -1536,11 +2039,13 @@ exports.assetRefId = assetRefId;
|
|
|
1536
2039
|
exports.clearFontVars = clearFontVars;
|
|
1537
2040
|
exports.clearThemeVars = clearThemeVars;
|
|
1538
2041
|
exports.createThemeStore = createThemeStore;
|
|
2042
|
+
exports.dayKey = dayKey;
|
|
1539
2043
|
exports.daysUntil = daysUntil;
|
|
1540
2044
|
exports.fmtDate = fmtDate;
|
|
1541
2045
|
exports.fmtDateTime = fmtDateTime;
|
|
1542
2046
|
exports.fontPackages = fontPackages;
|
|
1543
2047
|
exports.formatPageRefs = formatPageRefs;
|
|
2048
|
+
exports.formatSpan = formatSpan;
|
|
1544
2049
|
exports.fromNow = fromNow;
|
|
1545
2050
|
exports.gbp = gbp;
|
|
1546
2051
|
exports.getFontPairing = getFontPairing;
|
|
@@ -1548,11 +2053,14 @@ exports.hrs = hrs;
|
|
|
1548
2053
|
exports.initials = initials;
|
|
1549
2054
|
exports.isAssetRef = isAssetRef;
|
|
1550
2055
|
exports.matchFontPairing = matchFontPairing;
|
|
2056
|
+
exports.monthLabel = monthLabel;
|
|
2057
|
+
exports.parseIso = parseIso2;
|
|
1551
2058
|
exports.pct = pct;
|
|
1552
2059
|
exports.tid = tid;
|
|
1553
2060
|
exports.toEmbedUrl = toEmbedUrl;
|
|
1554
2061
|
exports.toHslTriplet = toHslTriplet;
|
|
1555
2062
|
exports.useAssetRenderer = useAssetRenderer;
|
|
1556
2063
|
exports.useAssetResolverActive = useAssetResolverActive;
|
|
1557
|
-
|
|
1558
|
-
//# sourceMappingURL=chunk-
|
|
2064
|
+
exports.utcDay = utcDay;
|
|
2065
|
+
//# sourceMappingURL=chunk-YNGRSAGP.cjs.map
|
|
2066
|
+
//# sourceMappingURL=chunk-YNGRSAGP.cjs.map
|