@underverse-ui/underverse 0.2.84 → 0.2.86

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.cjs CHANGED
@@ -7757,20 +7757,21 @@ var DateTimePicker = ({
7757
7757
  ] });
7758
7758
  };
7759
7759
 
7760
- // ../../components/ui/CalendarTimeline.tsx
7761
- var React27 = __toESM(require("react"), 1);
7760
+ // ../../components/ui/CalendarTimeline/CalendarTimeline.tsx
7761
+ var React28 = __toESM(require("react"), 1);
7762
7762
  var import_lucide_react18 = require("lucide-react");
7763
- var import_jsx_runtime33 = require("react/jsx-runtime");
7763
+
7764
+ // ../../components/ui/CalendarTimeline/date.ts
7764
7765
  function toDate2(input) {
7765
7766
  return input instanceof Date ? input : new Date(input);
7766
7767
  }
7767
- var localeToBCP47 = (l) => {
7768
- if (l === "vi") return "vi-VN";
7769
- if (l === "en") return "en-US";
7770
- if (l === "ko") return "ko-KR";
7771
- if (l === "ja") return "ja-JP";
7772
- return l;
7773
- };
7768
+ function localeToBCP47(locale) {
7769
+ if (locale === "vi") return "vi-VN";
7770
+ if (locale === "en") return "en-US";
7771
+ if (locale === "ko") return "ko-KR";
7772
+ if (locale === "ja") return "ja-JP";
7773
+ return locale;
7774
+ }
7774
7775
  var dtfCache = /* @__PURE__ */ new Map();
7775
7776
  function getDtf(locale, timeZone, options) {
7776
7777
  const key = `${locale}__${timeZone}__${JSON.stringify(options)}`;
@@ -7840,6 +7841,8 @@ function startOfZonedWeek(date, weekStartsOn, timeZone) {
7840
7841
  const diff = (weekday - weekStartsOn + 7) % 7;
7841
7842
  return new Date(zonedTimeToUtcMs({ year: p.year, month: p.month, day: p.day - diff, hour: 0, minute: 0, second: 0 }, timeZone));
7842
7843
  }
7844
+
7845
+ // ../../components/ui/CalendarTimeline/layout.ts
7843
7846
  function clamp3(n, min, max) {
7844
7847
  return Math.max(min, Math.min(max, n));
7845
7848
  }
@@ -7884,6 +7887,80 @@ function intervalPack(items) {
7884
7887
  }
7885
7888
  return { packed: out, laneCount: lanes.length };
7886
7889
  }
7890
+
7891
+ // ../../components/ui/CalendarTimeline/hooks.ts
7892
+ var React27 = __toESM(require("react"), 1);
7893
+ function useHorizontalScrollSync(args) {
7894
+ const { bodyRef, headerRef } = args;
7895
+ React27.useEffect(() => {
7896
+ const body = bodyRef.current;
7897
+ const header = headerRef.current;
7898
+ if (!body || !header) return;
7899
+ let raf = 0;
7900
+ let syncing = false;
7901
+ const syncHeader = () => {
7902
+ if (syncing) return;
7903
+ syncing = true;
7904
+ header.scrollLeft = body.scrollLeft;
7905
+ syncing = false;
7906
+ };
7907
+ const syncBody = () => {
7908
+ if (syncing) return;
7909
+ syncing = true;
7910
+ body.scrollLeft = header.scrollLeft;
7911
+ syncing = false;
7912
+ };
7913
+ const onBodyScroll = () => {
7914
+ cancelAnimationFrame(raf);
7915
+ raf = requestAnimationFrame(syncHeader);
7916
+ };
7917
+ const onHeaderScroll = () => {
7918
+ cancelAnimationFrame(raf);
7919
+ raf = requestAnimationFrame(syncBody);
7920
+ };
7921
+ body.addEventListener("scroll", onBodyScroll, { passive: true });
7922
+ header.addEventListener("scroll", onHeaderScroll, { passive: true });
7923
+ return () => {
7924
+ cancelAnimationFrame(raf);
7925
+ body.removeEventListener("scroll", onBodyScroll);
7926
+ header.removeEventListener("scroll", onHeaderScroll);
7927
+ };
7928
+ }, [bodyRef, headerRef]);
7929
+ }
7930
+ function useVirtualRows(args) {
7931
+ const { enabled, overscan, rowHeight, itemCount, scrollRef } = args;
7932
+ const [viewportHeight, setViewportHeight] = React27.useState(0);
7933
+ const [scrollTop, setScrollTop] = React27.useState(0);
7934
+ React27.useEffect(() => {
7935
+ const el = scrollRef.current;
7936
+ if (!el) return;
7937
+ const update = () => setViewportHeight(el.clientHeight);
7938
+ update();
7939
+ const ro = new ResizeObserver(update);
7940
+ ro.observe(el);
7941
+ return () => ro.disconnect();
7942
+ }, [scrollRef]);
7943
+ React27.useEffect(() => {
7944
+ const el = scrollRef.current;
7945
+ if (!el) return;
7946
+ const onScroll = () => setScrollTop(el.scrollTop);
7947
+ el.addEventListener("scroll", onScroll, { passive: true });
7948
+ return () => el.removeEventListener("scroll", onScroll);
7949
+ }, [scrollRef]);
7950
+ return React27.useMemo(() => {
7951
+ if (!enabled) {
7952
+ return { startIndex: 0, endIndex: itemCount, topSpacer: 0, bottomSpacer: 0 };
7953
+ }
7954
+ const startIndex = clamp3(Math.floor(scrollTop / rowHeight) - overscan, 0, itemCount);
7955
+ const endIndex = clamp3(Math.ceil((scrollTop + viewportHeight) / rowHeight) + overscan, 0, itemCount);
7956
+ const topSpacer = startIndex * rowHeight;
7957
+ const bottomSpacer = (itemCount - endIndex) * rowHeight;
7958
+ return { startIndex, endIndex, topSpacer, bottomSpacer };
7959
+ }, [enabled, itemCount, overscan, rowHeight, scrollTop, viewportHeight]);
7960
+ }
7961
+
7962
+ // ../../components/ui/CalendarTimeline/CalendarTimeline.tsx
7963
+ var import_jsx_runtime33 = require("react/jsx-runtime");
7887
7964
  function defaultMonthTitle(date, locale, timeZone) {
7888
7965
  return getDtf(locale, timeZone, { month: "long", year: "numeric" }).format(date);
7889
7966
  }
@@ -7893,9 +7970,9 @@ function defaultSlotHeader(slotStart, view, locale, timeZone) {
7893
7970
  }
7894
7971
  const weekday = getDtf(locale, timeZone, { weekday: "short" }).format(slotStart);
7895
7972
  const day = getDtf(locale, timeZone, { day: "numeric" }).format(slotStart);
7896
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "inline-flex flex-col leading-tight", children: [
7897
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-[11px] text-muted-foreground", children: weekday }),
7898
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-[12px] font-medium", children: day })
7973
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "inline-flex flex-col items-center leading-tight", children: [
7974
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70", children: weekday }),
7975
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-sm font-semibold text-foreground", children: day })
7899
7976
  ] });
7900
7977
  }
7901
7978
  function defaultEventTime(args) {
@@ -7910,6 +7987,7 @@ function defaultEventTime(args) {
7910
7987
  function CalendarTimeline({
7911
7988
  resources,
7912
7989
  events,
7990
+ size = "md",
7913
7991
  view,
7914
7992
  defaultView = "month",
7915
7993
  onViewChange,
@@ -7925,9 +8003,9 @@ function CalendarTimeline({
7925
8003
  groupCollapsed,
7926
8004
  defaultGroupCollapsed,
7927
8005
  onGroupCollapsedChange,
7928
- resourceColumnWidth = 220,
7929
- rowHeight = 48,
7930
- slotMinWidth = 56,
8006
+ resourceColumnWidth,
8007
+ rowHeight,
8008
+ slotMinWidth,
7931
8009
  dayTimeStepMinutes = 60,
7932
8010
  maxLanesPerRow = 3,
7933
8011
  now,
@@ -7948,19 +8026,72 @@ function CalendarTimeline({
7948
8026
  }) {
7949
8027
  const t = useTranslations("CalendarTimeline");
7950
8028
  const detectedLocale = useLocale();
7951
- const resolvedLocale = React27.useMemo(() => locale ?? localeToBCP47(detectedLocale), [locale, detectedLocale]);
7952
- const resolvedTimeZone = React27.useMemo(
7953
- () => timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone ?? "UTC",
7954
- [timeZone]
7955
- );
8029
+ const resolvedLocale = React28.useMemo(() => localeToBCP47(locale ?? detectedLocale), [locale, detectedLocale]);
8030
+ const resolvedTimeZone = React28.useMemo(() => timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone ?? "UTC", [timeZone]);
8031
+ const sizeConfig = React28.useMemo(() => {
8032
+ const cfgBySize = {
8033
+ sm: {
8034
+ resourceColumnWidth: 200,
8035
+ rowHeight: 44,
8036
+ slotMinWidth: 52,
8037
+ eventHeight: 16,
8038
+ laneGap: 3,
8039
+ lanePaddingY: 5,
8040
+ densityClass: "text-xs",
8041
+ headerPaddingClass: "px-3 py-2",
8042
+ titleClass: "text-base",
8043
+ resourceRowClass: "gap-2 px-3",
8044
+ groupRowClass: "gap-2 px-3",
8045
+ slotHeaderClass: "px-1 py-2",
8046
+ controlButtonIconClass: "h-7 w-7",
8047
+ controlButtonTextClass: "h-7 px-2 text-xs"
8048
+ },
8049
+ md: {
8050
+ resourceColumnWidth: 240,
8051
+ rowHeight: 52,
8052
+ slotMinWidth: 64,
8053
+ eventHeight: 18,
8054
+ laneGap: 4,
8055
+ lanePaddingY: 6,
8056
+ densityClass: "text-sm",
8057
+ headerPaddingClass: "px-4 py-3",
8058
+ titleClass: "text-lg",
8059
+ resourceRowClass: "gap-3 px-4",
8060
+ groupRowClass: "gap-3 px-4",
8061
+ slotHeaderClass: "px-1 py-3",
8062
+ controlButtonIconClass: "h-8 w-8",
8063
+ controlButtonTextClass: "h-8 px-3"
8064
+ },
8065
+ xl: {
8066
+ resourceColumnWidth: 280,
8067
+ rowHeight: 60,
8068
+ slotMinWidth: 76,
8069
+ eventHeight: 20,
8070
+ laneGap: 5,
8071
+ lanePaddingY: 8,
8072
+ densityClass: "text-base",
8073
+ headerPaddingClass: "px-5 py-4",
8074
+ titleClass: "text-xl",
8075
+ resourceRowClass: "gap-4 px-5",
8076
+ groupRowClass: "gap-4 px-5",
8077
+ slotHeaderClass: "px-2 py-4",
8078
+ controlButtonIconClass: "h-9 w-9",
8079
+ controlButtonTextClass: "h-9 px-4 text-sm"
8080
+ }
8081
+ };
8082
+ return cfgBySize[size];
8083
+ }, [size]);
8084
+ const effectiveResourceColumnWidth = resourceColumnWidth ?? sizeConfig.resourceColumnWidth;
8085
+ const effectiveRowHeight = rowHeight ?? sizeConfig.rowHeight;
8086
+ const effectiveSlotMinWidth = slotMinWidth ?? sizeConfig.slotMinWidth;
7956
8087
  const isControlledView = view !== void 0;
7957
- const [internalView, setInternalView] = React27.useState(defaultView);
8088
+ const [internalView, setInternalView] = React28.useState(defaultView);
7958
8089
  const activeView = isControlledView ? view : internalView;
7959
8090
  const isControlledDate = date !== void 0;
7960
- const [internalDate, setInternalDate] = React27.useState(() => defaultDate ?? /* @__PURE__ */ new Date());
8091
+ const [internalDate, setInternalDate] = React28.useState(() => defaultDate ?? /* @__PURE__ */ new Date());
7961
8092
  const activeDate = isControlledDate ? date : internalDate;
7962
8093
  const resolvedNow = now ?? /* @__PURE__ */ new Date();
7963
- const l = React27.useMemo(
8094
+ const l = React28.useMemo(
7964
8095
  () => ({
7965
8096
  today: labels?.today ?? t("today"),
7966
8097
  prev: labels?.prev ?? t("prev"),
@@ -7974,39 +8105,46 @@ function CalendarTimeline({
7974
8105
  }),
7975
8106
  [labels, t]
7976
8107
  );
7977
- const setView = (next) => {
7978
- if (!isControlledView) setInternalView(next);
7979
- onViewChange?.(next);
7980
- };
7981
- const setDate = (next) => {
7982
- if (!isControlledDate) setInternalDate(next);
7983
- onDateChange?.(next);
7984
- };
7985
- const navigate = (dir) => {
7986
- const base = activeDate;
7987
- if (activeView === "month") {
7988
- setDate(addZonedMonths(base, dir, resolvedTimeZone));
7989
- return;
7990
- }
7991
- if (activeView === "week") {
7992
- setDate(addZonedDays(base, dir * 7, resolvedTimeZone));
7993
- return;
7994
- }
7995
- setDate(addZonedDays(base, dir, resolvedTimeZone));
7996
- };
7997
- const goToday = () => setDate(resolvedNow);
7998
- const [internalCollapsed, setInternalCollapsed] = React27.useState(() => defaultGroupCollapsed ?? {});
8108
+ const setView = React28.useCallback(
8109
+ (next) => {
8110
+ if (!isControlledView) setInternalView(next);
8111
+ onViewChange?.(next);
8112
+ },
8113
+ [isControlledView, onViewChange]
8114
+ );
8115
+ const setDate = React28.useCallback(
8116
+ (next) => {
8117
+ if (!isControlledDate) setInternalDate(next);
8118
+ onDateChange?.(next);
8119
+ },
8120
+ [isControlledDate, onDateChange]
8121
+ );
8122
+ const navigate = React28.useCallback(
8123
+ (dir) => {
8124
+ const base = activeDate;
8125
+ if (activeView === "month") {
8126
+ setDate(addZonedMonths(base, dir, resolvedTimeZone));
8127
+ return;
8128
+ }
8129
+ if (activeView === "week") {
8130
+ setDate(addZonedDays(base, dir * 7, resolvedTimeZone));
8131
+ return;
8132
+ }
8133
+ setDate(addZonedDays(base, dir, resolvedTimeZone));
8134
+ },
8135
+ [activeDate, activeView, resolvedTimeZone, setDate]
8136
+ );
8137
+ const goToday = React28.useCallback(() => setDate(resolvedNow), [resolvedNow, setDate]);
8138
+ const [internalCollapsed, setInternalCollapsed] = React28.useState(() => defaultGroupCollapsed ?? {});
7999
8139
  const collapsed = groupCollapsed ?? internalCollapsed;
8000
- const setCollapsed = (next) => {
8001
- if (!groupCollapsed) setInternalCollapsed(next);
8002
- onGroupCollapsedChange?.(next);
8003
- };
8004
- const groupById = React27.useMemo(() => {
8005
- const map = /* @__PURE__ */ new Map();
8006
- for (const g of groups ?? []) map.set(g.id, g);
8007
- return map;
8008
- }, [groups]);
8009
- const rows = React27.useMemo(() => {
8140
+ const setCollapsed = React28.useCallback(
8141
+ (next) => {
8142
+ if (!groupCollapsed) setInternalCollapsed(next);
8143
+ onGroupCollapsedChange?.(next);
8144
+ },
8145
+ [groupCollapsed, onGroupCollapsedChange]
8146
+ );
8147
+ const rows = React28.useMemo(() => {
8010
8148
  if (!groups || groups.length === 0) return resources.map((resource) => ({ kind: "resource", resource }));
8011
8149
  const byGroup = /* @__PURE__ */ new Map();
8012
8150
  for (const r of resources) {
@@ -8037,7 +8175,7 @@ function CalendarTimeline({
8037
8175
  }
8038
8176
  return out;
8039
8177
  }, [resources, groups, collapsed]);
8040
- const { slots, range } = React27.useMemo(() => {
8178
+ const { slots, range } = React28.useMemo(() => {
8041
8179
  const start = activeView === "month" ? startOfZonedMonth(activeDate, resolvedTimeZone) : activeView === "week" ? startOfZonedWeek(activeDate, weekStartsOn, resolvedTimeZone) : startOfZonedDay(activeDate, resolvedTimeZone);
8042
8180
  if (activeView === "day") {
8043
8181
  const step = Math.max(5, Math.min(240, Math.trunc(dayTimeStepMinutes)));
@@ -8071,13 +8209,13 @@ function CalendarTimeline({
8071
8209
  }));
8072
8210
  return { slots: slotItems, range: { start, end } };
8073
8211
  }, [activeView, activeDate, resolvedTimeZone, resolvedLocale, weekStartsOn, dayTimeStepMinutes, resolvedNow, formatters]);
8074
- React27.useEffect(() => {
8212
+ React28.useEffect(() => {
8075
8213
  onRangeChange?.(range);
8076
8214
  }, [range.start, range.end, onRangeChange]);
8077
- const slotStarts = React27.useMemo(() => slots.map((s) => s.start), [slots]);
8078
- const slotWidth = slotMinWidth;
8215
+ const slotStarts = React28.useMemo(() => slots.map((s) => s.start), [slots]);
8216
+ const slotWidth = effectiveSlotMinWidth;
8079
8217
  const gridWidth = slots.length * slotWidth;
8080
- const normalizedEvents = React27.useMemo(() => {
8218
+ const normalizedEvents = React28.useMemo(() => {
8081
8219
  const rangeStart = range.start.getTime();
8082
8220
  const rangeEnd = range.end.getTime();
8083
8221
  return events.map((e) => {
@@ -8093,7 +8231,7 @@ function CalendarTimeline({
8093
8231
  return { ...e, _start: cs, _end: ce };
8094
8232
  }).filter(Boolean);
8095
8233
  }, [events, range.start, range.end, activeView, resolvedTimeZone]);
8096
- const eventsByResource = React27.useMemo(() => {
8234
+ const eventsByResource = React28.useMemo(() => {
8097
8235
  const map = /* @__PURE__ */ new Map();
8098
8236
  for (const e of normalizedEvents) {
8099
8237
  if (!map.has(e.resourceId)) map.set(e.resourceId, []);
@@ -8101,97 +8239,59 @@ function CalendarTimeline({
8101
8239
  }
8102
8240
  return map;
8103
8241
  }, [normalizedEvents]);
8104
- const bodyRef = React27.useRef(null);
8105
- const headerRef = React27.useRef(null);
8106
- React27.useEffect(() => {
8107
- const body = bodyRef.current;
8108
- const header = headerRef.current;
8109
- if (!body || !header) return;
8110
- let raf = 0;
8111
- let syncing = false;
8112
- const syncHeader = () => {
8113
- if (syncing) return;
8114
- syncing = true;
8115
- header.scrollLeft = body.scrollLeft;
8116
- syncing = false;
8117
- };
8118
- const syncBody = () => {
8119
- if (syncing) return;
8120
- syncing = true;
8121
- body.scrollLeft = header.scrollLeft;
8122
- syncing = false;
8123
- };
8124
- const onBodyScroll = () => {
8125
- cancelAnimationFrame(raf);
8126
- raf = requestAnimationFrame(syncHeader);
8127
- };
8128
- const onHeaderScroll = () => {
8129
- cancelAnimationFrame(raf);
8130
- raf = requestAnimationFrame(syncBody);
8131
- };
8132
- body.addEventListener("scroll", onBodyScroll, { passive: true });
8133
- header.addEventListener("scroll", onHeaderScroll, { passive: true });
8134
- return () => {
8135
- cancelAnimationFrame(raf);
8136
- body.removeEventListener("scroll", onBodyScroll);
8137
- header.removeEventListener("scroll", onHeaderScroll);
8138
- };
8139
- }, []);
8140
- const title = React27.useMemo(() => {
8242
+ const bodyRef = React28.useRef(null);
8243
+ const headerRef = React28.useRef(null);
8244
+ useHorizontalScrollSync({ bodyRef, headerRef });
8245
+ const title = React28.useMemo(() => {
8141
8246
  return formatters?.monthTitle?.(activeDate, { locale: resolvedLocale, timeZone: resolvedTimeZone }) ?? defaultMonthTitle(activeDate, resolvedLocale, resolvedTimeZone);
8142
8247
  }, [activeDate, formatters, resolvedLocale, resolvedTimeZone]);
8143
- const densityClass = "text-sm";
8144
- const eventHeight = 18;
8145
- const laneGap = 4;
8146
- const lanePaddingY = 6;
8248
+ const densityClass = sizeConfig.densityClass;
8249
+ const eventHeight = sizeConfig.eventHeight;
8250
+ const laneGap = sizeConfig.laneGap;
8251
+ const lanePaddingY = sizeConfig.lanePaddingY;
8147
8252
  const virt = virtualization?.enabled;
8148
8253
  const overscan = virtualization?.overscan ?? 8;
8149
- const [viewportHeight, setViewportHeight] = React27.useState(0);
8150
- const [scrollTop, setScrollTop] = React27.useState(0);
8151
- React27.useEffect(() => {
8152
- const el = bodyRef.current;
8153
- if (!el) return;
8154
- const update = () => setViewportHeight(el.clientHeight);
8155
- update();
8156
- const ro = new ResizeObserver(update);
8157
- ro.observe(el);
8158
- return () => ro.disconnect();
8159
- }, []);
8160
- React27.useEffect(() => {
8161
- const el = bodyRef.current;
8162
- if (!el) return;
8163
- const onScroll = () => setScrollTop(el.scrollTop);
8164
- el.addEventListener("scroll", onScroll, { passive: true });
8165
- return () => el.removeEventListener("scroll", onScroll);
8166
- }, []);
8167
- const totalRows = rows.length;
8168
- const startRow = virt ? clamp3(Math.floor(scrollTop / rowHeight) - overscan, 0, totalRows) : 0;
8169
- const endRow = virt ? clamp3(Math.ceil((scrollTop + viewportHeight) / rowHeight) + overscan, 0, totalRows) : totalRows;
8170
- const topSpacer = startRow * rowHeight;
8171
- const bottomSpacer = (totalRows - endRow) * rowHeight;
8172
- const dragRef = React27.useRef(null);
8173
- const [preview, setPreview] = React27.useState(null);
8174
- const getPointerContext = (clientX, clientY) => {
8175
- const body = bodyRef.current;
8176
- if (!body) return null;
8177
- const el = document.elementFromPoint(clientX, clientY);
8178
- const timelineEl = el?.closest?.("[data-uv-ct-timeline]");
8179
- if (!timelineEl) return null;
8180
- const timelineRect = timelineEl.getBoundingClientRect();
8181
- const x = clientX - timelineRect.left + body.scrollLeft;
8182
- const slotIdx = clamp3(Math.floor(x / slotWidth), 0, Math.max(0, slots.length - 1));
8183
- const rowEl = el?.closest?.("[data-uv-ct-row]");
8184
- const rid = rowEl?.dataset?.uvCtRow ?? null;
8185
- return { slotIdx, resourceId: rid, x };
8186
- };
8187
- const slotToDate = (slotIdx) => {
8188
- const start = slotStarts[clamp3(slotIdx, 0, slotStarts.length - 1)];
8189
- if (activeView === "day") {
8190
- const stepMs = Math.trunc(Math.max(5, Math.min(240, Math.trunc(dayTimeStepMinutes))) * 6e4);
8191
- return { start, end: new Date(start.getTime() + stepMs) };
8192
- }
8193
- return { start, end: addZonedDays(start, 1, resolvedTimeZone) };
8194
- };
8254
+ const {
8255
+ startIndex: startRow,
8256
+ endIndex: endRow,
8257
+ topSpacer,
8258
+ bottomSpacer
8259
+ } = useVirtualRows({
8260
+ enabled: virt,
8261
+ overscan,
8262
+ rowHeight: effectiveRowHeight,
8263
+ itemCount: rows.length,
8264
+ scrollRef: bodyRef
8265
+ });
8266
+ const dragRef = React28.useRef(null);
8267
+ const [preview, setPreview] = React28.useState(null);
8268
+ const getPointerContext = React28.useCallback(
8269
+ (clientX, clientY) => {
8270
+ const body = bodyRef.current;
8271
+ if (!body) return null;
8272
+ const el = document.elementFromPoint(clientX, clientY);
8273
+ const timelineEl = el?.closest?.("[data-uv-ct-timeline]");
8274
+ if (!timelineEl) return null;
8275
+ const timelineRect = timelineEl.getBoundingClientRect();
8276
+ const x = clientX - timelineRect.left + body.scrollLeft;
8277
+ const slotIdx = clamp3(Math.floor(x / slotWidth), 0, Math.max(0, slots.length - 1));
8278
+ const rowEl = el?.closest?.("[data-uv-ct-row]");
8279
+ const rid = rowEl?.dataset?.uvCtRow ?? null;
8280
+ return { slotIdx, resourceId: rid, x };
8281
+ },
8282
+ [slotWidth, slots.length]
8283
+ );
8284
+ const slotToDate = React28.useCallback(
8285
+ (slotIdx) => {
8286
+ const start = slotStarts[clamp3(slotIdx, 0, slotStarts.length - 1)];
8287
+ if (activeView === "day") {
8288
+ const stepMs = Math.trunc(Math.max(5, Math.min(240, Math.trunc(dayTimeStepMinutes))) * 6e4);
8289
+ return { start, end: new Date(start.getTime() + stepMs) };
8290
+ }
8291
+ return { start, end: addZonedDays(start, 1, resolvedTimeZone) };
8292
+ },
8293
+ [activeView, dayTimeStepMinutes, resolvedTimeZone, slotStarts]
8294
+ );
8195
8295
  const onPointerDownEvent = (e, ev, mode) => {
8196
8296
  if (ev.resourceId == null) return;
8197
8297
  const allowDrag = interactions?.draggableEvents ?? true;
@@ -8306,14 +8406,29 @@ function CalendarTimeline({
8306
8406
  type: "button",
8307
8407
  onClick: canToggle ? toggle : void 0,
8308
8408
  className: cn(
8309
- "w-full h-full flex items-center gap-2 px-3 text-left",
8310
- "bg-muted/30 border-b border-border/60",
8311
- canToggle ? "cursor-pointer hover:bg-muted/50" : "cursor-default"
8409
+ "w-full h-full flex items-center text-left",
8410
+ sizeConfig.groupRowClass,
8411
+ "bg-linear-to-r from-muted/40 to-muted/20 border-b border-border/40",
8412
+ "backdrop-blur-sm",
8413
+ canToggle ? "cursor-pointer hover:from-muted/60 hover:to-muted/30 transition-all duration-200" : "cursor-default"
8312
8414
  ),
8313
8415
  "aria-label": isCollapsed ? l.expandGroup : l.collapseGroup,
8314
8416
  children: [
8315
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: cn("inline-flex transition-transform", isCollapsed ? "" : "rotate-180"), children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.ChevronsUpDown, { className: "h-4 w-4 text-muted-foreground" }) }),
8316
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "font-semibold", children: g.label })
8417
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8418
+ "span",
8419
+ {
8420
+ className: cn(
8421
+ "inline-flex items-center justify-center w-5 h-5 rounded-md bg-background/60 transition-transform duration-200",
8422
+ isCollapsed ? "" : "rotate-180"
8423
+ ),
8424
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
8425
+ }
8426
+ ),
8427
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "font-semibold text-foreground/90", children: g.label }),
8428
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "ml-auto text-xs text-muted-foreground/60 font-medium", children: [
8429
+ resources.filter((r) => r.groupId === g.id).length,
8430
+ " items"
8431
+ ] })
8317
8432
  ]
8318
8433
  }
8319
8434
  );
@@ -8330,44 +8445,111 @@ function CalendarTimeline({
8330
8445
  "div",
8331
8446
  {
8332
8447
  className: cn(
8333
- "flex-shrink-0 border-l border-border/60 px-2 py-2",
8334
- s.isToday && "bg-primary/5"
8448
+ "shrink-0 border-l border-border/30 flex items-center justify-center transition-colors duration-150",
8449
+ sizeConfig.slotHeaderClass,
8450
+ s.isToday && "bg-primary/8 border-l-primary/40"
8335
8451
  ),
8336
8452
  style: { width: slotWidth, minWidth: slotWidth },
8337
8453
  "aria-label": formatters?.ariaSlotLabel?.(s.start, { view: activeView, locale: resolvedLocale, timeZone: resolvedTimeZone }),
8338
- children: s.label
8454
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: cn("flex flex-col items-center", s.isToday && "relative"), children: [
8455
+ s.isToday && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.Dot, { className: "absolute -top-2.5 h-4 w-4 text-primary animate-pulse" }),
8456
+ s.label
8457
+ ] })
8339
8458
  },
8340
8459
  `${s.start.toISOString()}_${idx}`
8341
8460
  ))
8342
8461
  }
8343
8462
  );
8344
- const Header = /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "sticky top-0 z-30 bg-background border-b border-border/60", children: [
8345
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center justify-between gap-3 px-3 py-2", children: [
8346
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
8347
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Button_default, { variant: "ghost", size: "sm", onClick: () => navigate(-1), "aria-label": l.prev, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.ChevronLeft, { className: "h-4 w-4" }) }),
8348
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Button_default, { variant: "ghost", size: "sm", onClick: goToday, children: l.today }),
8349
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Button_default, { variant: "ghost", size: "sm", onClick: () => navigate(1), "aria-label": l.next, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.ChevronRight, { className: "h-4 w-4" }) }),
8350
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "ml-2 font-semibold truncate", children: title })
8463
+ const viewIcons = {
8464
+ month: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.CalendarRange, { className: "h-4 w-4" }),
8465
+ week: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.CalendarDays, { className: "h-4 w-4" }),
8466
+ day: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.Calendar, { className: "h-4 w-4" })
8467
+ };
8468
+ const Header = /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "sticky top-0 z-30 bg-linear-to-b from-background via-background to-background/95 border-b border-border/40 backdrop-blur-xl", children: [
8469
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: cn("flex items-center justify-between gap-4", sizeConfig.headerPaddingClass), children: [
8470
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center gap-1.5 min-w-0", children: [
8471
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center bg-muted/40 rounded-xl p-1 gap-0.5", children: [
8472
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8473
+ Button_default,
8474
+ {
8475
+ variant: "ghost",
8476
+ size: "icon",
8477
+ onClick: () => navigate(-1),
8478
+ "aria-label": l.prev,
8479
+ className: cn(sizeConfig.controlButtonIconClass, "rounded-lg hover:bg-background/80 transition-all duration-200"),
8480
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.ChevronLeft, { className: "h-4 w-4" })
8481
+ }
8482
+ ),
8483
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8484
+ Button_default,
8485
+ {
8486
+ variant: "ghost",
8487
+ size: "sm",
8488
+ onClick: goToday,
8489
+ className: cn(sizeConfig.controlButtonTextClass, "rounded-lg hover:bg-background/80 font-medium transition-all duration-200"),
8490
+ children: l.today
8491
+ }
8492
+ ),
8493
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8494
+ Button_default,
8495
+ {
8496
+ variant: "ghost",
8497
+ size: "icon",
8498
+ onClick: () => navigate(1),
8499
+ "aria-label": l.next,
8500
+ className: cn(sizeConfig.controlButtonIconClass, "rounded-lg hover:bg-background/80 transition-all duration-200"),
8501
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.ChevronRight, { className: "h-4 w-4" })
8502
+ }
8503
+ )
8504
+ ] }),
8505
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h2", { className: cn("ml-3 font-semibold tracking-tight truncate text-foreground", sizeConfig.titleClass), children: title })
8351
8506
  ] }),
8352
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-center gap-1", children: [
8353
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Button_default, { variant: activeView === "month" ? "default" : "ghost", size: "sm", onClick: () => setView("month"), children: l.month }),
8354
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Button_default, { variant: activeView === "week" ? "default" : "ghost", size: "sm", onClick: () => setView("week"), children: l.week }),
8355
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Button_default, { variant: activeView === "day" ? "default" : "ghost", size: "sm", onClick: () => setView("day"), children: l.day })
8356
- ] })
8507
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex items-center bg-muted/40 rounded-xl p-1 gap-0.5", children: ["month", "week", "day"].map((v) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
8508
+ Button_default,
8509
+ {
8510
+ variant: activeView === v ? "default" : "ghost",
8511
+ size: "sm",
8512
+ onClick: () => setView(v),
8513
+ className: cn(
8514
+ sizeConfig.controlButtonTextClass,
8515
+ "rounded-lg font-medium transition-all duration-200 gap-1.5",
8516
+ activeView === v ? "bg-primary text-primary-foreground shadow-sm shadow-primary/25" : "hover:bg-background/80 text-muted-foreground hover:text-foreground"
8517
+ ),
8518
+ children: [
8519
+ viewIcons[v],
8520
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "hidden sm:inline", children: l[v] })
8521
+ ]
8522
+ },
8523
+ v
8524
+ )) })
8357
8525
  ] }),
8358
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex", children: [
8526
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex border-t border-border/20", children: [
8359
8527
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8360
8528
  "div",
8361
8529
  {
8362
- className: "flex-shrink-0 border-r border-border/60 bg-background",
8363
- style: { width: resourceColumnWidth, minWidth: resourceColumnWidth }
8530
+ className: "shrink-0 border-r border-border/30 bg-muted/20 flex items-center justify-center",
8531
+ style: { width: effectiveResourceColumnWidth, minWidth: effectiveResourceColumnWidth },
8532
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-xs font-medium text-muted-foreground/70 uppercase tracking-wider", children: t("resourcesHeader") })
8364
8533
  }
8365
8534
  ),
8366
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: headerRef, className: "overflow-x-auto overflow-y-hidden", children: slotHeaderNodes })
8535
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: headerRef, className: "overflow-x-auto overflow-y-hidden scrollbar-none", children: slotHeaderNodes })
8367
8536
  ] })
8368
8537
  ] });
8369
- const ResourceCell = (r) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "h-full w-full flex items-center px-3 border-b border-border/60 bg-background", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn("truncate", r.disabled && "opacity-50"), children: renderResource ? renderResource(r) : r.label }) });
8370
- const layoutsByResource = React27.useMemo(() => {
8538
+ const ResourceCell = (r) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
8539
+ "div",
8540
+ {
8541
+ className: cn(
8542
+ "h-full w-full flex items-center border-b border-border/30 bg-linear-to-r from-background to-background/95",
8543
+ sizeConfig.resourceRowClass,
8544
+ "hover:from-muted/30 hover:to-muted/10 transition-all duration-200 group"
8545
+ ),
8546
+ children: [
8547
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "shrink-0 opacity-0 group-hover:opacity-60 transition-opacity cursor-grab", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.GripVertical, { className: "h-4 w-4 text-muted-foreground" }) }),
8548
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn("flex-1 min-w-0", r.disabled && "opacity-50"), children: renderResource ? renderResource(r) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "font-medium text-sm truncate block", children: r.label }) })
8549
+ ]
8550
+ }
8551
+ );
8552
+ const layoutsByResource = React28.useMemo(() => {
8371
8553
  const map = /* @__PURE__ */ new Map();
8372
8554
  for (const [resourceId, list] of eventsByResource.entries()) {
8373
8555
  const mapped = list.map((ev) => {
@@ -8396,7 +8578,12 @@ function CalendarTimeline({
8396
8578
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
8397
8579
  "div",
8398
8580
  {
8399
- className: cn("border border-border/60 rounded-2xl overflow-hidden bg-background", densityClass, className),
8581
+ className: cn(
8582
+ "border border-border/40 rounded-2xl overflow-hidden bg-background/95 backdrop-blur-sm",
8583
+ "shadow-sm hover:shadow-md transition-shadow duration-300",
8584
+ densityClass,
8585
+ className
8586
+ ),
8400
8587
  ...rest,
8401
8588
  children: [
8402
8589
  Header,
@@ -8404,7 +8591,7 @@ function CalendarTimeline({
8404
8591
  "div",
8405
8592
  {
8406
8593
  ref: bodyRef,
8407
- className: "relative overflow-auto",
8594
+ className: "relative overflow-auto scrollbar-thin scrollbar-thumb-muted scrollbar-track-transparent",
8408
8595
  onPointerMove,
8409
8596
  onPointerUp,
8410
8597
  children: [
@@ -8412,16 +8599,16 @@ function CalendarTimeline({
8412
8599
  rows.slice(startRow, endRow).map((row, idx) => {
8413
8600
  const rowIndex = startRow + idx;
8414
8601
  if (row.kind === "group") {
8415
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex", style: { height: rowHeight }, children: [
8602
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex", style: { height: effectiveRowHeight }, children: [
8416
8603
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8417
8604
  "div",
8418
8605
  {
8419
- className: "flex-shrink-0 sticky left-0 z-20",
8420
- style: { width: resourceColumnWidth, minWidth: resourceColumnWidth },
8606
+ className: "shrink-0 sticky left-0 z-20",
8607
+ style: { width: effectiveResourceColumnWidth, minWidth: effectiveResourceColumnWidth },
8421
8608
  children: renderGroupRow(row.group)
8422
8609
  }
8423
8610
  ),
8424
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 border-b border-border/60 bg-muted/20", style: { minWidth: gridWidth } })
8611
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 border-b border-border/30 bg-linear-to-r from-muted/15 to-muted/5", style: { minWidth: gridWidth } })
8425
8612
  ] }, `g_${row.group.id}_${rowIndex}`);
8426
8613
  }
8427
8614
  const r = row.resource;
@@ -8430,122 +8617,130 @@ function CalendarTimeline({
8430
8617
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
8431
8618
  "div",
8432
8619
  {
8433
- className: "flex",
8434
- style: { height: rowHeight },
8620
+ className: "flex group/row hover:bg-muted/5 transition-colors duration-150",
8621
+ style: { height: effectiveRowHeight },
8435
8622
  "data-uv-ct-row": r.id,
8436
8623
  children: [
8437
8624
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8438
8625
  "div",
8439
8626
  {
8440
- className: "flex-shrink-0 sticky left-0 z-20 border-r border-border/60",
8441
- style: { width: resourceColumnWidth, minWidth: resourceColumnWidth },
8627
+ className: "shrink-0 sticky left-0 z-20 border-r border-border/30",
8628
+ style: { width: effectiveResourceColumnWidth, minWidth: effectiveResourceColumnWidth },
8442
8629
  children: ResourceCell(r)
8443
8630
  }
8444
8631
  ),
8445
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
8446
- "div",
8447
- {
8448
- className: "relative flex-shrink-0",
8449
- style: { width: gridWidth, minWidth: gridWidth },
8450
- children: [
8451
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8452
- "div",
8453
- {
8454
- className: "absolute inset-0",
8455
- onPointerDown: onPointerDownCell,
8456
- "data-uv-ct-timeline": true,
8457
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "absolute inset-0 flex", children: slots.map((s, i2) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8458
- "div",
8459
- {
8460
- className: cn("h-full border-l border-border/60", s.isToday && "bg-primary/5"),
8461
- style: { width: slotWidth, minWidth: slotWidth }
8462
- },
8463
- `${r.id}_${i2}`
8464
- )) })
8465
- }
8632
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "relative shrink-0", style: { width: gridWidth, minWidth: gridWidth }, children: [
8633
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "absolute inset-0", onPointerDown: onPointerDownCell, "data-uv-ct-timeline": true, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "absolute inset-0 flex", children: slots.map((s, i2) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8634
+ "div",
8635
+ {
8636
+ className: cn(
8637
+ "h-full border-l border-border/20 transition-colors duration-100",
8638
+ s.isToday && "bg-primary/5 border-l-primary/30",
8639
+ "hover:bg-muted/10"
8466
8640
  ),
8467
- layout.visible.map(({ ev, left, width, lane }) => {
8468
- const top = lanePaddingY + lane * (eventHeight + laneGap);
8469
- const isPreview = preview?.eventId === ev.id;
8470
- const bg = ev.color ? ev.color : "var(--primary-soft)";
8471
- const border = ev.color ? ev.color : "var(--primary)";
8472
- const aria = formatters?.ariaEventLabel?.(ev, { locale: resolvedLocale, timeZone: resolvedTimeZone }) ?? (typeof ev.title === "string" ? ev.title : "Event");
8473
- const timeText = formatters?.eventTime?.({ start: ev._start, end: ev._end, locale: resolvedLocale, timeZone: resolvedTimeZone, view: activeView }) ?? defaultEventTime({ start: ev._start, end: ev._end, locale: resolvedLocale, timeZone: resolvedTimeZone, view: activeView });
8474
- const node = renderEvent?.(ev, { left, width, lane }) ?? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "px-2 py-[2px] truncate text-[11px] leading-tight", children: [
8475
- ev.title ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "font-semibold truncate", children: ev.title }) : null,
8476
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "text-[10px] opacity-80 truncate", children: timeText })
8477
- ] });
8478
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
8479
- "div",
8480
- {
8481
- className: cn(
8482
- "absolute rounded-md border shadow-sm select-none",
8483
- "hover:shadow transition-shadow",
8484
- ev.className,
8485
- isPreview && "ring-2 ring-primary/40"
8641
+ style: { width: slotWidth, minWidth: slotWidth }
8642
+ },
8643
+ `${r.id}_${i2}`
8644
+ )) }) }),
8645
+ layout.visible.map(({ ev, left, width, lane }) => {
8646
+ const top = lanePaddingY + lane * (eventHeight + laneGap);
8647
+ const isPreview = preview?.eventId === ev.id;
8648
+ const bg = ev.color ? ev.color : "hsl(var(--primary) / 0.15)";
8649
+ const border = ev.color ? ev.color : "hsl(var(--primary))";
8650
+ const aria = formatters?.ariaEventLabel?.(ev, { locale: resolvedLocale, timeZone: resolvedTimeZone }) ?? (typeof ev.title === "string" ? ev.title : "Event");
8651
+ const timeText = formatters?.eventTime?.({
8652
+ start: ev._start,
8653
+ end: ev._end,
8654
+ locale: resolvedLocale,
8655
+ timeZone: resolvedTimeZone,
8656
+ view: activeView
8657
+ }) ?? defaultEventTime({ start: ev._start, end: ev._end, locale: resolvedLocale, timeZone: resolvedTimeZone, view: activeView });
8658
+ const node = renderEvent?.(ev, { left, width, lane }) ?? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "px-2.5 py-1 truncate flex items-center gap-1.5", children: [
8659
+ ev.title ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "font-semibold text-[11px] truncate leading-tight", children: ev.title }) : null,
8660
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-[10px] opacity-70 truncate ml-auto", children: timeText })
8661
+ ] });
8662
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
8663
+ "div",
8664
+ {
8665
+ className: cn(
8666
+ "absolute rounded-lg border select-none cursor-pointer",
8667
+ "shadow-sm hover:shadow-md hover:scale-[1.02] hover:z-10",
8668
+ "transition-all duration-150 ease-out",
8669
+ "backdrop-blur-sm",
8670
+ ev.className,
8671
+ isPreview && "ring-2 ring-primary/50 ring-offset-1 ring-offset-background scale-[1.02] z-10"
8672
+ ),
8673
+ style: {
8674
+ left,
8675
+ top,
8676
+ width,
8677
+ height: eventHeight,
8678
+ background: bg,
8679
+ borderColor: border,
8680
+ borderLeftWidth: 3
8681
+ },
8682
+ role: "button",
8683
+ tabIndex: 0,
8684
+ "aria-label": aria,
8685
+ onClick: () => onEventClick?.(ev),
8686
+ onDoubleClick: () => onEventDoubleClick?.(ev),
8687
+ onPointerDown: (e) => onPointerDownEvent(e, ev, "move"),
8688
+ children: [
8689
+ (interactions?.resizableEvents ?? true) && ev.resizable !== false ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
8690
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8691
+ "div",
8692
+ {
8693
+ className: "absolute left-0 top-0 h-full w-2 cursor-ew-resize opacity-0 hover:opacity-100 bg-primary/20 rounded-l-lg transition-opacity",
8694
+ onPointerDown: (e) => onPointerDownEvent(e, ev, "resize-start")
8695
+ }
8486
8696
  ),
8487
- style: {
8488
- left,
8489
- top,
8490
- width,
8491
- height: eventHeight,
8492
- background: bg,
8493
- borderColor: border
8494
- },
8495
- role: "button",
8496
- tabIndex: 0,
8497
- "aria-label": aria,
8498
- onClick: () => onEventClick?.(ev),
8499
- onDoubleClick: () => onEventDoubleClick?.(ev),
8500
- onPointerDown: (e) => onPointerDownEvent(e, ev, "move"),
8501
- children: [
8502
- (interactions?.resizableEvents ?? true) && ev.resizable !== false ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
8503
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8504
- "div",
8505
- {
8506
- className: "absolute left-0 top-0 h-full w-2 cursor-ew-resize",
8507
- onPointerDown: (e) => onPointerDownEvent(e, ev, "resize-start")
8508
- }
8509
- ),
8510
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8511
- "div",
8512
- {
8513
- className: "absolute right-0 top-0 h-full w-2 cursor-ew-resize",
8514
- onPointerDown: (e) => onPointerDownEvent(e, ev, "resize-end")
8515
- }
8516
- )
8517
- ] }) : null,
8518
- node
8519
- ]
8520
- },
8521
- ev.id
8522
- );
8523
- }),
8524
- preview && preview.resourceId === r.id && !preview.eventId ? (() => {
8525
- const startIdx = binarySearchLastLE(slotStarts, preview.start);
8526
- const endIdx = clamp3(binarySearchFirstGE(slotStarts, preview.end), startIdx + 1, slots.length);
8527
- const left = startIdx * slotWidth;
8528
- const width = Math.max(1, (endIdx - startIdx) * slotWidth);
8529
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8530
- "div",
8531
- {
8532
- className: "absolute rounded-md border border-primary/60 bg-primary/20",
8533
- style: { left, top: lanePaddingY, width, height: eventHeight }
8534
- }
8535
- );
8536
- })() : null,
8537
- canMore ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8538
- "button",
8539
- {
8540
- type: "button",
8541
- className: "absolute right-2 bottom-1 text-[11px] text-primary hover:underline",
8542
- onClick: () => onMoreClick?.({ resourceId: r.id, hiddenEvents: layout.hidden }),
8543
- children: l.more(layout.hidden.length)
8544
- }
8545
- ) : null
8546
- ]
8547
- }
8548
- )
8697
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8698
+ "div",
8699
+ {
8700
+ className: "absolute right-0 top-0 h-full w-2 cursor-ew-resize opacity-0 hover:opacity-100 bg-primary/20 rounded-r-lg transition-opacity",
8701
+ onPointerDown: (e) => onPointerDownEvent(e, ev, "resize-end")
8702
+ }
8703
+ )
8704
+ ] }) : null,
8705
+ node
8706
+ ]
8707
+ },
8708
+ ev.id
8709
+ );
8710
+ }),
8711
+ preview && preview.resourceId === r.id && !preview.eventId ? (() => {
8712
+ const startIdx = binarySearchLastLE(slotStarts, preview.start);
8713
+ const endIdx = clamp3(binarySearchFirstGE(slotStarts, preview.end), startIdx + 1, slots.length);
8714
+ const left = startIdx * slotWidth;
8715
+ const width = Math.max(1, (endIdx - startIdx) * slotWidth);
8716
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
8717
+ "div",
8718
+ {
8719
+ className: "absolute rounded-lg border-2 border-dashed border-primary/60 bg-primary/10 backdrop-blur-sm animate-pulse",
8720
+ style: { left, top: lanePaddingY, width, height: eventHeight }
8721
+ }
8722
+ );
8723
+ })() : null,
8724
+ canMore ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
8725
+ "button",
8726
+ {
8727
+ type: "button",
8728
+ className: cn(
8729
+ "absolute right-2 bottom-1.5 text-[10px] font-semibold",
8730
+ "px-2 py-0.5 rounded-full",
8731
+ "bg-primary/10 text-primary hover:bg-primary/20",
8732
+ "transition-all duration-200 hover:scale-105"
8733
+ ),
8734
+ onClick: () => onMoreClick?.({ resourceId: r.id, hiddenEvents: layout.hidden }),
8735
+ children: [
8736
+ "+",
8737
+ layout.hidden.length,
8738
+ " ",
8739
+ l.more(layout.hidden.length).replace(/^\+?\d+\s*/, "")
8740
+ ]
8741
+ }
8742
+ ) : null
8743
+ ] })
8549
8744
  ]
8550
8745
  },
8551
8746
  `r_${r.id}_${rowIndex}`
@@ -8561,7 +8756,7 @@ function CalendarTimeline({
8561
8756
  }
8562
8757
 
8563
8758
  // ../../components/ui/MultiCombobox.tsx
8564
- var React28 = __toESM(require("react"), 1);
8759
+ var React29 = __toESM(require("react"), 1);
8565
8760
  var import_react16 = require("react");
8566
8761
  var import_lucide_react19 = require("lucide-react");
8567
8762
  var import_jsx_runtime34 = require("react/jsx-runtime");
@@ -8596,27 +8791,27 @@ var MultiCombobox = ({
8596
8791
  helperText,
8597
8792
  maxTagsVisible = 3
8598
8793
  }) => {
8599
- const [query, setQuery] = React28.useState("");
8600
- const [open, setOpen] = React28.useState(false);
8601
- const [activeIndex, setActiveIndex] = React28.useState(null);
8602
- const inputRef = React28.useRef(null);
8603
- const listRef = React28.useRef([]);
8604
- const triggerRef = React28.useRef(null);
8794
+ const [query, setQuery] = React29.useState("");
8795
+ const [open, setOpen] = React29.useState(false);
8796
+ const [activeIndex, setActiveIndex] = React29.useState(null);
8797
+ const inputRef = React29.useRef(null);
8798
+ const listRef = React29.useRef([]);
8799
+ const triggerRef = React29.useRef(null);
8605
8800
  useShadCNAnimations();
8606
- const normalizedOptions = React28.useMemo(
8801
+ const normalizedOptions = React29.useMemo(
8607
8802
  () => options.map(
8608
8803
  (o) => typeof o === "string" ? { value: o, label: o } : { value: o.value, label: o.label, icon: o.icon, description: o.description, disabled: o.disabled, group: o.group }
8609
8804
  ),
8610
8805
  [options]
8611
8806
  );
8612
8807
  const enableSearch = normalizedOptions.length > 10;
8613
- const filtered = React28.useMemo(
8808
+ const filtered = React29.useMemo(
8614
8809
  () => enableSearch ? normalizedOptions.filter(
8615
8810
  (opt) => opt.label.toLowerCase().includes(query.toLowerCase()) || opt.description?.toLowerCase().includes(query.toLowerCase())
8616
8811
  ) : normalizedOptions,
8617
8812
  [normalizedOptions, query, enableSearch]
8618
8813
  );
8619
- const groupedOptions = React28.useMemo(() => {
8814
+ const groupedOptions = React29.useMemo(() => {
8620
8815
  if (!groupBy) return null;
8621
8816
  const groups = /* @__PURE__ */ new Map();
8622
8817
  filtered.forEach((opt) => {
@@ -8652,7 +8847,7 @@ var MultiCombobox = ({
8652
8847
  const handleClearAll = () => {
8653
8848
  onChange([]);
8654
8849
  };
8655
- React28.useEffect(() => {
8850
+ React29.useEffect(() => {
8656
8851
  if (open && enableSearch) {
8657
8852
  setTimeout(() => {
8658
8853
  inputRef.current?.focus();
@@ -8877,7 +9072,7 @@ var MultiCombobox = ({
8877
9072
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex items-center gap-1.5 flex-wrap min-h-6 flex-1", children: value.length > 0 ? showTags ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
8878
9073
  visibleTags.map((option) => {
8879
9074
  if (renderTag) {
8880
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(React28.Fragment, { children: renderTag(option, () => handleRemove(option.value)) }, option.value);
9075
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(React29.Fragment, { children: renderTag(option, () => handleRemove(option.value)) }, option.value);
8881
9076
  }
8882
9077
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
8883
9078
  "span",
@@ -9018,17 +9213,17 @@ var MultiCombobox = ({
9018
9213
  };
9019
9214
 
9020
9215
  // ../../components/ui/RadioGroup.tsx
9021
- var React29 = __toESM(require("react"), 1);
9216
+ var React30 = __toESM(require("react"), 1);
9022
9217
  var import_jsx_runtime35 = require("react/jsx-runtime");
9023
- var RadioGroupContext = React29.createContext(void 0);
9218
+ var RadioGroupContext = React30.createContext(void 0);
9024
9219
  var useRadioGroup = () => {
9025
- const context = React29.useContext(RadioGroupContext);
9220
+ const context = React30.useContext(RadioGroupContext);
9026
9221
  if (!context) {
9027
9222
  throw new Error("RadioGroupItem must be used within a RadioGroup");
9028
9223
  }
9029
9224
  return context;
9030
9225
  };
9031
- var RadioGroup = React29.forwardRef(
9226
+ var RadioGroup = React30.forwardRef(
9032
9227
  ({
9033
9228
  value,
9034
9229
  defaultValue,
@@ -9044,7 +9239,7 @@ var RadioGroup = React29.forwardRef(
9044
9239
  error = false,
9045
9240
  errorMessage
9046
9241
  }, ref) => {
9047
- const [internalValue, setInternalValue] = React29.useState(defaultValue || "");
9242
+ const [internalValue, setInternalValue] = React30.useState(defaultValue || "");
9048
9243
  const isControlled = value !== void 0;
9049
9244
  const currentValue = isControlled ? value : internalValue;
9050
9245
  const handleValueChange = (newValue) => {
@@ -9055,7 +9250,7 @@ var RadioGroup = React29.forwardRef(
9055
9250
  onValueChange?.(newValue);
9056
9251
  }
9057
9252
  };
9058
- const uniqueId = React29.useId();
9253
+ const uniqueId = React30.useId();
9059
9254
  const radioName = name || `radio-group-${uniqueId}`;
9060
9255
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
9061
9256
  RadioGroupContext.Provider,
@@ -9113,7 +9308,7 @@ var sizeStyles7 = {
9113
9308
  padding: "p-4"
9114
9309
  }
9115
9310
  };
9116
- var RadioGroupItem = React29.forwardRef(
9311
+ var RadioGroupItem = React30.forwardRef(
9117
9312
  ({ value, id, disabled, className, children, label, description, icon }, ref) => {
9118
9313
  const { value: selectedValue, onValueChange, name, disabled: groupDisabled, size = "md", variant = "default" } = useRadioGroup();
9119
9314
  const isDisabled = disabled || groupDisabled;
@@ -9290,7 +9485,7 @@ var RadioGroupItem = React29.forwardRef(
9290
9485
  RadioGroupItem.displayName = "RadioGroupItem";
9291
9486
 
9292
9487
  // ../../components/ui/Slider.tsx
9293
- var React30 = __toESM(require("react"), 1);
9488
+ var React31 = __toESM(require("react"), 1);
9294
9489
  var import_jsx_runtime36 = require("react/jsx-runtime");
9295
9490
  var SIZE_STYLES = {
9296
9491
  sm: {
@@ -9309,7 +9504,7 @@ var SIZE_STYLES = {
9309
9504
  container: "py-3"
9310
9505
  }
9311
9506
  };
9312
- var Slider = React30.forwardRef(
9507
+ var Slider = React31.forwardRef(
9313
9508
  ({
9314
9509
  className,
9315
9510
  value,
@@ -9335,7 +9530,7 @@ var Slider = React30.forwardRef(
9335
9530
  noFocus = true,
9336
9531
  ...props
9337
9532
  }, ref) => {
9338
- const [internalValue, setInternalValue] = React30.useState(defaultValue);
9533
+ const [internalValue, setInternalValue] = React31.useState(defaultValue);
9339
9534
  const isControlled = value !== void 0;
9340
9535
  const currentValue = isControlled ? value : internalValue;
9341
9536
  const handleChange = (e) => {
@@ -10336,7 +10531,7 @@ function ImageUpload({
10336
10531
  }
10337
10532
 
10338
10533
  // ../../components/ui/Carousel.tsx
10339
- var React33 = __toESM(require("react"), 1);
10534
+ var React34 = __toESM(require("react"), 1);
10340
10535
  var import_lucide_react23 = require("lucide-react");
10341
10536
  var import_jsx_runtime40 = require("react/jsx-runtime");
10342
10537
  function Carousel({
@@ -10359,19 +10554,19 @@ function Carousel({
10359
10554
  thumbnailRenderer,
10360
10555
  ariaLabel = "Carousel"
10361
10556
  }) {
10362
- const [currentIndex, setCurrentIndex] = React33.useState(0);
10363
- const [isPaused, setIsPaused] = React33.useState(false);
10364
- const [isDragging, setIsDragging] = React33.useState(false);
10365
- const [startPos, setStartPos] = React33.useState(0);
10366
- const [currentTranslate, setCurrentTranslate] = React33.useState(0);
10367
- const [prevTranslate, setPrevTranslate] = React33.useState(0);
10368
- const progressElRef = React33.useRef(null);
10369
- const carouselRef = React33.useRef(null);
10370
- const rafRef = React33.useRef(null);
10371
- const totalSlides = React33.Children.count(children);
10557
+ const [currentIndex, setCurrentIndex] = React34.useState(0);
10558
+ const [isPaused, setIsPaused] = React34.useState(false);
10559
+ const [isDragging, setIsDragging] = React34.useState(false);
10560
+ const [startPos, setStartPos] = React34.useState(0);
10561
+ const [currentTranslate, setCurrentTranslate] = React34.useState(0);
10562
+ const [prevTranslate, setPrevTranslate] = React34.useState(0);
10563
+ const progressElRef = React34.useRef(null);
10564
+ const carouselRef = React34.useRef(null);
10565
+ const rafRef = React34.useRef(null);
10566
+ const totalSlides = React34.Children.count(children);
10372
10567
  const maxIndex = Math.max(0, totalSlides - slidesToShow);
10373
10568
  const isHorizontal = orientation === "horizontal";
10374
- const scrollPrev = React33.useCallback(() => {
10569
+ const scrollPrev = React34.useCallback(() => {
10375
10570
  setCurrentIndex((prev) => {
10376
10571
  if (prev === 0) {
10377
10572
  return loop ? maxIndex : 0;
@@ -10379,7 +10574,7 @@ function Carousel({
10379
10574
  return Math.max(0, prev - slidesToScroll);
10380
10575
  });
10381
10576
  }, [loop, maxIndex, slidesToScroll]);
10382
- const scrollNext = React33.useCallback(() => {
10577
+ const scrollNext = React34.useCallback(() => {
10383
10578
  setCurrentIndex((prev) => {
10384
10579
  if (prev >= maxIndex) {
10385
10580
  return loop ? 0 : maxIndex;
@@ -10387,13 +10582,13 @@ function Carousel({
10387
10582
  return Math.min(maxIndex, prev + slidesToScroll);
10388
10583
  });
10389
10584
  }, [loop, maxIndex, slidesToScroll]);
10390
- const scrollTo = React33.useCallback(
10585
+ const scrollTo = React34.useCallback(
10391
10586
  (index) => {
10392
10587
  setCurrentIndex(Math.min(maxIndex, Math.max(0, index)));
10393
10588
  },
10394
10589
  [maxIndex]
10395
10590
  );
10396
- React33.useEffect(() => {
10591
+ React34.useEffect(() => {
10397
10592
  const handleKeyDown = (e) => {
10398
10593
  if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
10399
10594
  e.preventDefault();
@@ -10415,7 +10610,7 @@ function Carousel({
10415
10610
  return () => carousel.removeEventListener("keydown", handleKeyDown);
10416
10611
  }
10417
10612
  }, [scrollPrev, scrollNext, scrollTo, maxIndex]);
10418
- React33.useEffect(() => {
10613
+ React34.useEffect(() => {
10419
10614
  const stop = () => {
10420
10615
  if (rafRef.current != null) {
10421
10616
  cancelAnimationFrame(rafRef.current);
@@ -10474,7 +10669,7 @@ function Carousel({
10474
10669
  setCurrentTranslate(0);
10475
10670
  setPrevTranslate(0);
10476
10671
  };
10477
- React33.useEffect(() => {
10672
+ React34.useEffect(() => {
10478
10673
  onSlideChange?.(currentIndex);
10479
10674
  }, [currentIndex, onSlideChange]);
10480
10675
  const getAnimationStyles2 = () => {
@@ -10527,7 +10722,7 @@ function Carousel({
10527
10722
  role: "group",
10528
10723
  "aria-atomic": "false",
10529
10724
  "aria-live": autoScroll ? "off" : "polite",
10530
- children: React33.Children.map(children, (child, idx) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
10725
+ children: React34.Children.map(children, (child, idx) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
10531
10726
  "div",
10532
10727
  {
10533
10728
  className: cn(
@@ -10617,7 +10812,7 @@ function Carousel({
10617
10812
  "absolute bottom-0 left-0 right-0 flex gap-2 p-4 bg-linear-to-t from-black/50 to-transparent overflow-x-auto",
10618
10813
  isHorizontal ? "flex-row" : "flex-col"
10619
10814
  ),
10620
- children: React33.Children.map(children, (child, idx) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
10815
+ children: React34.Children.map(children, (child, idx) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
10621
10816
  "button",
10622
10817
  {
10623
10818
  onClick: () => scrollTo(idx),
@@ -10910,7 +11105,7 @@ function FallingIcons({
10910
11105
  }
10911
11106
 
10912
11107
  // ../../components/ui/List.tsx
10913
- var React35 = __toESM(require("react"), 1);
11108
+ var React36 = __toESM(require("react"), 1);
10914
11109
  var import_lucide_react24 = require("lucide-react");
10915
11110
  var import_jsx_runtime42 = require("react/jsx-runtime");
10916
11111
  var SIZE_STYLES2 = {
@@ -10936,7 +11131,7 @@ var ListItemSkeleton = ({ size }) => {
10936
11131
  ] })
10937
11132
  ] });
10938
11133
  };
10939
- var ListRoot = React35.forwardRef(
11134
+ var ListRoot = React36.forwardRef(
10940
11135
  ({
10941
11136
  as = "ul",
10942
11137
  ordered,
@@ -10956,7 +11151,7 @@ var ListRoot = React35.forwardRef(
10956
11151
  ...rest
10957
11152
  }, ref) => {
10958
11153
  const Comp = ordered ? "ol" : as;
10959
- const childCount = React35.Children.count(children);
11154
+ const childCount = React36.Children.count(children);
10960
11155
  const hasChildren = childCount > 0;
10961
11156
  const variantClasses2 = {
10962
11157
  plain: "",
@@ -10994,14 +11189,14 @@ var ListRoot = React35.forwardRef(
10994
11189
  className
10995
11190
  ),
10996
11191
  ...rest,
10997
- children: React35.Children.map(children, (child, idx) => {
10998
- if (!React35.isValidElement(child)) return child;
11192
+ children: React36.Children.map(children, (child, idx) => {
11193
+ if (!React36.isValidElement(child)) return child;
10999
11194
  const childClass = cn(
11000
11195
  child.props?.className,
11001
11196
  hoverable && variant !== "flush" && "hover:bg-accent/50 focus:bg-accent/60 focus:outline-none transition-colors",
11002
11197
  variant === "flush" && "hover:bg-accent/30"
11003
11198
  );
11004
- return React35.cloneElement(child, {
11199
+ return React36.cloneElement(child, {
11005
11200
  className: childClass,
11006
11201
  // Pass global item class to contentClassName of ListItem
11007
11202
  contentClassName: cn(itemClassName, child.props?.contentClassName),
@@ -11016,7 +11211,7 @@ var ListRoot = React35.forwardRef(
11016
11211
  }
11017
11212
  );
11018
11213
  ListRoot.displayName = "List";
11019
- var ListItem = React35.forwardRef(
11214
+ var ListItem = React36.forwardRef(
11020
11215
  ({
11021
11216
  as = "li",
11022
11217
  selected = false,
@@ -11039,7 +11234,7 @@ var ListItem = React35.forwardRef(
11039
11234
  children,
11040
11235
  ...rest
11041
11236
  }, ref) => {
11042
- const [internalExpanded, setInternalExpanded] = React35.useState(false);
11237
+ const [internalExpanded, setInternalExpanded] = React36.useState(false);
11043
11238
  const isExpanded = controlledExpanded !== void 0 ? controlledExpanded : internalExpanded;
11044
11239
  const sizeAttr = rest["data-size"];
11045
11240
  const resolvedSize = sizeAttr && ["xs", "sm", "md", "lg"].includes(sizeAttr) ? sizeAttr : "md";
@@ -11107,7 +11302,7 @@ var List = Object.assign(ListRoot, { Item: ListItem });
11107
11302
  var List_default = List;
11108
11303
 
11109
11304
  // ../../components/ui/Watermark.tsx
11110
- var React36 = __toESM(require("react"), 1);
11305
+ var React37 = __toESM(require("react"), 1);
11111
11306
  var import_react_dom5 = require("react-dom");
11112
11307
  var import_jsx_runtime43 = require("react/jsx-runtime");
11113
11308
  var PRESETS2 = {
@@ -11119,8 +11314,8 @@ var PRESETS2 = {
11119
11314
  internal: { text: "INTERNAL USE ONLY", color: "rgba(156, 163, 175, 0.15)", rotate: -22, fontSize: 13, fontWeight: "600" }
11120
11315
  };
11121
11316
  function useWatermarkDataURL(opts) {
11122
- const [url, setUrl] = React36.useState(null);
11123
- React36.useEffect(() => {
11317
+ const [url, setUrl] = React37.useState(null);
11318
+ React37.useEffect(() => {
11124
11319
  let cancelled = false;
11125
11320
  const text = opts.text;
11126
11321
  const image = opts.image;
@@ -11297,9 +11492,9 @@ var Watermark = ({
11297
11492
  children,
11298
11493
  ...rest
11299
11494
  }) => {
11300
- const [visible, setVisible] = React36.useState(true);
11301
- const [isDark, setIsDark] = React36.useState(false);
11302
- React36.useEffect(() => {
11495
+ const [visible, setVisible] = React37.useState(true);
11496
+ const [isDark, setIsDark] = React37.useState(false);
11497
+ React37.useEffect(() => {
11303
11498
  if (!darkMode) return;
11304
11499
  const checkDarkMode = () => {
11305
11500
  const isDarkMode = document.documentElement.classList.contains("dark") || window.matchMedia("(prefers-color-scheme: dark)").matches;
@@ -11401,7 +11596,7 @@ var Watermark = ({
11401
11596
  var Watermark_default = Watermark;
11402
11597
 
11403
11598
  // ../../components/ui/Timeline.tsx
11404
- var React37 = __toESM(require("react"), 1);
11599
+ var React38 = __toESM(require("react"), 1);
11405
11600
  var import_lucide_react25 = require("lucide-react");
11406
11601
  var import_jsx_runtime44 = require("react/jsx-runtime");
11407
11602
  var SIZE_STYLE = {
@@ -11454,7 +11649,7 @@ var STATUS_COLOR = {
11454
11649
  error: "bg-destructive",
11455
11650
  info: "bg-info"
11456
11651
  };
11457
- var TimelineContext = React37.createContext(null);
11652
+ var TimelineContext = React38.createContext(null);
11458
11653
  var LINE_STYLE_MAP = {
11459
11654
  solid: "border-solid",
11460
11655
  dashed: "border-dashed",
@@ -11482,7 +11677,7 @@ var Marker = ({ index, last, size, color, status = "default", lineColor, lineSty
11482
11677
  !last && showLine && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: cn("flex-1 border-l-2", LINE_STYLE_MAP[lineStyle]), style: { borderColor: lineColor || "hsl(var(--border))" } })
11483
11678
  ] });
11484
11679
  };
11485
- var TimelineRoot = React37.forwardRef(
11680
+ var TimelineRoot = React38.forwardRef(
11486
11681
  ({
11487
11682
  align = "left",
11488
11683
  variant = "default",
@@ -11512,7 +11707,7 @@ var TimelineRoot = React37.forwardRef(
11512
11707
  }
11513
11708
  );
11514
11709
  TimelineRoot.displayName = "Timeline";
11515
- var TimelineItem = React37.forwardRef(
11710
+ var TimelineItem = React38.forwardRef(
11516
11711
  ({
11517
11712
  title,
11518
11713
  description,
@@ -11531,11 +11726,11 @@ var TimelineItem = React37.forwardRef(
11531
11726
  children,
11532
11727
  ...rest
11533
11728
  }, ref) => {
11534
- const ctx = React37.useContext(TimelineContext);
11729
+ const ctx = React38.useContext(TimelineContext);
11535
11730
  const idx = rest["data-index"];
11536
11731
  const isLast = Boolean(rest["data-last"]);
11537
11732
  const sz = SIZE_STYLE[ctx.size];
11538
- const [internalExpanded, setInternalExpanded] = React37.useState(false);
11733
+ const [internalExpanded, setInternalExpanded] = React38.useState(false);
11539
11734
  const isExpanded = controlledExpanded !== void 0 ? controlledExpanded : internalExpanded;
11540
11735
  const toggleExpanded = () => {
11541
11736
  const newExpanded = !isExpanded;
@@ -11677,7 +11872,7 @@ var Timeline = Object.assign(TimelineRoot, { Item: TimelineItem });
11677
11872
  var Timeline_default = Timeline;
11678
11873
 
11679
11874
  // ../../components/ui/ColorPicker.tsx
11680
- var React38 = __toESM(require("react"), 1);
11875
+ var React39 = __toESM(require("react"), 1);
11681
11876
  var import_lucide_react26 = require("lucide-react");
11682
11877
  var import_jsx_runtime45 = require("react/jsx-runtime");
11683
11878
  var clamp4 = (n, min, max) => Math.max(min, Math.min(max, n));
@@ -11871,12 +12066,12 @@ function ColorPicker({
11871
12066
  }) {
11872
12067
  const isControlled = value !== void 0;
11873
12068
  const initial = parseAnyColor(isControlled ? value : defaultValue) || { r: 79, g: 70, b: 229, a: 1 };
11874
- const [rgba, setRgba] = React38.useState(initial);
11875
- const [open, setOpen] = React38.useState(false);
11876
- const [text, setText] = React38.useState(() => formatOutput(initial, withAlpha, format));
11877
- const [copied, setCopied] = React38.useState(false);
11878
- const [recentColors, setRecentColors] = React38.useState([]);
11879
- React38.useEffect(() => {
12069
+ const [rgba, setRgba] = React39.useState(initial);
12070
+ const [open, setOpen] = React39.useState(false);
12071
+ const [text, setText] = React39.useState(() => formatOutput(initial, withAlpha, format));
12072
+ const [copied, setCopied] = React39.useState(false);
12073
+ const [recentColors, setRecentColors] = React39.useState([]);
12074
+ React39.useEffect(() => {
11880
12075
  if (isControlled) {
11881
12076
  const parsed = parseAnyColor(value);
11882
12077
  if (parsed) {
@@ -14828,10 +15023,10 @@ function DataTable({
14828
15023
  var DataTable_default = DataTable;
14829
15024
 
14830
15025
  // ../../components/ui/Form.tsx
14831
- var React53 = __toESM(require("react"), 1);
15026
+ var React54 = __toESM(require("react"), 1);
14832
15027
  var import_react_hook_form = require("react-hook-form");
14833
15028
  var import_jsx_runtime61 = require("react/jsx-runtime");
14834
- var FormConfigContext = React53.createContext({ size: "md" });
15029
+ var FormConfigContext = React54.createContext({ size: "md" });
14835
15030
  var FormWrapper = ({
14836
15031
  children,
14837
15032
  onSubmit,
@@ -14844,7 +15039,7 @@ var FormWrapper = ({
14844
15039
  const methods = (0, import_react_hook_form.useForm)({
14845
15040
  defaultValues: initialValues
14846
15041
  });
14847
- React53.useEffect(() => {
15042
+ React54.useEffect(() => {
14848
15043
  if (initialValues) {
14849
15044
  methods.reset(initialValues);
14850
15045
  }
@@ -14853,15 +15048,15 @@ var FormWrapper = ({
14853
15048
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_react_hook_form.FormProvider, { ...methods, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(FormConfigContext.Provider, { value: { size }, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("form", { onSubmit: methods.handleSubmit(onSubmit), className, ...formProps, children }) }) });
14854
15049
  };
14855
15050
  var Form = FormWrapper;
14856
- var FormFieldContext = React53.createContext({});
15051
+ var FormFieldContext = React54.createContext({});
14857
15052
  var FormField = ({
14858
15053
  ...props
14859
15054
  }) => {
14860
15055
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_react_hook_form.Controller, { ...props }) });
14861
15056
  };
14862
15057
  var useFormField = () => {
14863
- const fieldContext = React53.useContext(FormFieldContext);
14864
- const itemContext = React53.useContext(FormItemContext);
15058
+ const fieldContext = React54.useContext(FormFieldContext);
15059
+ const itemContext = React54.useContext(FormItemContext);
14865
15060
  const { getFieldState, formState } = (0, import_react_hook_form.useFormContext)();
14866
15061
  if (!fieldContext) {
14867
15062
  try {
@@ -14882,16 +15077,16 @@ var useFormField = () => {
14882
15077
  ...fieldState
14883
15078
  };
14884
15079
  };
14885
- var FormItemContext = React53.createContext({});
14886
- var FormItem = React53.forwardRef(({ className, ...props }, ref) => {
14887
- const id = React53.useId();
15080
+ var FormItemContext = React54.createContext({});
15081
+ var FormItem = React54.forwardRef(({ className, ...props }, ref) => {
15082
+ const id = React54.useId();
14888
15083
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { ref, className: cn("space-y-2", className), ...props }) });
14889
15084
  });
14890
15085
  FormItem.displayName = "FormItem";
14891
- var FormLabel = React53.forwardRef(
15086
+ var FormLabel = React54.forwardRef(
14892
15087
  ({ className, children, required, ...props }, ref) => {
14893
15088
  const { error, formItemId } = useFormField();
14894
- const config = React53.useContext(FormConfigContext);
15089
+ const config = React54.useContext(FormConfigContext);
14895
15090
  const sizeClass = config.size === "sm" ? "text-xs" : config.size === "lg" ? "text-base" : "text-sm";
14896
15091
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(Label, { ref, className: cn(sizeClass, error && "text-destructive", className), htmlFor: formItemId, ...props, children: [
14897
15092
  children,
@@ -14900,7 +15095,7 @@ var FormLabel = React53.forwardRef(
14900
15095
  }
14901
15096
  );
14902
15097
  FormLabel.displayName = "FormLabel";
14903
- var FormControl = React53.forwardRef(({ ...props }, ref) => {
15098
+ var FormControl = React54.forwardRef(({ ...props }, ref) => {
14904
15099
  const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
14905
15100
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
14906
15101
  "div",
@@ -14914,12 +15109,12 @@ var FormControl = React53.forwardRef(({ ...props }, ref) => {
14914
15109
  );
14915
15110
  });
14916
15111
  FormControl.displayName = "FormControl";
14917
- var FormDescription = React53.forwardRef(({ className, ...props }, ref) => {
15112
+ var FormDescription = React54.forwardRef(({ className, ...props }, ref) => {
14918
15113
  const { formDescriptionId } = useFormField();
14919
15114
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { ref, id: formDescriptionId, className: cn("text-sm text-muted-foreground", className), ...props });
14920
15115
  });
14921
15116
  FormDescription.displayName = "FormDescription";
14922
- var FormMessage = React53.forwardRef(({ className, children, ...props }, ref) => {
15117
+ var FormMessage = React54.forwardRef(({ className, children, ...props }, ref) => {
14923
15118
  const { error, formMessageId } = useFormField();
14924
15119
  const body = error ? String(error?.message) : children;
14925
15120
  if (!body) {
@@ -14928,7 +15123,7 @@ var FormMessage = React53.forwardRef(({ className, children, ...props }, ref) =>
14928
15123
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { ref, id: formMessageId, className: cn("text-sm font-medium text-destructive", className), ...props, children: body });
14929
15124
  });
14930
15125
  FormMessage.displayName = "FormMessage";
14931
- var FormInput = React53.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
15126
+ var FormInput = React54.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
14932
15127
  FormField,
14933
15128
  {
14934
15129
  name,
@@ -14939,7 +15134,7 @@ var FormInput = React53.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */
14939
15134
  }
14940
15135
  ) }));
14941
15136
  FormInput.displayName = "FormInput";
14942
- var FormCheckbox = React53.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
15137
+ var FormCheckbox = React54.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
14943
15138
  FormField,
14944
15139
  {
14945
15140
  name,
@@ -14963,9 +15158,9 @@ var FormCheckbox = React53.forwardRef(({ name, ...props }, ref) => /* @__PURE__
14963
15158
  }
14964
15159
  ) }));
14965
15160
  FormCheckbox.displayName = "FormCheckbox";
14966
- var FormActions = React53.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { ref, className: cn("flex gap-2 justify-end", className), ...props }));
15161
+ var FormActions = React54.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { ref, className: cn("flex gap-2 justify-end", className), ...props }));
14967
15162
  FormActions.displayName = "FormActions";
14968
- var FormSubmitButton = React53.forwardRef(
15163
+ var FormSubmitButton = React54.forwardRef(
14969
15164
  ({ children, loading: loading2, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Button_default, { ref, type: "submit", size: props.size ?? size, disabled: loading2, ...props, children }) })
14970
15165
  );
14971
15166
  FormSubmitButton.displayName = "FormSubmitButton";
@@ -15747,7 +15942,7 @@ var VARIANT_STYLES_ALERT = {
15747
15942
  };
15748
15943
 
15749
15944
  // src/contexts/TranslationContext.tsx
15750
- var React55 = __toESM(require("react"), 1);
15945
+ var React56 = __toESM(require("react"), 1);
15751
15946
 
15752
15947
  // locales/en.json
15753
15948
  var en_default = {
@@ -16101,9 +16296,9 @@ var defaultTranslations2 = {
16101
16296
  ko: ko_default,
16102
16297
  ja: ja_default
16103
16298
  };
16104
- var TranslationContext2 = React55.createContext(null);
16299
+ var TranslationContext2 = React56.createContext(null);
16105
16300
  var TranslationProvider = ({ children, locale = "en", translations }) => {
16106
- const t = React55.useCallback(
16301
+ const t = React56.useCallback(
16107
16302
  (namespace) => {
16108
16303
  return (key) => {
16109
16304
  const mergedTranslations = {
@@ -16131,7 +16326,7 @@ var TranslationProvider = ({ children, locale = "en", translations }) => {
16131
16326
  return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(TranslationContext2.Provider, { value: { locale, t }, children });
16132
16327
  };
16133
16328
  var useUnderverseTranslations = (namespace) => {
16134
- const context = React55.useContext(TranslationContext2);
16329
+ const context = React56.useContext(TranslationContext2);
16135
16330
  if (!context) {
16136
16331
  return (key) => {
16137
16332
  const parts = namespace.split(".");
@@ -16153,12 +16348,12 @@ var useUnderverseTranslations = (namespace) => {
16153
16348
  return context.t(namespace);
16154
16349
  };
16155
16350
  var useUnderverseLocale = () => {
16156
- const context = React55.useContext(TranslationContext2);
16351
+ const context = React56.useContext(TranslationContext2);
16157
16352
  return context?.locale || "en";
16158
16353
  };
16159
16354
 
16160
16355
  // src/hooks/useSmartTranslations.tsx
16161
- var React56 = __toESM(require("react"), 1);
16356
+ var React57 = __toESM(require("react"), 1);
16162
16357
  var import_jsx_runtime68 = require("react/jsx-runtime");
16163
16358
  var nextIntlHooks = null;
16164
16359
  try {
@@ -16170,12 +16365,12 @@ try {
16170
16365
  } catch {
16171
16366
  nextIntlHooks = null;
16172
16367
  }
16173
- var ForceInternalContext = React56.createContext(false);
16368
+ var ForceInternalContext = React57.createContext(false);
16174
16369
  var ForceInternalTranslationsProvider = ({ children }) => {
16175
16370
  return /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(ForceInternalContext.Provider, { value: true, children });
16176
16371
  };
16177
16372
  function useSmartTranslations(namespace) {
16178
- const forceInternal = React56.useContext(ForceInternalContext);
16373
+ const forceInternal = React57.useContext(ForceInternalContext);
16179
16374
  const internalT = useUnderverseTranslations(namespace);
16180
16375
  if (forceInternal || !nextIntlHooks?.useTranslations) {
16181
16376
  return internalT;
@@ -16188,7 +16383,7 @@ function useSmartTranslations(namespace) {
16188
16383
  }
16189
16384
  }
16190
16385
  function useSmartLocale() {
16191
- const forceInternal = React56.useContext(ForceInternalContext);
16386
+ const forceInternal = React57.useContext(ForceInternalContext);
16192
16387
  const internalLocale = useUnderverseLocale();
16193
16388
  if (forceInternal || !nextIntlHooks?.useLocale) {
16194
16389
  return internalLocale;
@@ -18049,9 +18244,9 @@ var UEditor = ({
18049
18244
  "[&_ul[data-type='taskList']_li>label>input]:border-2",
18050
18245
  "[&_ul[data-type='taskList']_li>label>input]:border-primary/50",
18051
18246
  "[&_ul[data-type='taskList']_li>label>input]:accent-primary",
18052
- "[&_pre]:!bg-[#1e1e1e]",
18053
- "[&_pre]:!text-[#d4d4d4]",
18054
- "[&_pre_code]:!bg-transparent",
18247
+ "[&_pre]:bg-[#1e1e1e]!",
18248
+ "[&_pre]:text-[#d4d4d4]!",
18249
+ "[&_pre_code]:bg-transparent!",
18055
18250
  "[&_img.ProseMirror-selectednode]:ring-2",
18056
18251
  "[&_img.ProseMirror-selectednode]:ring-primary/60",
18057
18252
  "[&_img.ProseMirror-selectednode]:ring-offset-2",