@hanzo/ui 8.0.13 → 8.0.14

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.
@@ -2,6 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  var chunkYBXVUV7P_cjs = require('../chunk-YBXVUV7P.cjs');
5
+ var chunkVGGGGXWS_cjs = require('../chunk-VGGGGXWS.cjs');
5
6
  var react = require('react');
6
7
  var gui = require('@hanzo/gui');
7
8
  var jsxRuntime = require('react/jsx-runtime');
@@ -674,12 +675,12 @@ function menuKeyDown(e, onClose) {
674
675
  if (items.length === 0) return;
675
676
  e.preventDefault();
676
677
  const active = document.activeElement;
677
- const current2 = active ? items.indexOf(active) : -1;
678
+ const current = active ? items.indexOf(active) : -1;
678
679
  let next;
679
680
  if (e.key === "Home") next = 0;
680
681
  else if (e.key === "End") next = items.length - 1;
681
- else if (e.key === "ArrowDown") next = current2 < 0 ? 0 : (current2 + 1) % items.length;
682
- else next = current2 <= 0 ? items.length - 1 : current2 - 1;
682
+ else if (e.key === "ArrowDown") next = current < 0 ? 0 : (current + 1) % items.length;
683
+ else next = current <= 0 ? items.length - 1 : current - 1;
683
684
  items[next]?.focus();
684
685
  }
685
686
  var EDGE = 8;
@@ -854,8 +855,8 @@ var SURFACES = ORDER.map((id) => {
854
855
  const s = products.surfaceById(id);
855
856
  return { id, label: s.label, href: s.href, hint: s.domain };
856
857
  });
857
- function otherSurfaces(current2) {
858
- return current2 ? SURFACES.filter((s) => s.id !== current2) : SURFACES;
858
+ function otherSurfaces(current) {
859
+ return current ? SURFACES.filter((s) => s.id !== current) : SURFACES;
859
860
  }
860
861
  function HanzoMark({ size = 22, color = "currentColor" }) {
861
862
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -912,7 +913,7 @@ function AppHeader({
912
913
  onBrand,
913
914
  org,
914
915
  children,
915
- current: current2,
916
+ current,
916
917
  surfaces,
917
918
  open,
918
919
  user,
@@ -925,7 +926,7 @@ function AppHeader({
925
926
  }) {
926
927
  const [appsOpen, setAppsOpen] = react.useState(false);
927
928
  const [menuOpen, setMenuOpen] = react.useState(false);
928
- const items = surfaces ?? otherSurfaces(current2);
929
+ const items = surfaces ?? otherSurfaces(current);
929
930
  const launch = (s) => {
930
931
  setAppsOpen(false);
931
932
  if (open) open(s);
@@ -1076,7 +1077,7 @@ function OrgSwitcher({ scope, orgs, pageSize = 20, current: given, create, picke
1076
1077
  const [open, setOpen] = react.useState(false);
1077
1078
  const [query, setQuery] = react.useState("");
1078
1079
  const [debounced, setDebounced] = react.useState("");
1079
- const [rows2, setRows] = react.useState([]);
1080
+ const [rows, setRows] = react.useState([]);
1080
1081
  const [loading, setLoading] = react.useState(false);
1081
1082
  const [loadingMore, setLoadingMore] = react.useState(false);
1082
1083
  const [hasMore, setHasMore] = react.useState(false);
@@ -1128,14 +1129,14 @@ function OrgSwitcher({ scope, orgs, pageSize = 20, current: given, create, picke
1128
1129
  void fetchPage(pageRef.current + 1, debounced, true);
1129
1130
  }, [loading, loadingMore, hasMore, debounced, fetchPage]);
1130
1131
  const visible = react.useMemo(() => {
1131
- if (orgs) return filterOrgs(rows2, query);
1132
+ if (orgs) return filterOrgs(rows, query);
1132
1133
  return [{ name: currentId, displayName: titleCase(currentId) }];
1133
- }, [orgs, rows2, query, currentId]);
1134
- const current2 = react.useMemo(() => {
1134
+ }, [orgs, rows, query, currentId]);
1135
+ const current = react.useMemo(() => {
1135
1136
  if (given && given.name === currentId) return given;
1136
- return rows2.find((o) => o.name === currentId) ?? { name: currentId, displayName: titleCase(currentId) };
1137
- }, [given, rows2, currentId]);
1138
- const currentLabel = current2.displayName || titleCase(current2.name);
1137
+ return rows.find((o) => o.name === currentId) ?? { name: currentId, displayName: titleCase(currentId) };
1138
+ }, [given, rows, currentId]);
1139
+ const currentLabel = current.displayName || titleCase(current.name);
1139
1140
  const select = react.useCallback(
1140
1141
  (org) => {
1141
1142
  setOpen(false);
@@ -1158,7 +1159,7 @@ function OrgSwitcher({ scope, orgs, pageSize = 20, current: given, create, picke
1158
1159
  };
1159
1160
  return /* @__PURE__ */ jsxRuntime.jsxs(gui.Popover, { open, onOpenChange: setOpen, placement: "bottom-start", children: [
1160
1161
  /* @__PURE__ */ jsxRuntime.jsx(gui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { chromeless: true, height: 44, px: "$2", justify: "flex-start", "aria-label": `${currentLabel} \xB7 switch organization`, children: /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", gap: "$2.5", flex: 1, minW: 0, children: [
1161
- /* @__PURE__ */ jsxRuntime.jsx(OrgMark, { org: current2, size: 30 }),
1162
+ /* @__PURE__ */ jsxRuntime.jsx(OrgMark, { org: current, size: 30 }),
1162
1163
  /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { flex: 1, minW: 0, fontSize: "$4", fontWeight: "800", color: "$color12", numberOfLines: 1, children: currentLabel }),
1163
1164
  /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.ChevronsUpDown, { size: 15, color: "$color9" })
1164
1165
  ] }) }) }),
@@ -1589,203 +1590,6 @@ function SiteFooter({ footer, brand, tagline, meta, link = defaultLink2 }) {
1589
1590
  ] })
1590
1591
  ] });
1591
1592
  }
1592
- var HostCtx = react.createContext({});
1593
- var HostProvider = ({ actions, children }) => /* @__PURE__ */ jsxRuntime.jsx(HostCtx.Provider, { value: actions, children });
1594
- var useHost = () => react.useContext(HostCtx);
1595
- function classifyBackend(e) {
1596
- const status = typeof e?.status === "number" ? e.status : 0;
1597
- const message = e instanceof Error ? e.message : String(e);
1598
- if (status === 503) return { kind: "not-initialized", message };
1599
- if (status === 404 || status === 405) return { kind: "unavailable", message };
1600
- if (status === 501) return { kind: "not-implemented", message };
1601
- if (status === 402) return { kind: "billing", message };
1602
- if (status === 401) return { kind: "signin", message };
1603
- if (status === 403) return { kind: "access", message };
1604
- return { kind: "error", message };
1605
- }
1606
- function classifyRead(e) {
1607
- const s = classifyBackend(e);
1608
- return s.kind === "billing" ? null : s;
1609
- }
1610
- var TITLES = {
1611
- "not-initialized": "Backend not initialized",
1612
- unavailable: "Not available on this deployment yet",
1613
- "not-implemented": "Not yet available",
1614
- access: "Not enabled for your account",
1615
- signin: "Your session expired",
1616
- billing: "Add credits to continue",
1617
- error: "Could not reach the backend"
1618
- };
1619
- var BODIES = {
1620
- "not-initialized": "The /v1 route is mounted but its runtime (or the console API key it proxies to) is not configured on this deployment yet. Real data appears here once it is \u2014 no placeholder data is shown.",
1621
- unavailable: "This endpoint is not mounted at the gateway on this host yet. The view lights up automatically once the route is live.",
1622
- // 501 — a real, planned capability whose body ships in a later phase.
1623
- "not-implemented": "This capability is planned but not wired yet. The backend answers honestly rather than pretending it worked \u2014 nothing here is fabricated, and the view lights up automatically once it ships.",
1624
- // 403 for a SIGNED-IN user — never "sign in".
1625
- access: "You're signed in, but this isn't enabled for your organization on this deployment, or it's an admin-only surface. It appears here automatically once your account has access \u2014 nothing is fabricated.",
1626
- // 401 — the session itself lapsed; re-auth returns to this exact page.
1627
- signin: "Your session has expired or isn\u2019t recognized here. Sign in again to continue where you left off.",
1628
- // Empty → the card shows the backend's own message (the honest "Insufficient
1629
- // balance. Please add credits…" from the gateway billing gate).
1630
- billing: "",
1631
- error: ""
1632
- };
1633
- function BackendStateCard({
1634
- state,
1635
- onRetry,
1636
- hint
1637
- }) {
1638
- const { signIn, addCredits } = useHost();
1639
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.Card, { borderWidth: 1, borderColor: "$borderColor", p: "$4", gap: "$2", maxWidth: 640, children: [
1640
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", children: [
1641
- /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.TriangleAlert, { size: 16 }),
1642
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$4", fontWeight: "700", children: TITLES[state.kind] })
1643
- ] }),
1644
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$color11", children: BODIES[state.kind] || state.message }),
1645
- hint ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color10", children: hint }) : null,
1646
- state.kind === "signin" && signIn ? /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { size: "$2", theme: "light", self: "flex-start", onPress: signIn, children: "Sign in again" }) : state.kind === "billing" && addCredits ? (
1647
- // 402 — the org has no funded balance. Offer a top-up CTA (and keep Retry so
1648
- // a returning, funded caller can reload in place).
1649
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", flexWrap: "wrap", children: [
1650
- /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { size: "$2", theme: "light", self: "flex-start", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.CreditCard, { size: 14 }), onPress: addCredits, children: "Add credits" }),
1651
- onRetry ? /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { size: "$2", self: "flex-start", onPress: onRetry, children: "Retry" }) : null
1652
- ] })
1653
- ) : onRetry ? /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { size: "$2", self: "flex-start", onPress: onRetry, children: "Retry" }) : null
1654
- ] });
1655
- }
1656
- function PageHeader({
1657
- title,
1658
- subtitle,
1659
- actions
1660
- }) {
1661
- return (
1662
- // flexWrap lets the actions drop below the title on narrow screens; flex={1}
1663
- // minW={0} lets the title column shrink so a long subtitle WRAPS instead of
1664
- // running off the viewport (a flex child defaults to min-width:auto = content
1665
- // width, which would overflow on mobile).
1666
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { justify: "space-between", items: "flex-start", gap: "$3", flexWrap: "wrap", children: [
1667
- /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$1", flex: 1, minW: 200, children: [
1668
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$7", fontWeight: "500", letterSpacing: -0.4, children: title }),
1669
- subtitle ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$color11", children: subtitle }) : null
1670
- ] }),
1671
- actions ? /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { gap: "$2", items: "center", flexWrap: "wrap", width: "100%", $md: { width: "auto", justify: "flex-end" }, children: actions }) : null
1672
- ] })
1673
- );
1674
- }
1675
- function SkeletonRows({ columns, count = 6 }) {
1676
- return /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { children: Array.from({ length: count }).map((_, r) => /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { py: "$2.5", px: "$3", gap: "$3", borderTopWidth: 1, borderColor: "$borderColor", items: "center", children: columns.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { width: c.width, flex: c.width ? void 0 : 1, minW: c.width ? void 0 : FLEX_MIN_COL_W, items: c.align === "right" ? "flex-end" : "flex-start", children: /* @__PURE__ */ jsxRuntime.jsx(
1677
- "div",
1678
- {
1679
- className: "hz-skeleton",
1680
- style: { height: 12, borderRadius: 6, width: `${[62, 40, 54, 34, 48][(i + r) % 5]}%` },
1681
- "aria-hidden": true
1682
- }
1683
- ) }, c.key)) }, r)) });
1684
- }
1685
- function DataTable({
1686
- columns,
1687
- rows: rows2,
1688
- loading,
1689
- empty = "Nothing here yet.",
1690
- rowKey,
1691
- onRowPress,
1692
- isRowExpanded,
1693
- renderExpanded,
1694
- sort,
1695
- onSortChange
1696
- }) {
1697
- const minTableW = columns.reduce((sum, c) => sum + (c.width ?? FLEX_MIN_COL_W), 0) + (columns.length + 1) * 12;
1698
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { borderWidth: 1, borderColor: "$borderColor", rounded: "$4", overflow: "hidden", children: [
1699
- /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { style: { overflowX: "auto", overflowY: "visible" }, children: /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { minW: minTableW, children: [
1700
- /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { bg: "$color1", py: "$2.5", px: "$3", gap: "$3", borderBottomWidth: 1, borderColor: "$borderColor", role: "row", children: columns.map((c) => {
1701
- const sortable = c.sortable === true && !!onSortChange;
1702
- const active = sortable && sort?.key === c.key;
1703
- const Caret = !sortable ? null : !active ? lucideIcons2.ChevronsUpDown : sort?.dir === "asc" ? lucideIcons2.ChevronUp : lucideIcons2.ChevronDown;
1704
- return /* @__PURE__ */ jsxRuntime.jsxs(
1705
- gui.XStack,
1706
- {
1707
- width: c.width,
1708
- flex: c.width ? void 0 : 1,
1709
- minW: c.width ? void 0 : FLEX_MIN_COL_W,
1710
- items: "center",
1711
- gap: "$1",
1712
- justify: c.align === "right" ? "flex-end" : "flex-start",
1713
- role: "columnheader",
1714
- "aria-sort": sortable ? active ? sort?.dir === "asc" ? "ascending" : "descending" : "none" : void 0,
1715
- "aria-label": sortable ? `Sort by ${c.header}` : void 0,
1716
- cursor: sortable ? "pointer" : void 0,
1717
- hoverStyle: sortable ? { opacity: 0.75 } : void 0,
1718
- onPress: sortable ? () => onSortChange?.(c.key) : void 0,
1719
- children: [
1720
- /* @__PURE__ */ jsxRuntime.jsx(
1721
- gui.Text,
1722
- {
1723
- fontSize: "$1",
1724
- fontWeight: "500",
1725
- color: active ? "$color12" : "$color10",
1726
- text: c.align === "right" ? "right" : "left",
1727
- className: c.mono ? "hz-tnum" : void 0,
1728
- children: c.header
1729
- }
1730
- ),
1731
- Caret ? /* @__PURE__ */ jsxRuntime.jsx(Caret, { size: 12, color: active ? "$color12" : "$color9" }) : null
1732
- ]
1733
- },
1734
- c.key
1735
- );
1736
- }) }),
1737
- loading ? /* @__PURE__ */ jsxRuntime.jsx(SkeletonRows, { columns }) : rows2.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { children: rows2.map((row) => {
1738
- const expanded = (isRowExpanded?.(row) ?? false) && !!renderExpanded;
1739
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { children: [
1740
- /* @__PURE__ */ jsxRuntime.jsx(
1741
- gui.XStack,
1742
- {
1743
- className: "hz-row",
1744
- py: "$2.5",
1745
- px: "$3",
1746
- gap: "$3",
1747
- borderTopWidth: 1,
1748
- borderColor: "$borderColor",
1749
- items: "center",
1750
- bg: expanded ? "$color2" : void 0,
1751
- hoverStyle: onRowPress ? { bg: "$color2" } : void 0,
1752
- cursor: onRowPress ? "pointer" : void 0,
1753
- onPress: onRowPress ? () => onRowPress(row) : void 0,
1754
- children: columns.map((c) => {
1755
- const cell = c.render ? c.render(row) : String(row[c.key] ?? "");
1756
- return /* @__PURE__ */ jsxRuntime.jsx(
1757
- gui.YStack,
1758
- {
1759
- width: c.width,
1760
- flex: c.width ? void 0 : 1,
1761
- minW: c.width ? void 0 : FLEX_MIN_COL_W,
1762
- justify: "center",
1763
- items: c.align === "right" ? "flex-end" : "flex-start",
1764
- children: typeof cell === "string" || typeof cell === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
1765
- gui.Text,
1766
- {
1767
- fontSize: "$3",
1768
- numberOfLines: 1,
1769
- color: "$color12",
1770
- text: c.align === "right" ? "right" : "left",
1771
- className: c.mono ? "hz-mono" : void 0,
1772
- children: cell
1773
- }
1774
- ) : cell
1775
- },
1776
- c.key
1777
- );
1778
- })
1779
- }
1780
- ),
1781
- expanded && renderExpanded ? /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { borderTopWidth: 1, borderColor: "$borderColor", bg: "$color1", children: renderExpanded(row) }) : null
1782
- ] }, rowKey(row));
1783
- }) }) : null
1784
- ] }) }),
1785
- !loading && rows2.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { py: "$8", px: "$4", items: "center", gap: "$1", borderTopWidth: 1, borderColor: "$borderColor", children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { color: "$color10", fontSize: "$3", text: "center", children: empty }) }) : null
1786
- ] });
1787
- }
1788
- var FLEX_MIN_COL_W = 120;
1789
1593
  function CommerceResource({
1790
1594
  title,
1791
1595
  subtitle,
@@ -1801,14 +1605,14 @@ function CommerceResource({
1801
1605
  loadRef.current = load;
1802
1606
  const reload = react.useCallback(() => {
1803
1607
  setState({ phase: "loading" });
1804
- loadRef.current().then((r) => setState({ phase: "ready", data: r.rows })).catch((e) => setState({ phase: "error", error: classifyBackend(e) }));
1608
+ loadRef.current().then((r) => setState({ phase: "ready", data: r.rows })).catch((e) => setState({ phase: "error", error: chunkVGGGGXWS_cjs.classifyBackend(e) }));
1805
1609
  }, []);
1806
1610
  react.useEffect(() => {
1807
1611
  reload();
1808
1612
  }, [reload]);
1809
1613
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1810
1614
  /* @__PURE__ */ jsxRuntime.jsx(
1811
- PageHeader,
1615
+ chunkVGGGGXWS_cjs.PageHeader,
1812
1616
  {
1813
1617
  title,
1814
1618
  subtitle,
@@ -1818,8 +1622,8 @@ function CommerceResource({
1818
1622
  ] })
1819
1623
  }
1820
1624
  ),
1821
- state.phase === "error" ? /* @__PURE__ */ jsxRuntime.jsx(BackendStateCard, { state: state.error, onRetry: reload, hint }) : /* @__PURE__ */ jsxRuntime.jsx(
1822
- DataTable,
1625
+ state.phase === "error" ? /* @__PURE__ */ jsxRuntime.jsx(chunkVGGGGXWS_cjs.BackendStateCard, { state: state.error, onRetry: reload, hint }) : /* @__PURE__ */ jsxRuntime.jsx(
1626
+ chunkVGGGGXWS_cjs.DataTable,
1823
1627
  {
1824
1628
  columns,
1825
1629
  rows: state.phase === "ready" ? state.data : [],
@@ -1845,7 +1649,7 @@ function ConfirmDelete({
1845
1649
  await run();
1846
1650
  onDone();
1847
1651
  } catch (e) {
1848
- setErr(classifyBackend(e).message || "Failed to delete.");
1652
+ setErr(chunkVGGGGXWS_cjs.classifyBackend(e).message || "Failed to delete.");
1849
1653
  setBusy(false);
1850
1654
  }
1851
1655
  };
@@ -2068,131 +1872,6 @@ function AnimatedLogo({
2068
1872
  }
2069
1873
  );
2070
1874
  }
2071
- function isHexColor(v) {
2072
- return typeof v === "string" && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(v.trim());
2073
- }
2074
- function resolveAccent(theme) {
2075
- if (!theme || !theme.isEnabled) return null;
2076
- const hex = (theme.colorPrimary ?? "").trim();
2077
- return isHexColor(hex) ? hex : null;
2078
- }
2079
- function expandHex(hex) {
2080
- const h = hex.trim().toLowerCase();
2081
- if (h.length === 4) return `#${h[1]}${h[1]}${h[2]}${h[2]}${h[3]}${h[3]}`;
2082
- return h;
2083
- }
2084
- function contrastText(hex) {
2085
- if (!isHexColor(hex)) return "#ffffff";
2086
- const h = expandHex(hex);
2087
- const r = parseInt(h.slice(1, 3), 16) / 255;
2088
- const g = parseInt(h.slice(3, 5), 16) / 255;
2089
- const b = parseInt(h.slice(5, 7), 16) / 255;
2090
- const lin = (c) => c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
2091
- const luminance = 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
2092
- return luminance > 0.5 ? "#000000" : "#ffffff";
2093
- }
2094
- function accentFor(theme) {
2095
- const hex = resolveAccent(theme);
2096
- return { accent: hex, contrast: hex ? contrastText(hex) : "#ffffff" };
2097
- }
2098
- var DEFAULT = { accent: null, contrast: "#ffffff" };
2099
- var current = DEFAULT;
2100
- var listeners = /* @__PURE__ */ new Set();
2101
- function setOrgAccent(theme) {
2102
- const next = accentFor(theme);
2103
- if (next.accent === current.accent) return;
2104
- current = next.accent ? next : DEFAULT;
2105
- for (const l of listeners) l();
2106
- }
2107
- function subscribe(cb) {
2108
- listeners.add(cb);
2109
- return () => {
2110
- listeners.delete(cb);
2111
- };
2112
- }
2113
- function useAccent() {
2114
- return react.useSyncExternalStore(
2115
- subscribe,
2116
- () => current,
2117
- () => DEFAULT
2118
- );
2119
- }
2120
- function PrimaryButton(props) {
2121
- const { accent, contrast } = useAccent();
2122
- if (accent) {
2123
- return /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { style: { backgroundColor: accent, color: contrast, borderColor: accent }, ...props });
2124
- }
2125
- return /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { theme: "light", ...props });
2126
- }
2127
- function openHref2(href) {
2128
- if (typeof window !== "undefined") window.open(href, "_blank", "noopener");
2129
- }
2130
- function EmptyState({
2131
- icon: Icon,
2132
- title,
2133
- description,
2134
- bullets,
2135
- primary,
2136
- secondary
2137
- }) {
2138
- return /* @__PURE__ */ jsxRuntime.jsxs(
2139
- gui.Card,
2140
- {
2141
- borderWidth: 1,
2142
- borderColor: "$borderColor",
2143
- borderStyle: "dashed",
2144
- p: "$6",
2145
- gap: "$4",
2146
- items: "center",
2147
- maxWidth: 640,
2148
- self: "center",
2149
- width: "100%",
2150
- children: [
2151
- /* @__PURE__ */ jsxRuntime.jsx(
2152
- gui.YStack,
2153
- {
2154
- width: 48,
2155
- height: 48,
2156
- items: "center",
2157
- justify: "center",
2158
- rounded: "$4",
2159
- bg: "$color3",
2160
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 24 })
2161
- }
2162
- ),
2163
- /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$2", items: "center", maxW: 480, children: [
2164
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$6", fontWeight: "500", text: "center", letterSpacing: -0.3, children: title }),
2165
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$color11", text: "center", children: description })
2166
- ] }),
2167
- bullets && bullets.length ? /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { gap: "$2", self: "stretch", maxW: 420, mx: "auto", children: bullets.map((b) => /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "flex-start", children: [
2168
- /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { pt: "$1", children: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Check, { size: 14, color: "$color10" }) }),
2169
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$color11", flex: 1, children: b })
2170
- ] }, b)) }) : null,
2171
- primary || secondary ? /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", flexWrap: "wrap", justify: "center", children: [
2172
- primary ? /* @__PURE__ */ jsxRuntime.jsx(
2173
- PrimaryButton,
2174
- {
2175
- icon: primary.icon,
2176
- iconAfter: primary.href ? /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.ExternalLink, { size: 15 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.ArrowRight, { size: 15 }),
2177
- onPress: () => primary.href ? openHref2(primary.href) : primary.onPress?.(),
2178
- children: primary.label
2179
- }
2180
- ) : null,
2181
- secondary ? /* @__PURE__ */ jsxRuntime.jsx(
2182
- gui.Button,
2183
- {
2184
- chromeless: true,
2185
- icon: secondary.icon,
2186
- iconAfter: secondary.href ? /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.ExternalLink, { size: 14 }) : void 0,
2187
- onPress: () => secondary.href ? openHref2(secondary.href) : secondary.onPress?.(),
2188
- children: secondary.label
2189
- }
2190
- ) : null
2191
- ] }) : null
2192
- ]
2193
- }
2194
- );
2195
- }
2196
1875
  function FadeIn({
2197
1876
  children,
2198
1877
  index = 0,
@@ -2203,125 +1882,6 @@ function FadeIn({
2203
1882
  const delay = delayMs ?? index * step;
2204
1883
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hz-fade-up", style: { animationDelay: `${delay}ms`, ...style }, children });
2205
1884
  }
2206
- function FieldRow({ label, children }) {
2207
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$3", items: "flex-start", flexWrap: "wrap", children: [
2208
- /* @__PURE__ */ jsxRuntime.jsx(gui.Label, { width: "100%", pt: "$2", color: "$color11", fontSize: "$3", $md: { width: 180 }, children: label }),
2209
- /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { flex: 1, minW: 0, $md: { minW: 240 }, children })
2210
- ] });
2211
- }
2212
- function FieldText({
2213
- value,
2214
- onChange,
2215
- disabled,
2216
- secure,
2217
- placeholder
2218
- }) {
2219
- return /* @__PURE__ */ jsxRuntime.jsx(
2220
- gui.Input,
2221
- {
2222
- value,
2223
- onChangeText: onChange,
2224
- disabled,
2225
- secureTextEntry: secure,
2226
- placeholder,
2227
- autoCapitalize: "none"
2228
- }
2229
- );
2230
- }
2231
- function FieldTextArea({
2232
- value,
2233
- onChange,
2234
- disabled,
2235
- rows: rows2 = 6
2236
- }) {
2237
- return /* @__PURE__ */ jsxRuntime.jsx(gui.TextArea, { value, onChangeText: onChange, disabled, numberOfLines: rows2 });
2238
- }
2239
- function FieldSwitch({
2240
- checked,
2241
- onChange,
2242
- disabled
2243
- }) {
2244
- return /* @__PURE__ */ jsxRuntime.jsx(gui.Switch, { checked, onCheckedChange: onChange, disabled, size: "$3", children: /* @__PURE__ */ jsxRuntime.jsx(gui.Switch.Thumb, {}) });
2245
- }
2246
- var CHEVRON = `data:image/svg+xml,${encodeURIComponent(
2247
- '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#9a9a9a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>'
2248
- )}`;
2249
- function selectStyle(disabled) {
2250
- return {
2251
- width: "100%",
2252
- boxSizing: "border-box",
2253
- appearance: "none",
2254
- WebkitAppearance: "none",
2255
- MozAppearance: "none",
2256
- background: `var(--background) url("${CHEVRON}") no-repeat right 10px center`,
2257
- color: "var(--color12)",
2258
- border: "1px solid var(--borderColor)",
2259
- borderRadius: 9,
2260
- padding: "9px 34px 9px 12px",
2261
- fontSize: 14,
2262
- lineHeight: "20px",
2263
- fontFamily: "inherit",
2264
- height: 40,
2265
- outline: "none",
2266
- cursor: disabled ? "not-allowed" : "pointer",
2267
- opacity: disabled ? 0.5 : 1
2268
- };
2269
- }
2270
- var OPTION_STYLE = { background: "var(--color2)", color: "var(--color12)" };
2271
- function FieldSelect({
2272
- value,
2273
- options,
2274
- onChange,
2275
- disabled,
2276
- placeholder = "Select\u2026"
2277
- }) {
2278
- const showPlaceholder = value === "" || !options.includes(value);
2279
- return /* @__PURE__ */ jsxRuntime.jsxs(
2280
- "select",
2281
- {
2282
- value: showPlaceholder ? "" : value,
2283
- onChange: (e) => onChange(e.currentTarget.value),
2284
- disabled,
2285
- "aria-label": placeholder,
2286
- style: selectStyle(disabled),
2287
- children: [
2288
- showPlaceholder ? /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, style: OPTION_STYLE, children: placeholder }) : null,
2289
- options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, style: OPTION_STYLE, children: opt }, opt))
2290
- ]
2291
- }
2292
- );
2293
- }
2294
- function FieldSlider({
2295
- value,
2296
- min,
2297
- max,
2298
- step,
2299
- onChange,
2300
- disabled
2301
- }) {
2302
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$3", items: "center", children: [
2303
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { width: 56, fontSize: "$3", color: "$color11", children: value }),
2304
- /* @__PURE__ */ jsxRuntime.jsxs(
2305
- gui.Slider,
2306
- {
2307
- flex: 1,
2308
- min,
2309
- max,
2310
- step,
2311
- value: [value],
2312
- onValueChange: (v) => onChange(v[0] ?? min),
2313
- disabled,
2314
- children: [
2315
- /* @__PURE__ */ jsxRuntime.jsx(gui.Slider.Track, { children: /* @__PURE__ */ jsxRuntime.jsx(gui.Slider.TrackActive, {}) }),
2316
- /* @__PURE__ */ jsxRuntime.jsx(gui.Slider.Thumb, { index: 0, circular: true })
2317
- ]
2318
- }
2319
- )
2320
- ] });
2321
- }
2322
-
2323
- // src/product/color.ts
2324
- var asColor = (hex) => hex;
2325
1885
  function ProductIcon({
2326
1886
  icon: Icon,
2327
1887
  color,
@@ -2340,7 +1900,7 @@ function ProductIcon({
2340
1900
  justify: "center",
2341
1901
  rounded: radius,
2342
1902
  style: { backgroundColor: color },
2343
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: glyph, color: asColor("#ffffff") })
1903
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: glyph, color: chunkVGGGGXWS_cjs.asColor("#ffffff") })
2344
1904
  }
2345
1905
  );
2346
1906
  }
@@ -2525,169 +2085,6 @@ function SelectMenu({
2525
2085
  }
2526
2086
  );
2527
2087
  }
2528
- var LG = 1024;
2529
- var lockCount = 0;
2530
- var savedOverflow = "";
2531
- function lockScroll() {
2532
- if (typeof document === "undefined") return;
2533
- if (lockCount === 0) {
2534
- savedOverflow = document.body.style.overflow;
2535
- document.body.style.overflow = "hidden";
2536
- }
2537
- lockCount++;
2538
- }
2539
- function unlockScroll() {
2540
- if (typeof document === "undefined") return;
2541
- lockCount = Math.max(0, lockCount - 1);
2542
- if (lockCount === 0) document.body.style.overflow = savedOverflow;
2543
- }
2544
- function SlideOver({
2545
- open,
2546
- onClose,
2547
- side = "right",
2548
- size = 420,
2549
- title,
2550
- icon: Icon,
2551
- iconColor,
2552
- headerRight,
2553
- ariaLabel,
2554
- zIndex = 1e3,
2555
- children
2556
- }) {
2557
- const panelRef = react.useRef(null);
2558
- const openerRef = react.useRef(null);
2559
- react.useEffect(() => {
2560
- if (!open) return;
2561
- openerRef.current = typeof document !== "undefined" ? document.activeElement : null;
2562
- lockScroll();
2563
- const t = window.setTimeout(() => {
2564
- const el = panelRef.current;
2565
- if (el && typeof el.focus === "function") el.focus();
2566
- }, 0);
2567
- return () => {
2568
- window.clearTimeout(t);
2569
- unlockScroll();
2570
- const opener = openerRef.current;
2571
- if (opener && opener instanceof HTMLElement && typeof opener.focus === "function") opener.focus();
2572
- };
2573
- }, [open]);
2574
- react.useEffect(() => {
2575
- if (!open) return;
2576
- const onKey = (e) => {
2577
- if (e.key === "Escape") {
2578
- e.stopPropagation();
2579
- onClose();
2580
- }
2581
- };
2582
- window.addEventListener("keydown", onKey);
2583
- return () => window.removeEventListener("keydown", onKey);
2584
- }, [open, onClose]);
2585
- const offscreen = side === "right" ? "translateX(100%)" : "translateX(-100%)";
2586
- const edge = side === "right" ? { r: 0 } : { l: 0 };
2587
- return /* @__PURE__ */ jsxRuntime.jsxs(
2588
- gui.YStack,
2589
- {
2590
- overflow: "hidden",
2591
- pointerEvents: open ? "auto" : "none",
2592
- "aria-hidden": !open,
2593
- style: { position: "fixed", inset: 0, zIndex },
2594
- children: [
2595
- /* @__PURE__ */ jsxRuntime.jsx(
2596
- gui.YStack,
2597
- {
2598
- position: "absolute",
2599
- t: 0,
2600
- l: 0,
2601
- r: 0,
2602
- b: 0,
2603
- bg: "rgba(0,0,0,0.55)",
2604
- className: "hz-fade",
2605
- style: { opacity: open ? 1 : 0 },
2606
- onPress: onClose
2607
- }
2608
- ),
2609
- /* @__PURE__ */ jsxRuntime.jsx(
2610
- gui.YStack,
2611
- {
2612
- ref: panelRef,
2613
- tabIndex: -1,
2614
- role: "dialog",
2615
- "aria-modal": open ? true : void 0,
2616
- "aria-label": typeof title === "string" ? title : ariaLabel,
2617
- position: "absolute",
2618
- t: 0,
2619
- b: 0,
2620
- ...edge,
2621
- width: "100%",
2622
- $lg: { width: size, maxW: "100vw" },
2623
- bg: "$color1",
2624
- borderLeftWidth: side === "right" ? 1 : 0,
2625
- borderRightWidth: side === "left" ? 1 : 0,
2626
- borderColor: "$borderColor",
2627
- className: "hz-slide hz-elevation-4",
2628
- style: {
2629
- transform: open ? "translateX(0)" : offscreen,
2630
- height: "100dvh",
2631
- paddingTop: "env(safe-area-inset-top)",
2632
- paddingBottom: "env(safe-area-inset-bottom)"
2633
- },
2634
- children: title !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2635
- /* @__PURE__ */ jsxRuntime.jsxs(
2636
- gui.XStack,
2637
- {
2638
- items: "center",
2639
- gap: "$2.5",
2640
- px: "$4",
2641
- height: 56,
2642
- borderBottomWidth: 1,
2643
- borderColor: "$borderColor",
2644
- children: [
2645
- Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 18, color: iconColor ? asColor(iconColor) : void 0 }) : null,
2646
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { flex: 1, fontSize: "$5", fontWeight: "700", color: "$color12", numberOfLines: 1, children: title }),
2647
- headerRight,
2648
- /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { chromeless: true, width: 44, height: 44, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.X, { size: 18 }), onPress: onClose, "aria-label": "Close" })
2649
- ]
2650
- }
2651
- ),
2652
- /* @__PURE__ */ jsxRuntime.jsx(gui.ScrollView, { flex: 1, children: /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { flex: 1, p: "$4", gap: "$3", children }) })
2653
- ] }) : (
2654
- // Bare mode — the caller owns the full panel layout (e.g. the nav drawer
2655
- // renders its own header + scroll + footer).
2656
- children
2657
- )
2658
- }
2659
- )
2660
- ]
2661
- }
2662
- );
2663
- }
2664
- var toneOf = (status) => {
2665
- const s = status.toLowerCase();
2666
- if (s === "green") return "green";
2667
- if (s === "yellow") return "yellow";
2668
- if (s === "red") return "red";
2669
- if (["ready", "active", "running", "available", "ok", "live", "succeeded", "connected", "synced", "imported"].includes(s)) return "green";
2670
- if (["creating", "provisioning", "pending", "updating", "attaching", "building", "deploying", "queued", "importing"].includes(s))
2671
- return "yellow";
2672
- if (["error", "failed", "degraded", "down", "canceled", "conflict"].includes(s)) return "red";
2673
- return "neutral";
2674
- };
2675
- var TONE_BG = {
2676
- green: "$color5",
2677
- yellow: "$color4",
2678
- red: "$color4",
2679
- neutral: "$color3"
2680
- };
2681
- var TONE_FG = {
2682
- green: "$color12",
2683
- yellow: "$color12",
2684
- red: "$color12",
2685
- neutral: "$color11"
2686
- };
2687
- function StatusTag({ status }) {
2688
- const tone2 = toneOf(status ?? "");
2689
- return /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", px: "$2", py: "$1", rounded: "$2", bg: TONE_BG[tone2], color: TONE_FG[tone2], children: status || "unknown" });
2690
- }
2691
2088
  var ToastContext = react.createContext(null);
2692
2089
  var ACCENT3 = {
2693
2090
  success: "$green10",
@@ -2785,622 +2182,6 @@ function useToast() {
2785
2182
  return ctx;
2786
2183
  }
2787
2184
 
2788
- // src/product/social/api.ts
2789
- var enc = encodeURIComponent;
2790
- var str = (v) => typeof v === "string" ? v : v == null ? "" : String(v);
2791
- var num = (v) => {
2792
- if (typeof v === "number" && Number.isFinite(v)) return v;
2793
- if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v))) return Number(v);
2794
- return 0;
2795
- };
2796
- var strs = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
2797
- var asRecord = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
2798
- var rows = (payload) => {
2799
- if (Array.isArray(payload)) return payload.filter((x) => x && typeof x === "object");
2800
- if (payload && typeof payload === "object") {
2801
- for (const k of ["data", "items", "rows"]) {
2802
- const v = payload[k];
2803
- if (Array.isArray(v)) return v.filter((x) => x && typeof x === "object");
2804
- }
2805
- }
2806
- return [];
2807
- };
2808
- var PROVIDERS = ["x", "facebook", "instagram", "linkedin", "tiktok", "youtube", "threads"];
2809
- var ACCOUNT_STATUSES = ["connected", "disconnected", "error"];
2810
- var POST_STATUSES = ["draft", "scheduled", "published", "failed"];
2811
- function normalizeAccount(raw) {
2812
- const r = asRecord(raw);
2813
- return {
2814
- id: str(r.id),
2815
- provider: str(r.provider) || "x",
2816
- handle: str(r.handle),
2817
- status: str(r.status) || "connected",
2818
- createdAt: num(r.createdAt),
2819
- updatedAt: num(r.updatedAt)
2820
- };
2821
- }
2822
- function normalizePost(raw) {
2823
- const r = asRecord(raw);
2824
- return {
2825
- id: str(r.id),
2826
- content: str(r.content),
2827
- channel: str(r.channel) || "x",
2828
- status: str(r.status) || "draft",
2829
- scheduleAt: num(r.scheduleAt),
2830
- media: strs(r.media),
2831
- accountId: str(r.accountId) || void 0,
2832
- externalId: str(r.externalId) || void 0,
2833
- error: str(r.error) || void 0,
2834
- createdAt: num(r.createdAt),
2835
- updatedAt: num(r.updatedAt)
2836
- };
2837
- }
2838
- function normalizeSummary(raw) {
2839
- const r = asRecord(raw);
2840
- return { posts: num(r.posts), scheduled: num(r.scheduled), published: num(r.published), accounts: num(r.accounts) };
2841
- }
2842
- function normalizeProviderCapability(raw) {
2843
- const r = asRecord(raw);
2844
- return {
2845
- provider: str(r.provider),
2846
- credentialsConfigured: Boolean(r.credentialsConfigured),
2847
- missingCredentials: strs(r.missingCredentials)
2848
- };
2849
- }
2850
- var normalizeAccounts = (p) => rows(p).map(normalizeAccount).filter((a) => a.id);
2851
- var normalizePosts = (p) => rows(p).map(normalizePost).filter((x) => x.id);
2852
- var normalizeProviders = (p) => rows(p).map(normalizeProviderCapability).filter((c) => c.provider);
2853
- function createSocialApi(rest) {
2854
- return {
2855
- summary: () => rest.get("summary").then(normalizeSummary),
2856
- /** Publish-readiness per network (+ the exact missing OAuth-app credentials). */
2857
- providers: () => rest.get("providers").then(normalizeProviders),
2858
- accounts: {
2859
- list: (provider) => rest.get(`accounts${provider ? `?provider=${enc(provider)}` : ""}`).then(normalizeAccounts),
2860
- get: (id) => rest.get(`accounts/${enc(id)}`).then(normalizeAccount),
2861
- create: (body) => rest.post("accounts", body).then(normalizeAccount),
2862
- update: (id, body) => rest.put(`accounts/${enc(id)}`, body).then(normalizeAccount),
2863
- remove: (id) => rest.del(`accounts/${enc(id)}`)
2864
- },
2865
- posts: {
2866
- list: (status) => rest.get(`posts${status ? `?status=${enc(status)}` : ""}`).then(normalizePosts),
2867
- get: (id) => rest.get(`posts/${enc(id)}`).then(normalizePost),
2868
- create: (body) => rest.post("posts", body).then(normalizePost),
2869
- update: (id, body) => rest.put(`posts/${enc(id)}`, body).then(normalizePost),
2870
- remove: (id) => rest.del(`posts/${enc(id)}`),
2871
- /** Publish a post NOW to its channel's connected accounts. */
2872
- publish: (id) => rest.post(`posts/${enc(id)}/publish`).then(normalizePost)
2873
- }
2874
- };
2875
- }
2876
-
2877
- // src/product/social/format.ts
2878
- function formatPostTime(unix) {
2879
- if (!unix) return "\u2014";
2880
- return new Date(unix * 1e3).toLocaleString(void 0, {
2881
- month: "short",
2882
- day: "numeric",
2883
- hour: "2-digit",
2884
- minute: "2-digit"
2885
- });
2886
- }
2887
- function postDayBucket(unix) {
2888
- const d = new Date(unix * 1e3);
2889
- const key = `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
2890
- const label = d.toLocaleDateString(void 0, { weekday: "short", month: "short", day: "numeric" });
2891
- return { key, label };
2892
- }
2893
- function postPreview(s) {
2894
- const t = s.trim();
2895
- return t.length > 72 ? `${t.slice(0, 72)}\u2026` : t || "\u2014";
2896
- }
2897
- function parsePostTime(dt) {
2898
- const ms = Date.parse(dt.trim());
2899
- return Number.isFinite(ms) && ms > 0 ? Math.floor(ms / 1e3) : 0;
2900
- }
2901
- function PostAgenda({ posts, onOpen }) {
2902
- const days = react.useMemo(() => {
2903
- const timed = posts.filter((p) => (p.scheduleAt ?? 0) > 0).sort((a, b) => (a.scheduleAt ?? 0) - (b.scheduleAt ?? 0));
2904
- const groups = [];
2905
- const index = /* @__PURE__ */ new Map();
2906
- for (const p of timed) {
2907
- const { key, label } = postDayBucket(p.scheduleAt ?? 0);
2908
- let i = index.get(key);
2909
- if (i === void 0) {
2910
- i = groups.length;
2911
- index.set(key, i);
2912
- groups.push({ label, items: [] });
2913
- }
2914
- groups[i].items.push(p);
2915
- }
2916
- return groups;
2917
- }, [posts]);
2918
- if (days.length === 0) {
2919
- return /* @__PURE__ */ jsxRuntime.jsx(
2920
- EmptyState,
2921
- {
2922
- icon: lucideIcons2.Calendar,
2923
- title: "Nothing on the calendar",
2924
- description: "Scheduled and timed posts appear here, grouped by day. Compose a post and pick Schedule to plan ahead."
2925
- }
2926
- );
2927
- }
2928
- return /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { gap: "$4", children: days.map((d) => /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$2", children: [
2929
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", fontWeight: "500", color: "$color11", children: d.label }),
2930
- d.items.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
2931
- gui.XStack,
2932
- {
2933
- items: "center",
2934
- justify: "space-between",
2935
- gap: "$3",
2936
- borderWidth: 1,
2937
- borderColor: "$borderColor",
2938
- rounded: "$4",
2939
- px: "$4",
2940
- py: "$3",
2941
- cursor: "pointer",
2942
- hoverStyle: { bg: "$color2" },
2943
- onPress: () => onOpen(p),
2944
- children: [
2945
- /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$1", flex: 1, children: [
2946
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", children: postPreview(p.content) }),
2947
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$2", items: "center", children: [
2948
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$color10", children: p.channel }),
2949
- /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$1", color: "$color10", children: [
2950
- "\xB7 ",
2951
- formatPostTime(p.scheduleAt ?? 0)
2952
- ] })
2953
- ] })
2954
- ] }),
2955
- /* @__PURE__ */ jsxRuntime.jsx(StatusTag, { status: p.status })
2956
- ]
2957
- },
2958
- p.id
2959
- ))
2960
- ] }, d.label)) });
2961
- }
2962
- var COMPOSE_MODES = ["draft", "schedule", "now"];
2963
- var COMPOSE_LABEL = {
2964
- draft: "Save draft",
2965
- schedule: "Schedule",
2966
- now: "Publish now"
2967
- };
2968
- function PostComposer({
2969
- channels,
2970
- providers,
2971
- onSubmit
2972
- }) {
2973
- const [content, setContent] = react.useState("");
2974
- const [channel, setChannel] = react.useState(channels[0] ?? "x");
2975
- const [mode, setMode] = react.useState("draft");
2976
- const [scheduleAt, setScheduleAt] = react.useState("");
2977
- const [saving, setSaving] = react.useState(false);
2978
- const [error, setError] = react.useState(null);
2979
- const cap = providers.find((p) => p.provider === channel);
2980
- const unconfigured = (mode === "now" || mode === "schedule") && !!cap && !cap.credentialsConfigured;
2981
- const submit = async () => {
2982
- if (!content.trim()) {
2983
- setError("Content is required.");
2984
- return;
2985
- }
2986
- let status = "draft";
2987
- let at = 0;
2988
- if (mode === "schedule") {
2989
- at = parsePostTime(scheduleAt);
2990
- if (at <= Math.floor(Date.now() / 1e3)) {
2991
- setError("Pick a future date and time to schedule.");
2992
- return;
2993
- }
2994
- status = "scheduled";
2995
- } else if (mode === "now") {
2996
- status = "scheduled";
2997
- }
2998
- setSaving(true);
2999
- setError(null);
3000
- const message = await onSubmit({ content: content.trim(), channel, status, scheduleAt: at }, mode);
3001
- if (message) {
3002
- setError(message);
3003
- setSaving(false);
3004
- }
3005
- };
3006
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$3", p: "$4", children: [
3007
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Content", children: /* @__PURE__ */ jsxRuntime.jsx(FieldTextArea, { value: content, onChange: setContent, disabled: saving }) }),
3008
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Channel", children: /* @__PURE__ */ jsxRuntime.jsx(FieldSelect, { value: channel, options: channels, onChange: setChannel, disabled: saving }) }),
3009
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "When", children: /* @__PURE__ */ jsxRuntime.jsx(
3010
- FieldSelect,
3011
- {
3012
- value: mode,
3013
- options: [...COMPOSE_MODES],
3014
- onChange: (v) => setMode(v),
3015
- disabled: saving
3016
- }
3017
- ) }),
3018
- mode === "schedule" ? /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Schedule at", children: /* @__PURE__ */ jsxRuntime.jsx(
3019
- FieldText,
3020
- {
3021
- value: scheduleAt,
3022
- onChange: setScheduleAt,
3023
- placeholder: "2026-07-15 09:00",
3024
- disabled: saving
3025
- }
3026
- ) }) : null,
3027
- unconfigured ? /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "flex-start", gap: "$2", children: [
3028
- /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.AlertTriangle, { size: 14, color: "var(--yellow10)" }),
3029
- /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$1", color: "$color10", children: [
3030
- channel,
3031
- " isn\u2019t configured to publish yet \u2014 needs ",
3032
- cap?.missingCredentials.join(", "),
3033
- ". The post is saved and marked failed on publish until credentials are supplied."
3034
- ] })
3035
- ] }) : null,
3036
- error ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$red10", children: error }) : null,
3037
- /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onPress: submit, disabled: saving, children: saving ? "Working\u2026" : COMPOSE_LABEL[mode] })
3038
- ] });
3039
- }
3040
- function ProviderReadinessList({ providers }) {
3041
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$2", children: [
3042
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color10", children: "Network publish-readiness" }),
3043
- providers.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", justify: "space-between", gap: "$3", py: "$1", children: [
3044
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", gap: "$2", children: [
3045
- p.credentialsConfigured ? /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.CheckCircle2, { size: 14, color: "var(--green10)" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.AlertTriangle, { size: 14, color: "var(--yellow10)" }),
3046
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", children: p.provider })
3047
- ] }),
3048
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$color10", children: p.credentialsConfigured ? "Ready" : `needs ${p.missingCredentials.join(", ")}` })
3049
- ] }, p.provider))
3050
- ] });
3051
- }
3052
- function SocialSummaryBar({ summary }) {
3053
- const cells = [
3054
- { label: "Posts", value: summary.posts },
3055
- { label: "Scheduled", value: summary.scheduled },
3056
- { label: "Published", value: summary.published },
3057
- { label: "Accounts", value: summary.accounts }
3058
- ];
3059
- return /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { gap: "$3", flexWrap: "wrap", children: cells.map((c) => /* @__PURE__ */ jsxRuntime.jsxs(
3060
- gui.YStack,
3061
- {
3062
- gap: "$1",
3063
- borderWidth: 1,
3064
- borderColor: "$borderColor",
3065
- rounded: "$4",
3066
- px: "$4",
3067
- py: "$3",
3068
- minW: 140,
3069
- children: [
3070
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$color10", children: c.label }),
3071
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$6", fontWeight: "500", className: "hz-tnum", children: c.value })
3072
- ]
3073
- },
3074
- c.label
3075
- )) });
3076
- }
3077
- var OPTIONS = [
3078
- { id: "list", label: "List", icon: lucideIcons2.List },
3079
- { id: "calendar", label: "Calendar", icon: lucideIcons2.Calendar }
3080
- ];
3081
- function ViewToggle({
3082
- view,
3083
- onChange
3084
- }) {
3085
- return /* @__PURE__ */ jsxRuntime.jsx(gui.XStack, { borderWidth: 1, borderColor: "$borderColor", rounded: "$4", overflow: "hidden", children: OPTIONS.map((o) => {
3086
- const Icon = o.icon;
3087
- const active = view === o.id;
3088
- return /* @__PURE__ */ jsxRuntime.jsxs(
3089
- gui.XStack,
3090
- {
3091
- items: "center",
3092
- gap: "$2",
3093
- px: "$3",
3094
- py: "$2",
3095
- cursor: "pointer",
3096
- bg: active ? "$color4" : "transparent",
3097
- hoverStyle: { bg: active ? "$color4" : "$color2" },
3098
- onPress: () => onChange(o.id),
3099
- children: [
3100
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 14 }),
3101
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", fontWeight: active ? "500" : "400", children: o.label })
3102
- ]
3103
- },
3104
- o.id
3105
- );
3106
- }) });
3107
- }
3108
- var POST_COLUMNS = [
3109
- { key: "content", header: "Post", render: (p) => postPreview(p.content) },
3110
- { key: "channel", header: "Channel", render: (p) => p.channel || "\u2014" },
3111
- { key: "status", header: "Status", render: (p) => /* @__PURE__ */ jsxRuntime.jsx(StatusTag, { status: p.status }) },
3112
- { key: "scheduleAt", header: "Scheduled", render: (p) => formatPostTime(p.scheduleAt) }
3113
- ];
3114
- var ACCOUNT_COLUMNS = [
3115
- { key: "handle", header: "Account", render: (a) => a.handle || "\u2014" },
3116
- { key: "provider", header: "Network", render: (a) => a.provider || "\u2014" },
3117
- { key: "status", header: "Status", render: (a) => /* @__PURE__ */ jsxRuntime.jsx(StatusTag, { status: a.status }) }
3118
- ];
3119
- function PostDetail({ api, post, onChanged }) {
3120
- const [publishing, setPublishing] = react.useState(false);
3121
- const [error, setError] = react.useState(null);
3122
- const canPublish = post.status === "draft" || post.status === "scheduled" || post.status === "failed";
3123
- const publish = async () => {
3124
- setPublishing(true);
3125
- setError(null);
3126
- try {
3127
- await api.posts.publish(post.id);
3128
- onChanged();
3129
- } catch (e) {
3130
- setError(classifyBackend(e).message || "Publish failed.");
3131
- } finally {
3132
- setPublishing(false);
3133
- }
3134
- };
3135
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$3", p: "$4", children: [
3136
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Content", children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", children: post.content || "\u2014" }) }),
3137
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Channel", children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", children: post.channel }) }),
3138
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Status", children: /* @__PURE__ */ jsxRuntime.jsx(StatusTag, { status: post.status }) }),
3139
- post.scheduleAt > 0 ? /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Scheduled", children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", children: formatPostTime(post.scheduleAt) }) }) : null,
3140
- post.media.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Media", children: /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { gap: "$1", children: post.media.map((m) => /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color11", children: m }, m)) }) }) : null,
3141
- post.externalId ? /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "External id", children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", className: "hz-tnum", children: post.externalId }) }) : null,
3142
- post.error ? /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Last error", children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$red10", children: post.error }) }) : null,
3143
- error ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$red10", children: error }) : null,
3144
- canPublish ? /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onPress: publish, disabled: publishing, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Send, { size: 16 }), children: publishing ? "Publishing\u2026" : "Publish now" }) : null
3145
- ] });
3146
- }
3147
- function ConnectAccount({
3148
- api,
3149
- providers,
3150
- onCreated
3151
- }) {
3152
- const [provider, setProvider] = react.useState("x");
3153
- const [handle, setHandle] = react.useState("");
3154
- const [saving, setSaving] = react.useState(false);
3155
- const [error, setError] = react.useState(null);
3156
- const submit = async () => {
3157
- setSaving(true);
3158
- setError(null);
3159
- try {
3160
- await api.accounts.create({ provider, handle: handle.trim(), status: "connected" });
3161
- onCreated();
3162
- } catch (e) {
3163
- setError(classifyBackend(e).message || "Failed to connect account.");
3164
- } finally {
3165
- setSaving(false);
3166
- }
3167
- };
3168
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$4", p: "$4", children: [
3169
- /* @__PURE__ */ jsxRuntime.jsx(ProviderReadinessList, { providers }),
3170
- /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$3", children: [
3171
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Network", children: /* @__PURE__ */ jsxRuntime.jsx(FieldSelect, { value: provider, options: [...PROVIDERS], onChange: setProvider, disabled: saving }) }),
3172
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Handle", children: /* @__PURE__ */ jsxRuntime.jsx(FieldText, { value: handle, onChange: setHandle, placeholder: "@hanzo", disabled: saving }) }),
3173
- error ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$red10", children: error }) : null,
3174
- /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onPress: submit, disabled: saving, children: saving ? "Connecting\u2026" : "Connect account" })
3175
- ] })
3176
- ] });
3177
- }
3178
- function SocialResource({
3179
- api,
3180
- title = "Publish",
3181
- subtitle = "Compose, schedule and publish your content across networks \u2014 per org, over the native /v1/social engine."
3182
- }) {
3183
- const [state, setState] = react.useState({ phase: "loading" });
3184
- const [view, setView] = react.useState("list");
3185
- const [composing, setComposing] = react.useState(false);
3186
- const [connecting, setConnecting] = react.useState(false);
3187
- const [openPost, setOpenPost] = react.useState(null);
3188
- const load = react.useCallback(async () => {
3189
- setState({ phase: "loading" });
3190
- try {
3191
- const [summary, posts2, accounts2, providers2] = await Promise.all([
3192
- api.summary(),
3193
- api.posts.list(),
3194
- api.accounts.list(),
3195
- api.providers()
3196
- ]);
3197
- setState({ phase: "ready", data: { summary, posts: posts2, accounts: accounts2, providers: providers2 } });
3198
- } catch (e) {
3199
- setState({ phase: "error", error: classifyBackend(e) });
3200
- }
3201
- }, [api]);
3202
- react.useEffect(() => {
3203
- void load();
3204
- }, [load]);
3205
- const providers = state.phase === "ready" ? state.data.providers : [];
3206
- const posts = state.phase === "ready" ? state.data.posts : [];
3207
- const accounts = state.phase === "ready" ? state.data.accounts : [];
3208
- const empty = state.phase === "ready" && posts.length === 0 && accounts.length === 0;
3209
- const submitDraft = async (draft, mode) => {
3210
- try {
3211
- const created = await api.posts.create(draft);
3212
- if (mode === "now" && created.status === "failed") return created.error || "Publish failed.";
3213
- } catch (e) {
3214
- return classifyBackend(e).message || "Failed to create post.";
3215
- }
3216
- setComposing(false);
3217
- void load();
3218
- return null;
3219
- };
3220
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$4", p: "$4", children: [
3221
- /* @__PURE__ */ jsxRuntime.jsx(
3222
- PageHeader,
3223
- {
3224
- title,
3225
- subtitle,
3226
- actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3227
- /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onPress: () => setComposing(true), icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Plus, { size: 16 }), children: "New post" }),
3228
- /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onPress: () => setConnecting(true), icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Link2, { size: 16 }), children: "Connect account" }),
3229
- /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onPress: () => void load(), icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.RefreshCw, { size: 16 }), children: "Refresh" })
3230
- ] })
3231
- }
3232
- ),
3233
- state.phase === "error" ? /* @__PURE__ */ jsxRuntime.jsx(BackendStateCard, { state: state.error, onRetry: () => void load() }) : empty ? /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$4", children: [
3234
- state.phase === "ready" ? /* @__PURE__ */ jsxRuntime.jsx(SocialSummaryBar, { summary: state.data.summary }) : null,
3235
- /* @__PURE__ */ jsxRuntime.jsx(
3236
- EmptyState,
3237
- {
3238
- icon: lucideIcons2.Share2,
3239
- title: "No posts or accounts yet",
3240
- description: "Connect a social account, then compose, schedule and publish across X, Instagram, LinkedIn, TikTok and more.",
3241
- primary: { label: "New post", onPress: () => setComposing(true) }
3242
- }
3243
- )
3244
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$5", children: [
3245
- state.phase === "ready" ? /* @__PURE__ */ jsxRuntime.jsx(SocialSummaryBar, { summary: state.data.summary }) : null,
3246
- /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$3", children: [
3247
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", justify: "space-between", gap: "$2", flexWrap: "wrap", children: [
3248
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", gap: "$2", children: [
3249
- /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Send, { size: 16 }),
3250
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$5", fontWeight: "500", children: "Posts" })
3251
- ] }),
3252
- /* @__PURE__ */ jsxRuntime.jsx(ViewToggle, { view, onChange: setView })
3253
- ] }),
3254
- view === "list" ? /* @__PURE__ */ jsxRuntime.jsx(
3255
- DataTable,
3256
- {
3257
- columns: POST_COLUMNS,
3258
- rows: posts,
3259
- loading: state.phase === "loading",
3260
- empty: "No posts yet.",
3261
- rowKey: (p) => p.id,
3262
- onRowPress: (p) => setOpenPost(p)
3263
- }
3264
- ) : /* @__PURE__ */ jsxRuntime.jsx(PostAgenda, { posts, onOpen: (p) => setOpenPost(p) })
3265
- ] }),
3266
- /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$2", children: [
3267
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", gap: "$2", children: [
3268
- /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Link2, { size: 16 }),
3269
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$5", fontWeight: "500", children: "Accounts" })
3270
- ] }),
3271
- /* @__PURE__ */ jsxRuntime.jsx(
3272
- DataTable,
3273
- {
3274
- columns: ACCOUNT_COLUMNS,
3275
- rows: accounts,
3276
- loading: state.phase === "loading",
3277
- empty: "No accounts connected yet.",
3278
- rowKey: (a) => a.id
3279
- }
3280
- )
3281
- ] })
3282
- ] }),
3283
- /* @__PURE__ */ jsxRuntime.jsx(SlideOver, { open: composing, onClose: () => setComposing(false), title: "New post", icon: lucideIcons2.Send, ariaLabel: "New post", children: /* @__PURE__ */ jsxRuntime.jsx(PostComposer, { channels: [...PROVIDERS], providers, onSubmit: submitDraft }) }),
3284
- /* @__PURE__ */ jsxRuntime.jsx(
3285
- SlideOver,
3286
- {
3287
- open: connecting,
3288
- onClose: () => setConnecting(false),
3289
- title: "Connect account",
3290
- icon: lucideIcons2.Link2,
3291
- ariaLabel: "Connect account",
3292
- children: /* @__PURE__ */ jsxRuntime.jsx(
3293
- ConnectAccount,
3294
- {
3295
- api,
3296
- providers,
3297
- onCreated: () => {
3298
- setConnecting(false);
3299
- void load();
3300
- }
3301
- }
3302
- )
3303
- }
3304
- ),
3305
- /* @__PURE__ */ jsxRuntime.jsx(SlideOver, { open: openPost !== null, onClose: () => setOpenPost(null), title: "Post", icon: lucideIcons2.Send, ariaLabel: "Post detail", children: openPost ? /* @__PURE__ */ jsxRuntime.jsx(
3306
- PostDetail,
3307
- {
3308
- api,
3309
- post: openPost,
3310
- onChanged: () => {
3311
- setOpenPost(null);
3312
- void load();
3313
- }
3314
- }
3315
- ) : null })
3316
- ] });
3317
- }
3318
- var META = {
3319
- x: { label: "X", bg: "#0f0f12", fg: "#e6e6ea", mark: "\u{1D54F}" },
3320
- facebook: { label: "Facebook", bg: "#1877f2", fg: "#ffffff", mark: "f" },
3321
- instagram: { label: "Instagram", bg: "#e1306c", fg: "#ffffff", mark: "IG" },
3322
- linkedin: { label: "LinkedIn", bg: "#0a66c2", fg: "#ffffff", mark: "in" },
3323
- tiktok: { label: "TikTok", bg: "#111114", fg: "#25f4ee", mark: "TT" },
3324
- youtube: { label: "YouTube", bg: "#ff0000", fg: "#ffffff", mark: "\u25B6" },
3325
- threads: { label: "Threads", bg: "#111114", fg: "#e6e6ea", mark: "@" }
3326
- };
3327
- function ChannelBadge({
3328
- channel,
3329
- showLabel = false,
3330
- size = 22
3331
- }) {
3332
- const m = META[channel] ?? META.x;
3333
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", gap: "$2", children: [
3334
- /* @__PURE__ */ jsxRuntime.jsx(
3335
- gui.YStack,
3336
- {
3337
- width: size,
3338
- height: size,
3339
- items: "center",
3340
- justify: "center",
3341
- rounded: "$2",
3342
- bg: m.bg,
3343
- children: /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", fontWeight: "800", color: m.fg, children: m.mark })
3344
- }
3345
- ),
3346
- showLabel ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$color12", children: m.label }) : null
3347
- ] });
3348
- }
3349
- var money = (cents) => `$${Math.round((cents || 0) / 100).toLocaleString()}`;
3350
- function CampaignCard({ campaign }) {
3351
- const pct = campaign.budget > 0 ? Math.min(100, campaign.spend / campaign.budget * 100) : 0;
3352
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.Card, { p: "$4", gap: "$3", borderWidth: 1, borderColor: "$borderColor", width: "100%", children: [
3353
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "flex-start", justify: "space-between", gap: "$2", children: [
3354
- /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$1", children: [
3355
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$4", fontWeight: "700", children: campaign.name }),
3356
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color11", children: campaign.channel })
3357
- ] }),
3358
- /* @__PURE__ */ jsxRuntime.jsx(StatusTag, { status: campaign.status })
3359
- ] }),
3360
- campaign.objective ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$2", color: "$color11", children: campaign.objective }) : null,
3361
- /* @__PURE__ */ jsxRuntime.jsxs(gui.YStack, { gap: "$1.5", children: [
3362
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { justify: "space-between", children: [
3363
- /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$1", color: "$color11", children: [
3364
- money(campaign.spend),
3365
- " spent"
3366
- ] }),
3367
- /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$1", color: "$color11", children: [
3368
- money(campaign.budget),
3369
- " budget"
3370
- ] })
3371
- ] }),
3372
- /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { height: 6, rounded: "$2", bg: "$color3", overflow: "hidden", children: /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, { height: 6, rounded: "$2", bg: "$color9", width: `${pct}%` }) })
3373
- ] })
3374
- ] });
3375
- }
3376
- function PostCard({
3377
- post,
3378
- onEdit,
3379
- onDelete
3380
- }) {
3381
- const mediaCount = post.media?.length ?? 0;
3382
- return /* @__PURE__ */ jsxRuntime.jsxs(gui.Card, { p: "$3", gap: "$2.5", borderWidth: 1, borderColor: "$borderColor", width: "100%", children: [
3383
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", justify: "space-between", gap: "$2", children: [
3384
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", gap: "$2", children: [
3385
- /* @__PURE__ */ jsxRuntime.jsx(ChannelBadge, { channel: post.channel }),
3386
- /* @__PURE__ */ jsxRuntime.jsx(StatusTag, { status: post.status })
3387
- ] }),
3388
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { gap: "$1", children: [
3389
- onEdit ? /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { size: "$2", chromeless: true, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Pencil, { size: 15 }), onPress: () => onEdit(post) }) : null,
3390
- onDelete ? /* @__PURE__ */ jsxRuntime.jsx(gui.Button, { size: "$2", chromeless: true, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideIcons2.Trash2, { size: 15 }), onPress: () => onDelete(post) }) : null
3391
- ] })
3392
- ] }),
3393
- /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$3", color: "$color12", children: post.content }),
3394
- /* @__PURE__ */ jsxRuntime.jsxs(gui.XStack, { items: "center", justify: "space-between", gap: "$2", children: [
3395
- post.scheduleAt ? /* @__PURE__ */ jsxRuntime.jsx(gui.Text, { fontSize: "$1", color: "$color11", children: formatPostTime(post.scheduleAt) }) : /* @__PURE__ */ jsxRuntime.jsx(gui.YStack, {}),
3396
- mediaCount ? /* @__PURE__ */ jsxRuntime.jsxs(gui.Text, { fontSize: "$1", color: "$color10", children: [
3397
- mediaCount,
3398
- " media"
3399
- ] }) : null
3400
- ] })
3401
- ] });
3402
- }
3403
-
3404
2185
  Object.defineProperty(exports, "AgnosticThemeToggle", {
3405
2186
  enumerable: true,
3406
2187
  get: function () { return chunkYBXVUV7P_cjs.AgnosticThemeToggle; }
@@ -3413,46 +2194,232 @@ Object.defineProperty(exports, "ThemeToggleNext", {
3413
2194
  enumerable: true,
3414
2195
  get: function () { return chunkYBXVUV7P_cjs.ThemeToggleNext; }
3415
2196
  });
2197
+ Object.defineProperty(exports, "ACCOUNT_STATUSES", {
2198
+ enumerable: true,
2199
+ get: function () { return chunkVGGGGXWS_cjs.ACCOUNT_STATUSES; }
2200
+ });
2201
+ Object.defineProperty(exports, "BackendStateCard", {
2202
+ enumerable: true,
2203
+ get: function () { return chunkVGGGGXWS_cjs.BackendStateCard; }
2204
+ });
2205
+ Object.defineProperty(exports, "COMPOSE_MODES", {
2206
+ enumerable: true,
2207
+ get: function () { return chunkVGGGGXWS_cjs.COMPOSE_MODES; }
2208
+ });
2209
+ Object.defineProperty(exports, "CampaignCard", {
2210
+ enumerable: true,
2211
+ get: function () { return chunkVGGGGXWS_cjs.CampaignCard; }
2212
+ });
2213
+ Object.defineProperty(exports, "ChannelBadge", {
2214
+ enumerable: true,
2215
+ get: function () { return chunkVGGGGXWS_cjs.ChannelBadge; }
2216
+ });
2217
+ Object.defineProperty(exports, "DataTable", {
2218
+ enumerable: true,
2219
+ get: function () { return chunkVGGGGXWS_cjs.DataTable; }
2220
+ });
2221
+ Object.defineProperty(exports, "EmptyState", {
2222
+ enumerable: true,
2223
+ get: function () { return chunkVGGGGXWS_cjs.EmptyState; }
2224
+ });
2225
+ Object.defineProperty(exports, "FieldRow", {
2226
+ enumerable: true,
2227
+ get: function () { return chunkVGGGGXWS_cjs.FieldRow; }
2228
+ });
2229
+ Object.defineProperty(exports, "FieldSelect", {
2230
+ enumerable: true,
2231
+ get: function () { return chunkVGGGGXWS_cjs.FieldSelect; }
2232
+ });
2233
+ Object.defineProperty(exports, "FieldSlider", {
2234
+ enumerable: true,
2235
+ get: function () { return chunkVGGGGXWS_cjs.FieldSlider; }
2236
+ });
2237
+ Object.defineProperty(exports, "FieldSwitch", {
2238
+ enumerable: true,
2239
+ get: function () { return chunkVGGGGXWS_cjs.FieldSwitch; }
2240
+ });
2241
+ Object.defineProperty(exports, "FieldText", {
2242
+ enumerable: true,
2243
+ get: function () { return chunkVGGGGXWS_cjs.FieldText; }
2244
+ });
2245
+ Object.defineProperty(exports, "FieldTextArea", {
2246
+ enumerable: true,
2247
+ get: function () { return chunkVGGGGXWS_cjs.FieldTextArea; }
2248
+ });
2249
+ Object.defineProperty(exports, "HostProvider", {
2250
+ enumerable: true,
2251
+ get: function () { return chunkVGGGGXWS_cjs.HostProvider; }
2252
+ });
2253
+ Object.defineProperty(exports, "POST_STATUSES", {
2254
+ enumerable: true,
2255
+ get: function () { return chunkVGGGGXWS_cjs.POST_STATUSES; }
2256
+ });
2257
+ Object.defineProperty(exports, "PROVIDERS", {
2258
+ enumerable: true,
2259
+ get: function () { return chunkVGGGGXWS_cjs.PROVIDERS; }
2260
+ });
2261
+ Object.defineProperty(exports, "PageHeader", {
2262
+ enumerable: true,
2263
+ get: function () { return chunkVGGGGXWS_cjs.PageHeader; }
2264
+ });
2265
+ Object.defineProperty(exports, "PostAgenda", {
2266
+ enumerable: true,
2267
+ get: function () { return chunkVGGGGXWS_cjs.PostAgenda; }
2268
+ });
2269
+ Object.defineProperty(exports, "PostCard", {
2270
+ enumerable: true,
2271
+ get: function () { return chunkVGGGGXWS_cjs.PostCard; }
2272
+ });
2273
+ Object.defineProperty(exports, "PostComposer", {
2274
+ enumerable: true,
2275
+ get: function () { return chunkVGGGGXWS_cjs.PostComposer; }
2276
+ });
2277
+ Object.defineProperty(exports, "PrimaryButton", {
2278
+ enumerable: true,
2279
+ get: function () { return chunkVGGGGXWS_cjs.PrimaryButton; }
2280
+ });
2281
+ Object.defineProperty(exports, "ProviderReadinessList", {
2282
+ enumerable: true,
2283
+ get: function () { return chunkVGGGGXWS_cjs.ProviderReadinessList; }
2284
+ });
2285
+ Object.defineProperty(exports, "SLIDEOVER_LG", {
2286
+ enumerable: true,
2287
+ get: function () { return chunkVGGGGXWS_cjs.LG; }
2288
+ });
2289
+ Object.defineProperty(exports, "SlideOver", {
2290
+ enumerable: true,
2291
+ get: function () { return chunkVGGGGXWS_cjs.SlideOver; }
2292
+ });
2293
+ Object.defineProperty(exports, "SocialResource", {
2294
+ enumerable: true,
2295
+ get: function () { return chunkVGGGGXWS_cjs.SocialResource; }
2296
+ });
2297
+ Object.defineProperty(exports, "SocialSummaryBar", {
2298
+ enumerable: true,
2299
+ get: function () { return chunkVGGGGXWS_cjs.SocialSummaryBar; }
2300
+ });
2301
+ Object.defineProperty(exports, "StatusTag", {
2302
+ enumerable: true,
2303
+ get: function () { return chunkVGGGGXWS_cjs.StatusTag; }
2304
+ });
2305
+ Object.defineProperty(exports, "ViewToggle", {
2306
+ enumerable: true,
2307
+ get: function () { return chunkVGGGGXWS_cjs.ViewToggle; }
2308
+ });
2309
+ Object.defineProperty(exports, "accentFor", {
2310
+ enumerable: true,
2311
+ get: function () { return chunkVGGGGXWS_cjs.accentFor; }
2312
+ });
2313
+ Object.defineProperty(exports, "asColor", {
2314
+ enumerable: true,
2315
+ get: function () { return chunkVGGGGXWS_cjs.asColor; }
2316
+ });
2317
+ Object.defineProperty(exports, "classifyBackend", {
2318
+ enumerable: true,
2319
+ get: function () { return chunkVGGGGXWS_cjs.classifyBackend; }
2320
+ });
2321
+ Object.defineProperty(exports, "classifyRead", {
2322
+ enumerable: true,
2323
+ get: function () { return chunkVGGGGXWS_cjs.classifyRead; }
2324
+ });
2325
+ Object.defineProperty(exports, "contrastText", {
2326
+ enumerable: true,
2327
+ get: function () { return chunkVGGGGXWS_cjs.contrastText; }
2328
+ });
2329
+ Object.defineProperty(exports, "createSocialApi", {
2330
+ enumerable: true,
2331
+ get: function () { return chunkVGGGGXWS_cjs.createSocialApi; }
2332
+ });
2333
+ Object.defineProperty(exports, "formatPostTime", {
2334
+ enumerable: true,
2335
+ get: function () { return chunkVGGGGXWS_cjs.formatPostTime; }
2336
+ });
2337
+ Object.defineProperty(exports, "isHexColor", {
2338
+ enumerable: true,
2339
+ get: function () { return chunkVGGGGXWS_cjs.isHexColor; }
2340
+ });
2341
+ Object.defineProperty(exports, "normalizeAccount", {
2342
+ enumerable: true,
2343
+ get: function () { return chunkVGGGGXWS_cjs.normalizeAccount; }
2344
+ });
2345
+ Object.defineProperty(exports, "normalizeAccounts", {
2346
+ enumerable: true,
2347
+ get: function () { return chunkVGGGGXWS_cjs.normalizeAccounts; }
2348
+ });
2349
+ Object.defineProperty(exports, "normalizePost", {
2350
+ enumerable: true,
2351
+ get: function () { return chunkVGGGGXWS_cjs.normalizePost; }
2352
+ });
2353
+ Object.defineProperty(exports, "normalizePosts", {
2354
+ enumerable: true,
2355
+ get: function () { return chunkVGGGGXWS_cjs.normalizePosts; }
2356
+ });
2357
+ Object.defineProperty(exports, "normalizeProviderCapability", {
2358
+ enumerable: true,
2359
+ get: function () { return chunkVGGGGXWS_cjs.normalizeProviderCapability; }
2360
+ });
2361
+ Object.defineProperty(exports, "normalizeProviders", {
2362
+ enumerable: true,
2363
+ get: function () { return chunkVGGGGXWS_cjs.normalizeProviders; }
2364
+ });
2365
+ Object.defineProperty(exports, "normalizeSummary", {
2366
+ enumerable: true,
2367
+ get: function () { return chunkVGGGGXWS_cjs.normalizeSummary; }
2368
+ });
2369
+ Object.defineProperty(exports, "parsePostTime", {
2370
+ enumerable: true,
2371
+ get: function () { return chunkVGGGGXWS_cjs.parsePostTime; }
2372
+ });
2373
+ Object.defineProperty(exports, "postDayBucket", {
2374
+ enumerable: true,
2375
+ get: function () { return chunkVGGGGXWS_cjs.postDayBucket; }
2376
+ });
2377
+ Object.defineProperty(exports, "postPreview", {
2378
+ enumerable: true,
2379
+ get: function () { return chunkVGGGGXWS_cjs.postPreview; }
2380
+ });
2381
+ Object.defineProperty(exports, "resolveAccent", {
2382
+ enumerable: true,
2383
+ get: function () { return chunkVGGGGXWS_cjs.resolveAccent; }
2384
+ });
2385
+ Object.defineProperty(exports, "setOrgAccent", {
2386
+ enumerable: true,
2387
+ get: function () { return chunkVGGGGXWS_cjs.setOrgAccent; }
2388
+ });
2389
+ Object.defineProperty(exports, "useAccent", {
2390
+ enumerable: true,
2391
+ get: function () { return chunkVGGGGXWS_cjs.useAccent; }
2392
+ });
2393
+ Object.defineProperty(exports, "useHost", {
2394
+ enumerable: true,
2395
+ get: function () { return chunkVGGGGXWS_cjs.useHost; }
2396
+ });
3416
2397
  Object.defineProperty(exports, "CustomModelMark", {
3417
2398
  enumerable: true,
3418
2399
  get: function () { return lucideIcons2.Boxes; }
3419
2400
  });
3420
- exports.ACCOUNT_STATUSES = ACCOUNT_STATUSES;
3421
2401
  exports.AnimatedLogo = AnimatedLogo;
3422
2402
  exports.AppHeader = AppHeader;
3423
2403
  exports.BRANDS = BRANDS;
3424
- exports.BackendStateCard = BackendStateCard;
3425
2404
  exports.BarChart = BarChart;
3426
2405
  exports.BarRows = BarRows;
3427
2406
  exports.BrandMark = BrandMark;
3428
2407
  exports.CHART_OTHER = CHART_OTHER;
3429
2408
  exports.CHART_PALETTE = CHART_PALETTE;
3430
- exports.COMPOSE_MODES = COMPOSE_MODES;
3431
- exports.CampaignCard = CampaignCard;
3432
- exports.ChannelBadge = ChannelBadge;
3433
2409
  exports.ComboBox = ComboBox;
3434
2410
  exports.CommerceResource = CommerceResource;
3435
2411
  exports.ConfirmDelete = ConfirmDelete;
3436
2412
  exports.ContextMenu = ContextMenu;
3437
- exports.DataTable = DataTable;
3438
2413
  exports.Donut = Donut;
3439
2414
  exports.DonutRing = Donut2;
3440
2415
  exports.DropdownMenu = DropdownMenu;
3441
- exports.EmptyState = EmptyState;
3442
2416
  exports.FadeIn = FadeIn;
3443
- exports.FieldRow = FieldRow;
3444
- exports.FieldSelect = FieldSelect;
3445
- exports.FieldSlider = FieldSlider;
3446
- exports.FieldSwitch = FieldSwitch;
3447
- exports.FieldText = FieldText;
3448
- exports.FieldTextArea = FieldTextArea;
3449
2417
  exports.FloatingMenu = FloatingMenu;
3450
2418
  exports.GenericLogo = GenericLogo;
3451
2419
  exports.HANZO = HANZO;
3452
2420
  exports.HANZO_MARK_CONTENT = HANZO_MARK_CONTENT;
3453
2421
  exports.HanzoMark = HanzoMark;
3454
2422
  exports.HintButton = HintButton;
3455
- exports.HostProvider = HostProvider;
3456
2423
  exports.LUX = LUX;
3457
2424
  exports.LegendDot = LegendDot;
3458
2425
  exports.LineChart = LineChart;
@@ -3466,71 +2433,35 @@ exports.MiniBars = MiniBars;
3466
2433
  exports.OrgMark = OrgMark;
3467
2434
  exports.OrgSwitcher = OrgSwitcher;
3468
2435
  exports.PARS = PARS;
3469
- exports.POST_STATUSES = POST_STATUSES;
3470
- exports.PROVIDERS = PROVIDERS;
3471
- exports.PageHeader = PageHeader;
3472
2436
  exports.Panel = Panel;
3473
2437
  exports.PortalTheme = PortalTheme;
3474
- exports.PostAgenda = PostAgenda;
3475
- exports.PostCard = PostCard;
3476
- exports.PostComposer = PostComposer;
3477
- exports.PrimaryButton = PrimaryButton;
3478
2438
  exports.ProductIcon = ProductIcon;
3479
2439
  exports.ProviderLogo = ProviderLogo;
3480
- exports.ProviderReadinessList = ProviderReadinessList;
3481
2440
  exports.Reorder = Reorder;
3482
2441
  exports.SERIES = SERIES;
3483
- exports.SLIDEOVER_LG = LG;
3484
2442
  exports.SURFACES = SURFACES;
3485
2443
  exports.SearchInput = SearchInput;
3486
2444
  exports.Segmented = Segmented;
3487
2445
  exports.SelectMenu = SelectMenu;
3488
2446
  exports.SiteFooter = SiteFooter;
3489
2447
  exports.SiteNav = SiteNav;
3490
- exports.SlideOver = SlideOver;
3491
- exports.SocialResource = SocialResource;
3492
- exports.SocialSummaryBar = SocialSummaryBar;
3493
2448
  exports.Sparkline = Sparkline;
3494
- exports.StatusTag = StatusTag;
3495
2449
  exports.ToastProvider = ToastProvider;
3496
2450
  exports.UtilBar = UtilBar;
3497
- exports.ViewToggle = ViewToggle;
3498
2451
  exports.ZOO = ZOO;
3499
- exports.accentFor = accentFor;
3500
- exports.asColor = asColor;
3501
- exports.classifyBackend = classifyBackend;
3502
- exports.classifyRead = classifyRead;
3503
2452
  exports.colorForIndex = colorForIndex;
3504
- exports.contrastText = contrastText;
3505
- exports.createSocialApi = createSocialApi;
3506
2453
  exports.filterOptions = filterOptions;
3507
2454
  exports.filterOrgs = filterOrgs;
3508
- exports.formatPostTime = formatPostTime;
3509
- exports.isHexColor = isHexColor;
3510
2455
  exports.isKnownOption = isKnownOption;
3511
2456
  exports.monogram = monogram;
3512
- exports.normalizeAccount = normalizeAccount;
3513
- exports.normalizeAccounts = normalizeAccounts;
3514
- exports.normalizePost = normalizePost;
3515
- exports.normalizePosts = normalizePosts;
3516
- exports.normalizeProviderCapability = normalizeProviderCapability;
3517
- exports.normalizeProviders = normalizeProviders;
3518
- exports.normalizeSummary = normalizeSummary;
3519
2457
  exports.orgScope = orgScope;
3520
2458
  exports.otherSurfaces = otherSurfaces;
3521
- exports.parsePostTime = parsePostTime;
3522
- exports.postDayBucket = postDayBucket;
3523
- exports.postPreview = postPreview;
3524
2459
  exports.providerInitials = providerInitials;
3525
2460
  exports.renderMenuItems = renderMenuItems;
3526
- exports.resolveAccent = resolveAccent;
3527
2461
  exports.resolveBrand = resolveBrand;
3528
2462
  exports.rowShift = rowShift;
3529
- exports.setOrgAccent = setOrgAccent;
3530
2463
  exports.targetIndex = targetIndex;
3531
- exports.useAccent = useAccent;
3532
2464
  exports.useContainerWidth = useContainerWidth;
3533
- exports.useHost = useHost;
3534
2465
  exports.useToast = useToast;
3535
2466
  exports.utilColor = utilColor;
3536
2467
  //# sourceMappingURL=index.cjs.map