@juv/codego-react-ui 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4943,6 +4943,45 @@ function addTerrain(map) {
4943
4943
  });
4944
4944
  }
4945
4945
  }
4946
+ var OSRM_PROFILE2 = { drive: "driving", walk: "foot" };
4947
+ async function fetchOsrmRoute2(points, routeType) {
4948
+ const profile = OSRM_PROFILE2[routeType];
4949
+ const coords = points.map((p) => `${p.lng},${p.lat}`).join(";");
4950
+ const res = await fetch(`https://router.project-osrm.org/route/v1/${profile}/${coords}?overview=full&geometries=geojson`);
4951
+ if (!res.ok) throw new Error("OSRM failed");
4952
+ const data = await res.json();
4953
+ if (data.code !== "Ok" || !data.routes?.length) throw new Error("No route");
4954
+ const route = data.routes[0];
4955
+ return {
4956
+ coords: route.geometry.coordinates,
4957
+ // already [lng, lat] for MapLibre
4958
+ distance: route.distance,
4959
+ duration: route.duration
4960
+ };
4961
+ }
4962
+ function fmtDistance2(m) {
4963
+ return m >= 1e3 ? `${(m / 1e3).toFixed(1)} km` : `${Math.round(m)} m`;
4964
+ }
4965
+ function fmtDuration2(s) {
4966
+ const h = Math.floor(s / 3600), m = Math.floor(s % 3600 / 60);
4967
+ return h > 0 ? `${h}h ${m}min` : `${m} min`;
4968
+ }
4969
+ function makeClusterHTML(variant, count, color) {
4970
+ if (variant === "bubble") {
4971
+ const size = count > 99 ? 52 : count > 9 ? 44 : 36;
4972
+ return `<div style="width:${size}px;height:${size}px;border-radius:50%;background:${color};color:#fff;font-weight:700;font-size:${count > 99 ? 11 : 13}px;font-family:sans-serif;display:flex;align-items:center;justify-content:center;border:3px solid white;box-shadow:0 2px 8px rgba(0,0,0,.3);">${count}</div>`;
4973
+ }
4974
+ if (variant === "donut") {
4975
+ const r = 20, stroke = 5, circ = 2 * Math.PI * r;
4976
+ const dash = Math.min(count / 50, 1) * circ;
4977
+ return `<svg width="54" height="54" viewBox="0 0 54 54"><circle cx="27" cy="27" r="${r}" fill="none" stroke="${color}33" stroke-width="${stroke}"/><circle cx="27" cy="27" r="${r}" fill="none" stroke="${color}" stroke-width="${stroke}" stroke-dasharray="${dash} ${circ}" stroke-dashoffset="${circ / 4}" stroke-linecap="round"/><circle cx="27" cy="27" r="${r - stroke - 2}" fill="${color}22"/><text x="27" y="27" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="${color}" font-family="sans-serif">${count}</text></svg>`;
4978
+ }
4979
+ const w = count > 99 ? 52 : 40;
4980
+ return `<div style="min-width:${w}px;height:28px;border-radius:14px;background:${color};color:#fff;font-weight:700;font-size:12px;font-family:sans-serif;display:flex;align-items:center;justify-content:center;padding:0 8px;border:2px solid white;box-shadow:0 2px 8px rgba(0,0,0,.25);">${count}</div>`;
4981
+ }
4982
+ function makeEndpointHTML(color, label) {
4983
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28"><circle cx="14" cy="14" r="12" fill="${color}" stroke="white" stroke-width="2.5"/><text x="14" y="14" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="white" font-family="sans-serif">${label}</text></svg>`;
4984
+ }
4946
4985
  function MapLibreMap({
4947
4986
  style: styleProp = "street",
4948
4987
  center = [0, 20],
@@ -4957,6 +4996,9 @@ function MapLibreMap({
4957
4996
  maxBearing = 180,
4958
4997
  flyTo,
4959
4998
  markers = [],
4999
+ routes = [],
5000
+ cluster = false,
5001
+ clusterVariant = "default",
4960
5002
  height = 480,
4961
5003
  showControls = true,
4962
5004
  showStyleSwitcher = true,
@@ -4967,7 +5009,9 @@ function MapLibreMap({
4967
5009
  const containerRef = React22.useRef(null);
4968
5010
  const mapRef = React22.useRef(null);
4969
5011
  const markersRef = React22.useRef([]);
5012
+ const routeMarkersRef = React22.useRef([]);
4970
5013
  const flyingRef = React22.useRef(false);
5014
+ const [routeLoading, setRouteLoading] = React22.useState(false);
4971
5015
  const [activeStyle, setActiveStyle] = React22.useState(styleProp);
4972
5016
  const [ready, setReady] = React22.useState(false);
4973
5017
  const [showCamera, setShowCamera] = React22.useState(false);
@@ -5055,6 +5099,109 @@ function MapLibreMap({
5055
5099
  if (ftBearing !== void 0) setBearing(clampBearing(ftBearing));
5056
5100
  });
5057
5101
  }, [flyTo]);
5102
+ React22.useEffect(() => {
5103
+ const map = mapRef.current;
5104
+ if (!map || !ready || routes.length === 0) return;
5105
+ function cleanRoutes() {
5106
+ routeMarkersRef.current.forEach((m) => m.remove());
5107
+ routeMarkersRef.current = [];
5108
+ const style = map.getStyle();
5109
+ (style.layers ?? []).forEach((l) => {
5110
+ if (l.id.startsWith("route-")) try {
5111
+ map.removeLayer(l.id);
5112
+ } catch {
5113
+ }
5114
+ });
5115
+ Object.keys(style.sources ?? {}).forEach((s) => {
5116
+ if (s.startsWith("route-")) try {
5117
+ map.removeSource(s);
5118
+ } catch {
5119
+ }
5120
+ });
5121
+ }
5122
+ cleanRoutes();
5123
+ setRouteLoading(true);
5124
+ Promise.all(
5125
+ routes.map(async (r, i) => {
5126
+ const points = [r.start, ...r.waypoints ?? [], r.end];
5127
+ try {
5128
+ const result = await fetchOsrmRoute2(points, r.routeType ?? "drive");
5129
+ return { route: r, idx: i, ...result, error: false };
5130
+ } catch {
5131
+ return { route: r, idx: i, coords: points.map((p) => [p.lng, p.lat]), distance: 0, duration: 0, error: true };
5132
+ }
5133
+ })
5134
+ ).then((results) => {
5135
+ setRouteLoading(false);
5136
+ if (!mapRef.current) return;
5137
+ const m = mapRef.current;
5138
+ const allCoords = [];
5139
+ results.forEach(({ route, idx, coords, distance, duration }) => {
5140
+ const color = route.color ?? (route.routeType === "walk" ? "#22c55e" : "#6366f1");
5141
+ const srcId = `route-${idx}`;
5142
+ const geojson = {
5143
+ type: "Feature",
5144
+ properties: {},
5145
+ geometry: { type: "LineString", coordinates: coords }
5146
+ };
5147
+ m.addSource(srcId, { type: "geojson", data: geojson });
5148
+ m.addLayer({
5149
+ id: `${srcId}-outline`,
5150
+ type: "line",
5151
+ source: srcId,
5152
+ layout: { "line-cap": "round", "line-join": "round" },
5153
+ paint: { "line-color": "#ffffff", "line-width": (route.weight ?? 5) + 4, "line-opacity": 0.3 }
5154
+ });
5155
+ m.addLayer({
5156
+ id: `${srcId}-line`,
5157
+ type: "line",
5158
+ source: srcId,
5159
+ layout: { "line-cap": "round", "line-join": "round" },
5160
+ paint: { "line-color": color, "line-width": route.weight ?? 5, "line-opacity": 0.9 }
5161
+ });
5162
+ allCoords.push(...coords);
5163
+ const makeEndpointMarker = (lngLat, label, markerColor, popupHtml) => {
5164
+ const el = document.createElement("div");
5165
+ el.innerHTML = makeEndpointHTML(markerColor, label);
5166
+ el.style.cssText = "width:28px;height:28px";
5167
+ const popup = new maplibregl.Popup({ offset: [0, -16], closeButton: false }).setHTML(popupHtml);
5168
+ const marker = new maplibregl.Marker({ element: el, anchor: "center" }).setLngLat(lngLat).setPopup(popup).addTo(m);
5169
+ routeMarkersRef.current.push(marker);
5170
+ };
5171
+ const infoHtml = distance > 0 ? `<p style="font-size:11px;color:#888;margin:2px 0 0">${fmtDistance2(distance)} \xB7 ${fmtDuration2(duration)} \xB7 ${route.routeType === "walk" ? "\u{1F6B6} Walk" : "\u{1F697} Drive"}</p>` : "";
5172
+ makeEndpointMarker(
5173
+ [route.start.lng, route.start.lat],
5174
+ "A",
5175
+ color,
5176
+ `<div style="padding:2px;min-width:120px"><p style="font-weight:700;font-size:13px;margin:0">${route.label ? `${route.label} \u2014 Start` : "Start"}</p>${infoHtml}</div>`
5177
+ );
5178
+ makeEndpointMarker(
5179
+ [route.end.lng, route.end.lat],
5180
+ "B",
5181
+ "#ef4444",
5182
+ `<div style="padding:2px;min-width:120px"><p style="font-weight:700;font-size:13px;margin:0">${route.label ? `${route.label} \u2014 End` : "End"}</p>${infoHtml}</div>`
5183
+ );
5184
+ if (distance > 0 && coords.length > 1) {
5185
+ const mid = coords[Math.floor(coords.length / 2)];
5186
+ const text = `${fmtDistance2(distance)} \xB7 ${fmtDuration2(duration)}`;
5187
+ const estW = text.length * 7 + 16;
5188
+ const el = document.createElement("div");
5189
+ el.innerHTML = `<div style="display:inline-flex;align-items:center;justify-content:center;background:${color};color:white;font-size:11px;font-weight:600;font-family:sans-serif;padding:3px 8px;border-radius:12px;border:2px solid white;box-shadow:0 2px 6px rgba(0,0,0,.25);white-space:nowrap;">${text}</div>`;
5190
+ el.style.cssText = `width:${estW}px;height:22px;pointer-events:none`;
5191
+ const badge = new maplibregl.Marker({ element: el, anchor: "center" }).setLngLat(mid).addTo(m);
5192
+ routeMarkersRef.current.push(badge);
5193
+ }
5194
+ });
5195
+ if (allCoords.length > 1) {
5196
+ const lngs = allCoords.map((c) => c[0]), lats = allCoords.map((c) => c[1]);
5197
+ m.fitBounds(
5198
+ [[Math.min(...lngs), Math.min(...lats)], [Math.max(...lngs), Math.max(...lats)]],
5199
+ { padding: 60, duration: 800 }
5200
+ );
5201
+ }
5202
+ });
5203
+ return cleanRoutes;
5204
+ }, [routes, ready]);
5058
5205
  function switchStyle(s) {
5059
5206
  const map = mapRef.current;
5060
5207
  if (!map) return;
@@ -5062,6 +5209,8 @@ function MapLibreMap({
5062
5209
  setReady(false);
5063
5210
  markersRef.current.forEach((m) => m.remove());
5064
5211
  markersRef.current = [];
5212
+ routeMarkersRef.current.forEach((m) => m.remove());
5213
+ routeMarkersRef.current = [];
5065
5214
  map.setStyle(s === "satellite" ? SATELLITE_STYLE : STYLE_URLS[s]);
5066
5215
  map.once("style.load", () => {
5067
5216
  if (s === "globe") {
@@ -5093,32 +5242,107 @@ function MapLibreMap({
5093
5242
  setReady(true);
5094
5243
  });
5095
5244
  }
5245
+ const [mapZoom, setMapZoom] = React22.useState(zoom);
5246
+ React22.useEffect(() => {
5247
+ const map = mapRef.current;
5248
+ if (!map) return;
5249
+ const h2 = () => setMapZoom(map.getZoom());
5250
+ map.on("zoomend", h2);
5251
+ return () => {
5252
+ map.off("zoomend", h2);
5253
+ };
5254
+ }, [ready]);
5096
5255
  React22.useEffect(() => {
5097
5256
  const map = mapRef.current;
5098
5257
  if (!map || !ready) return;
5099
5258
  markersRef.current.forEach((m) => m.remove());
5100
5259
  markersRef.current = [];
5101
- markers.forEach((m) => {
5102
- const color = resolveColor2(m.color);
5103
- const el = document.createElement("div");
5104
- el.innerHTML = makePinHTML(color, m.icon, m.image);
5105
- el.style.cssText = m.image ? "width:40px;height:50px" : "width:32px;height:42px";
5106
- const popup = new maplibregl.Popup({ offset: m.image ? [0, -52] : [0, -44], closeButton: false });
5107
- if (m.popup) {
5108
- if (typeof m.popup === "string") popup.setHTML(m.popup);
5109
- else popup.setDOMContent(m.popup);
5110
- } else if (m.label) {
5111
- popup.setHTML(`<span style="font-size:13px;font-weight:600">${m.label}</span>`);
5112
- }
5113
- const marker = new maplibregl.Marker({ element: el, anchor: "bottom" }).setLngLat([m.lng, m.lat]);
5114
- if (m.popup || m.label) marker.setPopup(popup);
5115
- el.addEventListener("click", () => onMarkerClick?.(m));
5116
- marker.addTo(map);
5117
- markersRef.current.push(marker);
5118
- });
5119
- }, [markers, ready, onMarkerClick]);
5260
+ if (cluster && markers.length > 0) {
5261
+ const GRID = 80;
5262
+ const used = /* @__PURE__ */ new Set();
5263
+ const groups = [];
5264
+ markers.forEach((m, i) => {
5265
+ if (used.has(i)) return;
5266
+ const pt = map.project([m.lng, m.lat]);
5267
+ const group = [m];
5268
+ used.add(i);
5269
+ markers.forEach((m2, j) => {
5270
+ if (used.has(j)) return;
5271
+ const pt2 = map.project([m2.lng, m2.lat]);
5272
+ if (Math.abs(pt.x - pt2.x) < GRID && Math.abs(pt.y - pt2.y) < GRID) {
5273
+ group.push(m2);
5274
+ used.add(j);
5275
+ }
5276
+ });
5277
+ const lat = group.reduce((s, x) => s + x.lat, 0) / group.length;
5278
+ const lng = group.reduce((s, x) => s + x.lng, 0) / group.length;
5279
+ groups.push({ center: { lng, lat }, items: group });
5280
+ });
5281
+ groups.forEach((g, gi) => {
5282
+ if (g.items.length === 1) {
5283
+ const m = g.items[0];
5284
+ const color = resolveColor2(m.color);
5285
+ const el = document.createElement("div");
5286
+ el.innerHTML = makePinHTML(color, m.icon, m.image);
5287
+ el.style.cssText = m.image ? "width:40px;height:50px" : "width:32px;height:42px";
5288
+ const popup = new maplibregl.Popup({ offset: m.image ? [0, -52] : [0, -44], closeButton: false });
5289
+ if (m.popup) {
5290
+ typeof m.popup === "string" ? popup.setHTML(m.popup) : popup.setDOMContent(m.popup);
5291
+ } else if (m.label) popup.setHTML(`<span style="font-size:13px;font-weight:600">${m.label}</span>`);
5292
+ const marker = new maplibregl.Marker({ element: el, anchor: "bottom" }).setLngLat([m.lng, m.lat]);
5293
+ if (m.popup || m.label) marker.setPopup(popup);
5294
+ el.addEventListener("click", () => onMarkerClick?.(m));
5295
+ marker.addTo(map);
5296
+ markersRef.current.push(marker);
5297
+ } else {
5298
+ const color = resolveColor2(g.items[0].color);
5299
+ const el = document.createElement("div");
5300
+ el.innerHTML = makeClusterHTML(clusterVariant, g.items.length, color);
5301
+ el.style.cssText = "cursor:pointer";
5302
+ const listItems = g.items.map(
5303
+ (m) => `<div data-id="${m.id}" style="font-size:12px;padding:2px 0;cursor:pointer;">${m.label ?? `Marker ${m.id}`}</div>`
5304
+ ).join("");
5305
+ const popup = new maplibregl.Popup({ offset: [0, -8], closeButton: false }).setHTML(`<div style="max-height:160px;overflow-y:auto;padding:2px">${listItems}</div>`);
5306
+ el.addEventListener("click", () => {
5307
+ map.flyTo({ center: [g.center.lng, g.center.lat], zoom: map.getZoom() + 2, duration: 400 });
5308
+ });
5309
+ const marker = new maplibregl.Marker({ element: el, anchor: "center" }).setLngLat([g.center.lng, g.center.lat]).setPopup(popup).addTo(map);
5310
+ markersRef.current.push(marker);
5311
+ marker.getPopup().on("open", () => {
5312
+ g.items.forEach((m) => {
5313
+ const node = document.querySelector(`[data-id="${m.id}"]`);
5314
+ node?.addEventListener("click", () => onMarkerClick?.(m));
5315
+ });
5316
+ });
5317
+ }
5318
+ });
5319
+ } else {
5320
+ markers.forEach((m) => {
5321
+ const color = resolveColor2(m.color);
5322
+ const el = document.createElement("div");
5323
+ el.innerHTML = makePinHTML(color, m.icon, m.image);
5324
+ el.style.cssText = m.image ? "width:40px;height:50px" : "width:32px;height:42px";
5325
+ const popup = new maplibregl.Popup({ offset: m.image ? [0, -52] : [0, -44], closeButton: false });
5326
+ if (m.popup) {
5327
+ if (typeof m.popup === "string") popup.setHTML(m.popup);
5328
+ else popup.setDOMContent(m.popup);
5329
+ } else if (m.label) {
5330
+ popup.setHTML(`<span style="font-size:13px;font-weight:600">${m.label}</span>`);
5331
+ }
5332
+ const marker = new maplibregl.Marker({ element: el, anchor: "bottom" }).setLngLat([m.lng, m.lat]);
5333
+ if (m.popup || m.label) marker.setPopup(popup);
5334
+ el.addEventListener("click", () => onMarkerClick?.(m));
5335
+ marker.addTo(map);
5336
+ markersRef.current.push(marker);
5337
+ });
5338
+ }
5339
+ }, [markers, ready, onMarkerClick, cluster, clusterVariant, mapZoom]);
5120
5340
  const cameraOpen = showCameraControls || showCamera;
5121
5341
  return /* @__PURE__ */ jsxs23("div", { className: cn("relative w-full overflow-hidden rounded-2xl border border-border", className), style: { height: h }, children: [
5342
+ routeLoading && /* @__PURE__ */ jsx27("div", { className: "absolute inset-0 z-[1000] flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2 bg-card/90 backdrop-blur-sm border border-border rounded-xl px-4 py-2 shadow-lg text-sm font-medium", children: [
5343
+ /* @__PURE__ */ jsx27("span", { className: "h-4 w-4 rounded-full border-2 border-primary border-t-transparent animate-spin" }),
5344
+ "Calculating route\u2026"
5345
+ ] }) }),
5122
5346
  /* @__PURE__ */ jsx27("div", { ref: containerRef, style: { width: "100%", height: "100%" } }),
5123
5347
  cameraOpen && /* @__PURE__ */ jsxs23("div", { className: "absolute top-4 left-4 z-10 bg-card/90 backdrop-blur-sm border border-border rounded-2xl p-3 shadow-xl space-y-3 w-52", children: [
5124
5348
  /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
@@ -6594,67 +6818,386 @@ import { createContext as createContext2, useContext as useContext2, useEffect a
6594
6818
 
6595
6819
  // src/components/conf/settingConfig.json
6596
6820
  var settingConfig_default = {
6597
- theme: "dark",
6598
- fontSize: "16px",
6599
- fontFamily: '"Space Grotesk", "Inter", sans-serif',
6600
- colors: {
6601
- primary: "#8b5cf6",
6602
- primaryHover: "#7c3aed",
6603
- secondary: "#171717",
6604
- secondaryHover: "#262626",
6605
- info: "#3b82f6",
6606
- infoHover: "#2563eb",
6607
- warning: "#f59e0b",
6608
- warningHover: "#d97706",
6609
- danger: "#ef4444",
6610
- dangerHover: "#dc2626"
6611
- }
6821
+ defaults: {
6822
+ theme: "light",
6823
+ fontSize: "16px",
6824
+ fontFamily: '"Space Grotesk", "Inter", sans-serif',
6825
+ colors: {
6826
+ primary: "#5CF6E2",
6827
+ primaryHover: "#73F3E2",
6828
+ secondary: "#171717",
6829
+ secondaryHover: "#262626",
6830
+ info: "#3b82f6",
6831
+ infoHover: "#2563eb",
6832
+ warning: "#f59e0b",
6833
+ warningHover: "#d97706",
6834
+ danger: "#ef4444",
6835
+ dangerHover: "#dc2626"
6836
+ }
6837
+ },
6838
+ themeOptions: [
6839
+ { light: "Light" },
6840
+ { dark: "Dark" },
6841
+ { system: "System" }
6842
+ ],
6843
+ fontSizes: [
6844
+ { "14px": "Small (14px)" },
6845
+ { "16px": "Medium (16px)" },
6846
+ { "18px": "Large (18px)" },
6847
+ { "20px": "Extra Large (20px)" }
6848
+ ],
6849
+ fontFamilies: [
6850
+ { '"Space Grotesk", "Inter", sans-serif': "Space Grotesk" },
6851
+ { '"Inter", sans-serif': "Inter" },
6852
+ { '"JetBrains Mono", monospace': "JetBrains Mono" },
6853
+ { "system-ui, sans-serif": "System UI" }
6854
+ ],
6855
+ colorPairs: [
6856
+ { base: "primary", hover: "primaryHover", label: "Primary" },
6857
+ { base: "secondary", hover: "secondaryHover", label: "Secondary" },
6858
+ { base: "info", hover: "infoHover", label: "Info" },
6859
+ { base: "warning", hover: "warningHover", label: "Warning" },
6860
+ { base: "danger", hover: "dangerHover", label: "Danger" }
6861
+ ],
6862
+ colorPalette: [
6863
+ {
6864
+ base: "#6366F1",
6865
+ hover: "#4F46E5",
6866
+ info: "#F59E0B",
6867
+ infoHover: "#D97706"
6868
+ },
6869
+ {
6870
+ base: "#818CF8",
6871
+ hover: "#6366F1",
6872
+ info: "#FBBF24",
6873
+ infoHover: "#F59E0B"
6874
+ },
6875
+ {
6876
+ base: "#4F46E5",
6877
+ hover: "#4338CA",
6878
+ info: "#F59E0B",
6879
+ infoHover: "#D97706"
6880
+ },
6881
+ {
6882
+ base: "#3730A3",
6883
+ hover: "#312E81",
6884
+ info: "#D97706",
6885
+ infoHover: "#B45309"
6886
+ },
6887
+ {
6888
+ base: "#7C3AED",
6889
+ hover: "#6D28D9",
6890
+ info: "#F97316",
6891
+ infoHover: "#EA580C"
6892
+ },
6893
+ {
6894
+ base: "#A78BFA",
6895
+ hover: "#8B5CF6",
6896
+ info: "#FB923C",
6897
+ infoHover: "#F97316"
6898
+ },
6899
+ {
6900
+ base: "#8B5CF6",
6901
+ hover: "#7C3AED",
6902
+ info: "#F97316",
6903
+ infoHover: "#EA580C"
6904
+ },
6905
+ {
6906
+ base: "#6D28D9",
6907
+ hover: "#5B21B6",
6908
+ info: "#EA580C",
6909
+ infoHover: "#C2410C"
6910
+ },
6911
+ {
6912
+ base: "#0EA5E9",
6913
+ hover: "#0284C7",
6914
+ info: "#F97316",
6915
+ infoHover: "#EA580C"
6916
+ },
6917
+ {
6918
+ base: "#38BDF8",
6919
+ hover: "#0EA5E9",
6920
+ info: "#FB923C",
6921
+ infoHover: "#F97316"
6922
+ },
6923
+ {
6924
+ base: "#3B82F6",
6925
+ hover: "#2563EB",
6926
+ info: "#F59E0B",
6927
+ infoHover: "#D97706"
6928
+ },
6929
+ {
6930
+ base: "#1D4ED8",
6931
+ hover: "#1E40AF",
6932
+ info: "#D97706",
6933
+ infoHover: "#B45309"
6934
+ },
6935
+ {
6936
+ base: "#06B6D4",
6937
+ hover: "#0891B2",
6938
+ info: "#A855F7",
6939
+ infoHover: "#9333EA"
6940
+ },
6941
+ {
6942
+ base: "#22D3EE",
6943
+ hover: "#06B6D4",
6944
+ info: "#C084FC",
6945
+ infoHover: "#A855F7"
6946
+ },
6947
+ {
6948
+ base: "#14B8A6",
6949
+ hover: "#0F766E",
6950
+ info: "#8B5CF6",
6951
+ infoHover: "#7C3AED"
6952
+ },
6953
+ {
6954
+ base: "#0D9488",
6955
+ hover: "#0F766E",
6956
+ info: "#7C3AED",
6957
+ infoHover: "#6D28D9"
6958
+ },
6959
+ {
6960
+ base: "#10B981",
6961
+ hover: "#059669",
6962
+ info: "#8B5CF6",
6963
+ infoHover: "#7C3AED"
6964
+ },
6965
+ {
6966
+ base: "#34D399",
6967
+ hover: "#10B981",
6968
+ info: "#A855F7",
6969
+ infoHover: "#9333EA"
6970
+ },
6971
+ {
6972
+ base: "#22C55E",
6973
+ hover: "#16A34A",
6974
+ info: "#7C3AED",
6975
+ infoHover: "#6D28D9"
6976
+ },
6977
+ {
6978
+ base: "#16A34A",
6979
+ hover: "#15803D",
6980
+ info: "#6D28D9",
6981
+ infoHover: "#5B21B6"
6982
+ },
6983
+ {
6984
+ base: "#84CC16",
6985
+ hover: "#65A30D",
6986
+ info: "#6366F1",
6987
+ infoHover: "#4F46E5"
6988
+ },
6989
+ {
6990
+ base: "#A3E635",
6991
+ hover: "#84CC16",
6992
+ info: "#818CF8",
6993
+ infoHover: "#6366F1"
6994
+ },
6995
+ {
6996
+ base: "#65A30D",
6997
+ hover: "#4D7C0F",
6998
+ info: "#4F46E5",
6999
+ infoHover: "#4338CA"
7000
+ },
7001
+ {
7002
+ base: "#4D7C0F",
7003
+ hover: "#3F6212",
7004
+ info: "#3730A3",
7005
+ infoHover: "#312E81"
7006
+ },
7007
+ {
7008
+ base: "#EAB308",
7009
+ hover: "#CA8A04",
7010
+ info: "#3B82F6",
7011
+ infoHover: "#2563EB"
7012
+ },
7013
+ {
7014
+ base: "#FACC15",
7015
+ hover: "#EAB308",
7016
+ info: "#60A5FA",
7017
+ infoHover: "#3B82F6"
7018
+ },
7019
+ {
7020
+ base: "#F59E0B",
7021
+ hover: "#D97706",
7022
+ info: "#2563EB",
7023
+ infoHover: "#1D4ED8"
7024
+ },
7025
+ {
7026
+ base: "#D97706",
7027
+ hover: "#B45309",
7028
+ info: "#1D4ED8",
7029
+ infoHover: "#1E40AF"
7030
+ },
7031
+ {
7032
+ base: "#F97316",
7033
+ hover: "#EA580C",
7034
+ info: "#0EA5E9",
7035
+ infoHover: "#0284C7"
7036
+ },
7037
+ {
7038
+ base: "#FB923C",
7039
+ hover: "#F97316",
7040
+ info: "#38BDF8",
7041
+ infoHover: "#0EA5E9"
7042
+ },
7043
+ {
7044
+ base: "#EA580C",
7045
+ hover: "#C2410C",
7046
+ info: "#0284C7",
7047
+ infoHover: "#0369A1"
7048
+ },
7049
+ {
7050
+ base: "#C2410C",
7051
+ hover: "#9A3412",
7052
+ info: "#0369A1",
7053
+ infoHover: "#075985"
7054
+ },
7055
+ {
7056
+ base: "#EF4444",
7057
+ hover: "#DC2626",
7058
+ info: "#0EA5E9",
7059
+ infoHover: "#0284C7"
7060
+ },
7061
+ {
7062
+ base: "#F87171",
7063
+ hover: "#EF4444",
7064
+ info: "#38BDF8",
7065
+ infoHover: "#0EA5E9"
7066
+ },
7067
+ {
7068
+ base: "#DC2626",
7069
+ hover: "#B91C1C",
7070
+ info: "#0284C7",
7071
+ infoHover: "#0369A1"
7072
+ },
7073
+ {
7074
+ base: "#B91C1C",
7075
+ hover: "#991B1B",
7076
+ info: "#0369A1",
7077
+ infoHover: "#075985"
7078
+ },
7079
+ {
7080
+ base: "#F43F5E",
7081
+ hover: "#E11D48",
7082
+ info: "#0EA5E9",
7083
+ infoHover: "#0284C7"
7084
+ },
7085
+ {
7086
+ base: "#FB7185",
7087
+ hover: "#F43F5E",
7088
+ info: "#38BDF8",
7089
+ infoHover: "#0EA5E9"
7090
+ },
7091
+ {
7092
+ base: "#E11D48",
7093
+ hover: "#BE123C",
7094
+ info: "#0284C7",
7095
+ infoHover: "#0369A1"
7096
+ },
7097
+ {
7098
+ base: "#BE123C",
7099
+ hover: "#9F1239",
7100
+ info: "#0369A1",
7101
+ infoHover: "#075985"
7102
+ },
7103
+ {
7104
+ base: "#EC4899",
7105
+ hover: "#DB2777",
7106
+ info: "#06B6D4",
7107
+ infoHover: "#0891B2"
7108
+ },
7109
+ {
7110
+ base: "#F472B6",
7111
+ hover: "#EC4899",
7112
+ info: "#22D3EE",
7113
+ infoHover: "#06B6D4"
7114
+ },
7115
+ {
7116
+ base: "#DB2777",
7117
+ hover: "#BE185D",
7118
+ info: "#0891B2",
7119
+ infoHover: "#0E7490"
7120
+ },
7121
+ {
7122
+ base: "#BE185D",
7123
+ hover: "#9D174D",
7124
+ info: "#0E7490",
7125
+ infoHover: "#155E75"
7126
+ },
7127
+ {
7128
+ base: "#D946EF",
7129
+ hover: "#C026D3",
7130
+ info: "#F59E0B",
7131
+ infoHover: "#D97706"
7132
+ },
7133
+ {
7134
+ base: "#E879F9",
7135
+ hover: "#D946EF",
7136
+ info: "#FBBF24",
7137
+ infoHover: "#F59E0B"
7138
+ },
7139
+ {
7140
+ base: "#C026D3",
7141
+ hover: "#A21CAF",
7142
+ info: "#D97706",
7143
+ infoHover: "#B45309"
7144
+ },
7145
+ {
7146
+ base: "#A21CAF",
7147
+ hover: "#86198F",
7148
+ info: "#B45309",
7149
+ infoHover: "#92400E"
7150
+ }
7151
+ ]
6612
7152
  };
6613
7153
 
6614
7154
  // src/components/theme-provider.tsx
6615
7155
  import { jsx as jsx36 } from "react/jsx-runtime";
6616
- var configDefaults = {
6617
- theme: settingConfig_default.theme,
6618
- fontSize: settingConfig_default.fontSize,
6619
- fontFamily: settingConfig_default.fontFamily,
6620
- colors: settingConfig_default.colors
7156
+ var FACTORY_DEFAULTS = {
7157
+ theme: settingConfig_default.defaults.theme,
7158
+ fontSize: settingConfig_default.defaults.fontSize,
7159
+ fontFamily: settingConfig_default.defaults.fontFamily,
7160
+ colors: settingConfig_default.defaults.colors
6621
7161
  };
7162
+ function loadJSON(key, fallback) {
7163
+ try {
7164
+ const raw = localStorage.getItem(key);
7165
+ if (raw) return { ...fallback, ...JSON.parse(raw) };
7166
+ } catch {
7167
+ }
7168
+ return fallback;
7169
+ }
7170
+ function saveJSON(key, value) {
7171
+ try {
7172
+ localStorage.setItem(key, JSON.stringify(value));
7173
+ } catch {
7174
+ }
7175
+ }
6622
7176
  var initialState = {
6623
- ...configDefaults,
7177
+ ...FACTORY_DEFAULTS,
6624
7178
  setTheme: () => null,
6625
7179
  setColors: () => null,
6626
7180
  setFontSize: () => null,
6627
7181
  setFontFamily: () => null,
7182
+ saveConfig: () => null,
6628
7183
  resetSettings: () => null
6629
7184
  };
6630
7185
  var ThemeProviderContext = createContext2(initialState);
6631
- var COLOR_PALETTE = [
6632
- { base: "#6366f1", hover: "#4f46e5" },
6633
- { base: "#8b5cf6", hover: "#7c3aed" },
6634
- { base: "#3b82f6", hover: "#2563eb" },
6635
- { base: "#10b981", hover: "#059669" },
6636
- { base: "#22c55e", hover: "#16a34a" },
6637
- { base: "#eab308", hover: "#ca8a04" },
6638
- { base: "#f59e0b", hover: "#d97706" },
6639
- { base: "#f97316", hover: "#ea580c" },
6640
- { base: "#ef4444", hover: "#dc2626" },
6641
- { base: "#ec4899", hover: "#db2777" }
6642
- ];
7186
+ var COLOR_PALETTE = settingConfig_default.colorPalette;
6643
7187
  function ThemeProvider({
6644
7188
  children,
6645
7189
  storageKey = "codego-ui-theme-settings",
7190
+ savedConfigKey = "codego-ui-saved-config",
6646
7191
  ...props
6647
7192
  }) {
6648
- const [settings, setSettings] = useState25(() => {
6649
- try {
6650
- const stored = localStorage.getItem(storageKey);
6651
- if (stored) return { ...configDefaults, ...JSON.parse(stored) };
6652
- } catch {
6653
- }
6654
- return configDefaults;
6655
- });
7193
+ const [savedConfig, setSavedConfig] = useState25(
7194
+ () => loadJSON(savedConfigKey, FACTORY_DEFAULTS)
7195
+ );
7196
+ const [settings, setSettings] = useState25(
7197
+ () => loadJSON(storageKey, savedConfig)
7198
+ );
6656
7199
  useEffect21(() => {
6657
- localStorage.setItem(storageKey, JSON.stringify(settings));
7200
+ saveJSON(storageKey, settings);
6658
7201
  }, [settings, storageKey]);
6659
7202
  useEffect21(() => {
6660
7203
  const root = window.document.documentElement;
@@ -6680,7 +7223,13 @@ function ThemeProvider({
6680
7223
  setColors: (colors) => setSettings((s) => ({ ...s, colors: { ...s.colors, ...colors } })),
6681
7224
  setFontSize: (fontSize) => setSettings((s) => ({ ...s, fontSize })),
6682
7225
  setFontFamily: (fontFamily) => setSettings((s) => ({ ...s, fontFamily })),
6683
- resetSettings: () => setSettings(configDefaults)
7226
+ // Save current live settings as the new persisted defaults
7227
+ saveConfig: () => {
7228
+ setSavedConfig(settings);
7229
+ saveJSON(savedConfigKey, settings);
7230
+ },
7231
+ // Reset live settings back to saved defaults
7232
+ resetSettings: () => setSettings(savedConfig)
6684
7233
  };
6685
7234
  return /* @__PURE__ */ jsx36(ThemeProviderContext.Provider, { ...props, value, children });
6686
7235
  }
@@ -7571,7 +8120,8 @@ function SectionBlock({
7571
8120
  }
7572
8121
 
7573
8122
  // src/components/ui/PanelSettings.tsx
7574
- import { RotateCcw as RotateCcw2 } from "lucide-react";
8123
+ import * as React39 from "react";
8124
+ import { RotateCcw as RotateCcw2, Save } from "lucide-react";
7575
8125
 
7576
8126
  // src/components/ui/tabs.tsx
7577
8127
  import * as React38 from "react";
@@ -7657,30 +8207,10 @@ function Tabs({
7657
8207
 
7658
8208
  // src/components/ui/PanelSettings.tsx
7659
8209
  import { jsx as jsx48, jsxs as jsxs42 } from "react/jsx-runtime";
7660
- var FONT_SIZES = [
7661
- { value: "14px", label: "Small (14px)" },
7662
- { value: "16px", label: "Medium (16px)" },
7663
- { value: "18px", label: "Large (18px)" },
7664
- { value: "20px", label: "Extra Large (20px)" }
7665
- ];
7666
- var FONT_FAMILIES = [
7667
- { value: '"Space Grotesk", "Inter", sans-serif', label: "Space Grotesk" },
7668
- { value: '"Inter", sans-serif', label: "Inter" },
7669
- { value: '"JetBrains Mono", monospace', label: "JetBrains Mono" },
7670
- { value: "system-ui, sans-serif", label: "System UI" }
7671
- ];
7672
- var THEME_OPTIONS = [
7673
- { value: "light", label: "Light" },
7674
- { value: "dark", label: "Dark" },
7675
- { value: "system", label: "System" }
7676
- ];
7677
- var COLOR_PAIRS = [
7678
- { base: "primary", hover: "primaryHover", label: "Primary" },
7679
- { base: "secondary", hover: "secondaryHover", label: "Secondary" },
7680
- { base: "info", hover: "infoHover", label: "Info" },
7681
- { base: "warning", hover: "warningHover", label: "Warning" },
7682
- { base: "danger", hover: "dangerHover", label: "Danger" }
7683
- ];
8210
+ var THEME_OPTIONS = settingConfig_default.themeOptions;
8211
+ var FONT_SIZES = settingConfig_default.fontSizes;
8212
+ var FONT_FAMILIES = settingConfig_default.fontFamilies;
8213
+ var COLOR_PAIRS = settingConfig_default.colorPairs;
7684
8214
  function SettingRow({ label, description, children }) {
7685
8215
  return /* @__PURE__ */ jsxs42("div", { className: "flex items-start justify-between gap-4 py-3 border-b border-border/60 last:border-0", children: [
7686
8216
  /* @__PURE__ */ jsxs42("div", { className: "min-w-0", children: [
@@ -7728,8 +8258,8 @@ function ColorsPanel({ onColorsChange }) {
7728
8258
  type: "button",
7729
8259
  title: c.base,
7730
8260
  onClick: () => {
7731
- setColors({ primary: c.base, primaryHover: c.hover });
7732
- onColorsChange?.({ primary: c.base, primaryHover: c.hover });
8261
+ setColors({ primary: c.base, primaryHover: c.hover, info: c.info, infoHover: c.infoHover });
8262
+ onColorsChange?.({ primary: c.base, primaryHover: c.hover, info: c.info, infoHover: c.infoHover });
7733
8263
  },
7734
8264
  className: cn(
7735
8265
  "h-7 w-full rounded-md border border-white/10 transition-transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-ring",
@@ -7805,10 +8335,18 @@ function PanelSettings({
7805
8335
  onColorsChange,
7806
8336
  onFontSizeChange,
7807
8337
  onFontFamilyChange,
8338
+ onSave,
7808
8339
  onReset,
7809
8340
  className
7810
8341
  }) {
7811
- const { resetSettings } = useTheme();
8342
+ const { saveConfig, resetSettings } = useTheme();
8343
+ const [saved, setSaved] = React39.useState(false);
8344
+ const handleSave = () => {
8345
+ saveConfig();
8346
+ onSave?.();
8347
+ setSaved(true);
8348
+ setTimeout(() => setSaved(false), 2e3);
8349
+ };
7812
8350
  const handleReset = () => {
7813
8351
  resetSettings();
7814
8352
  onReset?.();
@@ -7832,10 +8370,16 @@ function PanelSettings({
7832
8370
  ];
7833
8371
  return /* @__PURE__ */ jsxs42("div", { className: cn("flex flex-col gap-4", className), children: [
7834
8372
  /* @__PURE__ */ jsx48(Tabs, { items: tabs, defaultValue: defaultTab, variant: "pill" }),
7835
- /* @__PURE__ */ jsx48("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsxs42(Button, { variant: "outline", size: "sm", onClick: handleReset, children: [
7836
- /* @__PURE__ */ jsx48(RotateCcw2, { className: "h-3.5 w-3.5 mr-1.5" }),
7837
- "Reset to Defaults"
7838
- ] }) })
8373
+ /* @__PURE__ */ jsxs42("div", { className: "flex justify-end gap-2 pt-1", children: [
8374
+ /* @__PURE__ */ jsxs42(Button, { variant: "outline", size: "sm", onClick: handleReset, children: [
8375
+ /* @__PURE__ */ jsx48(RotateCcw2, { className: "h-3.5 w-3.5 mr-1.5" }),
8376
+ "Reset"
8377
+ ] }),
8378
+ /* @__PURE__ */ jsxs42(Button, { size: "sm", onClick: handleSave, children: [
8379
+ /* @__PURE__ */ jsx48(Save, { className: "h-3.5 w-3.5 mr-1.5" }),
8380
+ saved ? "Saved!" : "Save"
8381
+ ] })
8382
+ ] })
7839
8383
  ] });
7840
8384
  }
7841
8385
 
@@ -7855,7 +8399,7 @@ function Skeleton({
7855
8399
  }
7856
8400
 
7857
8401
  // src/components/ui/slider.tsx
7858
- import * as React39 from "react";
8402
+ import * as React40 from "react";
7859
8403
  import { jsx as jsx50, jsxs as jsxs43 } from "react/jsx-runtime";
7860
8404
  function pct(val, min, max) {
7861
8405
  return (val - min) / (max - min) * 100;
@@ -7875,8 +8419,8 @@ function Slider({
7875
8419
  showValue = false,
7876
8420
  className
7877
8421
  }) {
7878
- const [internal, setInternal] = React39.useState(defaultValue);
7879
- const [hovering, setHovering] = React39.useState(false);
8422
+ const [internal, setInternal] = React40.useState(defaultValue);
8423
+ const [hovering, setHovering] = React40.useState(false);
7880
8424
  const val = controlled ?? internal;
7881
8425
  function handleChange(e) {
7882
8426
  const v = Number(e.target.value);
@@ -7953,8 +8497,8 @@ function RangeSlider({
7953
8497
  showValue = false,
7954
8498
  className
7955
8499
  }) {
7956
- const [internal, setInternal] = React39.useState(defaultValue);
7957
- const [active, setActive] = React39.useState(null);
8500
+ const [internal, setInternal] = React40.useState(defaultValue);
8501
+ const [active, setActive] = React40.useState(null);
7958
8502
  const val = controlled ?? internal;
7959
8503
  function handleChange(idx, e) {
7960
8504
  const v = Number(e.target.value);
@@ -7977,7 +8521,7 @@ function RangeSlider({
7977
8521
  /* @__PURE__ */ jsx50("div", { className: "absolute w-full h-1.5 rounded-full bg-muted", children: /* @__PURE__ */ jsx50("div", { className: "absolute h-full rounded-full bg-primary", style: { left: `${p0}%`, width: `${p1 - p0}%` } }) }),
7978
8522
  [0, 1].map((idx) => {
7979
8523
  const p = idx === 0 ? p0 : p1;
7980
- return /* @__PURE__ */ jsxs43(React39.Fragment, { children: [
8524
+ return /* @__PURE__ */ jsxs43(React40.Fragment, { children: [
7981
8525
  showTooltip && active === idx && !disabled && /* @__PURE__ */ jsx50(
7982
8526
  "div",
7983
8527
  {
@@ -8088,7 +8632,7 @@ function StatCard({
8088
8632
  }
8089
8633
 
8090
8634
  // src/components/ui/stepper.tsx
8091
- import * as React40 from "react";
8635
+ import * as React41 from "react";
8092
8636
  import { Check as Check6, X as X11 } from "lucide-react";
8093
8637
  import { jsx as jsx52, jsxs as jsxs45 } from "react/jsx-runtime";
8094
8638
  function getStatus(idx, current) {
@@ -8111,7 +8655,7 @@ function Stepper({
8111
8655
  clickable = false,
8112
8656
  className
8113
8657
  }) {
8114
- const [internal, setInternal] = React40.useState(defaultCurrent);
8658
+ const [internal, setInternal] = React41.useState(defaultCurrent);
8115
8659
  const current = controlled ?? internal;
8116
8660
  function go(idx) {
8117
8661
  if (!clickable) return;
@@ -8126,7 +8670,7 @@ function Stepper({
8126
8670
  ), children: steps.map((step, i) => {
8127
8671
  const status = getStatus(i, current);
8128
8672
  const isLast = i === steps.length - 1;
8129
- return /* @__PURE__ */ jsx52(React40.Fragment, { children: /* @__PURE__ */ jsxs45("div", { className: cn(
8673
+ return /* @__PURE__ */ jsx52(React41.Fragment, { children: /* @__PURE__ */ jsxs45("div", { className: cn(
8130
8674
  "flex",
8131
8675
  isHorizontal ? "flex-col items-center flex-1" : "flex-row gap-4"
8132
8676
  ), children: [
@@ -8170,7 +8714,7 @@ function Stepper({
8170
8714
  }
8171
8715
 
8172
8716
  // src/components/ui/table.tsx
8173
- import * as React41 from "react";
8717
+ import * as React42 from "react";
8174
8718
  import { ChevronLeft as ChevronLeft5, ChevronRight as ChevronRight8, Search as Search5, Trash2 as Trash23, ChevronsUpDown as ChevronsUpDown2, ChevronUp as ChevronUp2, ChevronDown as ChevronDown7, X as X12 } from "lucide-react";
8175
8719
  import { Fragment as Fragment13, jsx as jsx53, jsxs as jsxs46 } from "react/jsx-runtime";
8176
8720
  var BADGE_COLORS = {
@@ -8195,11 +8739,11 @@ function Table({
8195
8739
  idKey = "id",
8196
8740
  className
8197
8741
  }) {
8198
- const [search, setSearch] = React41.useState("");
8199
- const [currentPage, setCurrentPage] = React41.useState(1);
8200
- const [selectedIds, setSelectedIds] = React41.useState([]);
8201
- const [sortKey, setSortKey] = React41.useState(null);
8202
- const [sortDir, setSortDir] = React41.useState(null);
8742
+ const [search, setSearch] = React42.useState("");
8743
+ const [currentPage, setCurrentPage] = React42.useState(1);
8744
+ const [selectedIds, setSelectedIds] = React42.useState([]);
8745
+ const [sortKey, setSortKey] = React42.useState(null);
8746
+ const [sortDir, setSortDir] = React42.useState(null);
8203
8747
  const handleSort = (key) => {
8204
8748
  if (sortKey !== key) {
8205
8749
  setSortKey(key);
@@ -8213,7 +8757,7 @@ function Table({
8213
8757
  setSortKey(null);
8214
8758
  setSortDir(null);
8215
8759
  };
8216
- const filteredData = React41.useMemo(() => {
8760
+ const filteredData = React42.useMemo(() => {
8217
8761
  let d = search ? data.filter(
8218
8762
  (item) => Object.values(item).some(
8219
8763
  (val) => val && typeof val === "string" && val.toLowerCase().includes(search.toLowerCase())
@@ -8231,18 +8775,18 @@ function Table({
8231
8775
  }, [data, search, sortKey, sortDir]);
8232
8776
  const totalPages = Math.max(1, Math.ceil(filteredData.length / itemsPerPage));
8233
8777
  const safePage = Math.min(currentPage, totalPages);
8234
- const paginatedData = React41.useMemo(() => {
8778
+ const paginatedData = React42.useMemo(() => {
8235
8779
  if (!pagination) return filteredData;
8236
8780
  const start = (safePage - 1) * itemsPerPage;
8237
8781
  return filteredData.slice(start, start + itemsPerPage);
8238
8782
  }, [filteredData, pagination, safePage, itemsPerPage]);
8239
- React41.useEffect(() => {
8783
+ React42.useEffect(() => {
8240
8784
  setCurrentPage(1);
8241
8785
  }, [search]);
8242
8786
  const handleSelectAll = (checked) => setSelectedIds(checked ? paginatedData.map((item) => String(item[idKey])) : []);
8243
8787
  const handleSelect = (id, checked) => setSelectedIds((prev) => checked ? [...prev, id] : prev.filter((i) => i !== id));
8244
8788
  const allSelected = paginatedData.length > 0 && selectedIds.length === paginatedData.length;
8245
- const pagePills = React41.useMemo(() => {
8789
+ const pagePills = React42.useMemo(() => {
8246
8790
  if (totalPages <= 5) return Array.from({ length: totalPages }, (_, i) => i + 1);
8247
8791
  if (safePage <= 3) return [1, 2, 3, 4, 5];
8248
8792
  if (safePage >= totalPages - 2) return [totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages];
@@ -8471,7 +9015,7 @@ function Table({
8471
9015
  }
8472
9016
 
8473
9017
  // src/components/ui/tag-input.tsx
8474
- import * as React42 from "react";
9018
+ import * as React43 from "react";
8475
9019
  import { jsx as jsx54, jsxs as jsxs47 } from "react/jsx-runtime";
8476
9020
  function TagInput({
8477
9021
  value: controlled,
@@ -8483,9 +9027,9 @@ function TagInput({
8483
9027
  disabled = false,
8484
9028
  className
8485
9029
  }) {
8486
- const [internal, setInternal] = React42.useState(defaultValue);
8487
- const [input, setInput] = React42.useState("");
8488
- const inputRef = React42.useRef(null);
9030
+ const [internal, setInternal] = React43.useState(defaultValue);
9031
+ const [input, setInput] = React43.useState("");
9032
+ const inputRef = React43.useRef(null);
8489
9033
  const tags = controlled ?? internal;
8490
9034
  function addTag(raw) {
8491
9035
  const tag = raw.trim();
@@ -8590,9 +9134,9 @@ function Timeline({ items, align = "left", className }) {
8590
9134
  }
8591
9135
 
8592
9136
  // src/components/ui/toggle-switch.tsx
8593
- import * as React43 from "react";
9137
+ import * as React44 from "react";
8594
9138
  import { jsx as jsx56, jsxs as jsxs49 } from "react/jsx-runtime";
8595
- var ToggleSwitch = React43.forwardRef(
9139
+ var ToggleSwitch = React44.forwardRef(
8596
9140
  ({
8597
9141
  className,
8598
9142
  inline = false,
@@ -8610,10 +9154,10 @@ var ToggleSwitch = React43.forwardRef(
8610
9154
  disabled,
8611
9155
  ...props
8612
9156
  }, ref) => {
8613
- const toggleId = id ?? React43.useId();
9157
+ const toggleId = id ?? React44.useId();
8614
9158
  const trackW = width ? typeof width === "number" ? `${width}px` : width : "2.75rem";
8615
9159
  const trackH = height ? typeof height === "number" ? `${height}px` : height : "1.5rem";
8616
- const [internalChecked, setInternalChecked] = React43.useState(defaultChecked ?? false);
9160
+ const [internalChecked, setInternalChecked] = React44.useState(defaultChecked ?? false);
8617
9161
  const isControlled = checked !== void 0;
8618
9162
  const isOn = accepted ? true : declined ? false : isControlled ? checked : internalChecked;
8619
9163
  const stateColor = accepted ? acceptedColor ?? "#22c55e" : declined ? declinedColor ?? "#ef4444" : isOn ? void 0 : void 0;
@@ -8683,7 +9227,7 @@ var ToggleSwitch = React43.forwardRef(
8683
9227
  ToggleSwitch.displayName = "ToggleSwitch";
8684
9228
 
8685
9229
  // src/components/ui/tree-view.tsx
8686
- import * as React44 from "react";
9230
+ import * as React45 from "react";
8687
9231
  import { ChevronRight as ChevronRight9, Folder, FolderOpen, File } from "lucide-react";
8688
9232
  import { jsx as jsx57, jsxs as jsxs50 } from "react/jsx-runtime";
8689
9233
  function TreeNodeItem({ node, depth, selected, expanded, onToggleExpand, onSelect, multiple }) {
@@ -8737,8 +9281,8 @@ function TreeView({
8737
9281
  className
8738
9282
  }) {
8739
9283
  const init = defaultSelected ? Array.isArray(defaultSelected) ? defaultSelected : [defaultSelected] : [];
8740
- const [internal, setInternal] = React44.useState(init);
8741
- const [expanded, setExpanded] = React44.useState(defaultExpanded);
9284
+ const [internal, setInternal] = React45.useState(init);
9285
+ const [expanded, setExpanded] = React45.useState(defaultExpanded);
8742
9286
  const selected = controlled ? Array.isArray(controlled) ? controlled : [controlled] : internal;
8743
9287
  function handleSelect(id) {
8744
9288
  let next;
@@ -8769,7 +9313,7 @@ function TreeView({
8769
9313
  }
8770
9314
 
8771
9315
  // src/components/ui/widget.tsx
8772
- import * as React45 from "react";
9316
+ import * as React46 from "react";
8773
9317
  import { jsx as jsx58, jsxs as jsxs51 } from "react/jsx-runtime";
8774
9318
  var iconColorMap = {
8775
9319
  primary: "bg-primary/10 text-primary",
@@ -8798,8 +9342,8 @@ var variantMap = {
8798
9342
  outline: "bg-transparent border-2"
8799
9343
  };
8800
9344
  function useCountUp(target, enabled, duration = 1e3) {
8801
- const [display, setDisplay] = React45.useState(enabled ? 0 : target);
8802
- React45.useEffect(() => {
9345
+ const [display, setDisplay] = React46.useState(enabled ? 0 : target);
9346
+ React46.useEffect(() => {
8803
9347
  if (!enabled) {
8804
9348
  setDisplay(target);
8805
9349
  return;
@@ -8912,7 +9456,7 @@ function Widget({
8912
9456
  }
8913
9457
 
8914
9458
  // src/components/ui/wizard.tsx
8915
- import * as React46 from "react";
9459
+ import * as React47 from "react";
8916
9460
  import { Check as Check7, X as X13, ChevronLeft as ChevronLeft6, ChevronRight as ChevronRight10, AlertCircle } from "lucide-react";
8917
9461
  import { Fragment as Fragment15, jsx as jsx59, jsxs as jsxs52 } from "react/jsx-runtime";
8918
9462
  var SIZE_MAP = {
@@ -8936,7 +9480,7 @@ function HeaderDefault({
8936
9480
  return /* @__PURE__ */ jsx59("div", { className: "flex items-start w-full", children: steps.map((step, i) => {
8937
9481
  const status = stepStatus(i, current);
8938
9482
  const isLast = i === steps.length - 1;
8939
- return /* @__PURE__ */ jsx59(React46.Fragment, { children: /* @__PURE__ */ jsxs52("div", { className: "flex flex-col items-center flex-1 min-w-0", children: [
9483
+ return /* @__PURE__ */ jsx59(React47.Fragment, { children: /* @__PURE__ */ jsxs52("div", { className: "flex flex-col items-center flex-1 min-w-0", children: [
8940
9484
  /* @__PURE__ */ jsxs52("div", { className: "flex items-center w-full", children: [
8941
9485
  i > 0 && /* @__PURE__ */ jsx59("div", { className: cn("flex-1 h-0.5 transition-colors", i <= current ? "bg-primary" : "bg-border") }),
8942
9486
  /* @__PURE__ */ jsx59(
@@ -9164,7 +9708,7 @@ function WizardPanel({
9164
9708
  const isFirst = current === 0;
9165
9709
  const isLast = current === steps.length - 1;
9166
9710
  const isSidebar = variant === "sidebar";
9167
- const [validationError, setValidationError] = React46.useState(null);
9711
+ const [validationError, setValidationError] = React47.useState(null);
9168
9712
  const handleNext = () => {
9169
9713
  const validate = steps[current]?.validate;
9170
9714
  if (validate) {
@@ -9268,7 +9812,7 @@ function Wizard({
9268
9812
  className,
9269
9813
  contentClassName
9270
9814
  }) {
9271
- const [internalStep, setInternalStep] = React46.useState(defaultStep);
9815
+ const [internalStep, setInternalStep] = React47.useState(defaultStep);
9272
9816
  const current = controlledStep ?? internalStep;
9273
9817
  const go = (idx) => {
9274
9818
  const clamped = Math.max(0, Math.min(steps.length - 1, idx));
@@ -9283,7 +9827,7 @@ function Wizard({
9283
9827
  }
9284
9828
  go(current + 1);
9285
9829
  };
9286
- React46.useEffect(() => {
9830
+ React47.useEffect(() => {
9287
9831
  if (layout !== "modal" || !isOpen || unchange) return;
9288
9832
  const handler = (e) => {
9289
9833
  if (e.key === "Escape") onClose?.();