@drawnagency/primitives 0.1.12 → 0.1.13

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.
Files changed (54) hide show
  1. package/dist/{chunk-Q7OKHD6I.js → chunk-46QI4FDZ.js} +1 -1
  2. package/dist/{chunk-PHCEJP7I.js → chunk-EAEX6DS7.js} +4 -1
  3. package/dist/{chunk-2YYC2VJY.js → chunk-P24YUT3O.js} +1 -1
  4. package/dist/components/editor/AudienceIndicator.d.ts +9 -0
  5. package/dist/components/editor/AudienceIndicator.d.ts.map +1 -0
  6. package/dist/components/editor/IndicatorPill.d.ts +18 -0
  7. package/dist/components/editor/IndicatorPill.d.ts.map +1 -0
  8. package/dist/components/editor/SectionWrapper.d.ts.map +1 -1
  9. package/dist/components/editor/StatusIndicator.d.ts +29 -0
  10. package/dist/components/editor/StatusIndicator.d.ts.map +1 -0
  11. package/dist/components/editor/index.d.ts +3 -2
  12. package/dist/components/editor/index.d.ts.map +1 -1
  13. package/dist/components/shared/Popover.d.ts +1 -1
  14. package/dist/components/shared/Popover.d.ts.map +1 -1
  15. package/dist/components/shell/BuildStatusIndicator.d.ts +9 -0
  16. package/dist/components/shell/BuildStatusIndicator.d.ts.map +1 -0
  17. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  18. package/dist/hooks/index.d.ts +1 -0
  19. package/dist/hooks/index.d.ts.map +1 -1
  20. package/dist/hooks/useBuildStatus.d.ts +11 -0
  21. package/dist/hooks/useBuildStatus.d.ts.map +1 -0
  22. package/dist/hooks/useEditorPublish.d.ts +2 -1
  23. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  24. package/dist/index.js +3 -3
  25. package/dist/lib/index.js +2 -2
  26. package/dist/schemas/index.js +2 -2
  27. package/dist/schemas/site-config.d.ts +6 -4
  28. package/dist/schemas/site-config.d.ts.map +1 -1
  29. package/package.json +1 -1
  30. package/src/components/editor/{AudiencePicker.tsx → AudienceIndicator.tsx} +25 -49
  31. package/src/components/editor/IndicatorPill.tsx +119 -0
  32. package/src/components/editor/SectionWrapper.tsx +18 -14
  33. package/src/components/editor/StatusIndicator.tsx +148 -0
  34. package/src/components/editor/index.ts +3 -2
  35. package/src/components/shared/Popover.tsx +26 -4
  36. package/src/components/shared/PopoverItem.tsx +1 -1
  37. package/src/components/shared/SplitButton.tsx +2 -2
  38. package/src/components/shell/BuildStatusIndicator.tsx +67 -0
  39. package/src/components/shell/EditorShell.tsx +23 -0
  40. package/src/hooks/index.ts +1 -0
  41. package/src/hooks/useBuildStatus.ts +139 -0
  42. package/src/hooks/useEditorPublish.ts +6 -2
  43. package/src/schemas/site-config.ts +5 -1
  44. package/dist/components/editor/AudiencePicker.d.ts +0 -9
  45. package/dist/components/editor/AudiencePicker.d.ts.map +0 -1
  46. package/dist/components/editor/StatusBadge.d.ts +0 -7
  47. package/dist/components/editor/StatusBadge.d.ts.map +0 -1
  48. package/dist/components/editor/StatusDots.d.ts +0 -25
  49. package/dist/components/editor/StatusDots.d.ts.map +0 -1
  50. package/dist/components/editor/StatusPicker.d.ts +0 -9
  51. package/dist/components/editor/StatusPicker.d.ts.map +0 -1
  52. package/src/components/editor/StatusBadge.tsx +0 -30
  53. package/src/components/editor/StatusDots.tsx +0 -131
  54. package/src/components/editor/StatusPicker.tsx +0 -86
@@ -2,7 +2,7 @@ import {
2
2
  IndexSchema,
3
3
  getAllSchemas,
4
4
  getSectionSchema
5
- } from "./chunk-PHCEJP7I.js";
5
+ } from "./chunk-EAEX6DS7.js";
6
6
  import {
7
7
  safeNextPath
8
8
  } from "./chunk-F3Z6RISI.js";
@@ -153,9 +153,12 @@ function getSectionSchema() {
153
153
 
154
154
  // src/schemas/site-config.ts
155
155
  import { z as z3 } from "zod";
156
+ var StatusSchema = z3.enum(["draft", "live", "archived", "published"]).transform(
157
+ (val) => val === "published" ? "live" : val
158
+ );
156
159
  var SectionMetaSchema = z3.object({
157
160
  type: z3.string(),
158
- status: z3.enum(["draft", "live", "archived"]),
161
+ status: StatusSchema,
159
162
  access: z3.array(z3.string())
160
163
  });
161
164
  var IndexSchema = z3.object({
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HexColorSchema
3
- } from "./chunk-PHCEJP7I.js";
3
+ } from "./chunk-EAEX6DS7.js";
4
4
 
5
5
  // src/schemas/audience.ts
6
6
  import { z } from "zod";
@@ -0,0 +1,9 @@
1
+ import type { Audience } from "../../auth/types";
2
+ interface AudienceIndicatorProps {
3
+ access: string[];
4
+ audiences: Audience[];
5
+ onChange: (access: string[]) => void;
6
+ }
7
+ export declare function AudienceIndicator({ access, audiences, onChange }: AudienceIndicatorProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=AudienceIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudienceIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/editor/AudienceIndicator.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,UAAU,sBAAsB;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,sBAAsB,2CAkExF"}
@@ -0,0 +1,18 @@
1
+ import { type ReactNode } from "react";
2
+ interface DotDef {
3
+ color?: string;
4
+ className?: string;
5
+ }
6
+ interface IndicatorPillProps {
7
+ dots: DotDef[];
8
+ label: string;
9
+ /** Shown on hover above the pill. Currently unused — kept for planned tooltip feature. */
10
+ hoverContent?: ReactNode;
11
+ clickContent?: ReactNode | ((onClose: () => void) => ReactNode);
12
+ className?: string;
13
+ buttonClassName?: string;
14
+ ariaLabel?: string;
15
+ }
16
+ export declare function IndicatorPill({ dots, label, hoverContent, clickContent, className, buttonClassName, ariaLabel, }: IndicatorPillProps): import("react/jsx-runtime").JSX.Element;
17
+ export {};
18
+ //# sourceMappingURL=IndicatorPill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IndicatorPill.d.ts","sourceRoot":"","sources":["../../../src/components/editor/IndicatorPill.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAItE,UAAU,MAAM;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,SAAS,CAAC,CAAC;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,SAAS,GACV,EAAE,kBAAkB,2CA0FpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"SectionWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/SectionWrapper.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,SAAS,EACT,MAAM,EACN,cAAc,EACd,cAAc,EACd,eAAe,EACf,SAAS,EACT,eAAe,EACf,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,QAAQ,GACT,EAAE,YAAY,kDA+Rd"}
1
+ {"version":3,"file":"SectionWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/SectionWrapper.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,SAAS,EACT,MAAM,EACN,cAAc,EACd,cAAc,EACd,eAAe,EACf,SAAS,EACT,eAAe,EACf,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,QAAQ,GACT,EAAE,YAAY,kDAqSd"}
@@ -0,0 +1,29 @@
1
+ type StatusColor = "draft" | "live" | "archived" | "modified";
2
+ type Status = "draft" | "live" | "archived";
3
+ interface DotDef {
4
+ color: StatusColor;
5
+ }
6
+ interface DeriveInput {
7
+ mainStatus: string | null;
8
+ savedStatus: string;
9
+ contentDiffers: boolean;
10
+ isLocalOnly: boolean;
11
+ }
12
+ interface DeriveResult {
13
+ dots: DotDef[];
14
+ unsaved: boolean;
15
+ description: string;
16
+ }
17
+ export declare function deriveStatusDisplay({ mainStatus, savedStatus, contentDiffers, isLocalOnly }: DeriveInput): DeriveResult;
18
+ interface StatusIndicatorProps {
19
+ mainStatus: string | null;
20
+ savedStatus: string;
21
+ contentDiffers: boolean;
22
+ isLocalOnly: boolean;
23
+ status: Status;
24
+ dirty?: boolean;
25
+ onChange: (status: Status) => void;
26
+ }
27
+ export declare function StatusIndicator({ mainStatus, savedStatus, contentDiffers, isLocalOnly, status, dirty, onChange, }: StatusIndicatorProps): import("react/jsx-runtime").JSX.Element;
28
+ export {};
29
+ //# sourceMappingURL=StatusIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/editor/StatusIndicator.tsx"],"names":[],"mappings":"AAKA,KAAK,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;AAC9D,KAAK,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;AAE5C,UAAU,MAAM;IACd,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,UAAU,WAAW;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAgBD,wBAAgB,mBAAmB,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,EAAE,WAAW,GAAG,YAAY,CAkCvH;AAYD,UAAU,oBAAoB;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,WAAW,EACX,cAAc,EACd,WAAW,EACX,MAAM,EACN,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,2CA4CtB"}
@@ -3,7 +3,8 @@ export { InsertButton } from "./InsertButton";
3
3
  export { DeleteButton } from "./DeleteButton";
4
4
  export { SettingsButton } from "./SettingsButton";
5
5
  export { SettingsForm } from "./SettingsForm";
6
- export { StatusBadge } from "./StatusBadge";
6
+ export { IndicatorPill } from "./IndicatorPill";
7
+ export { StatusIndicator, deriveStatusDisplay } from "./StatusIndicator";
8
+ export { AudienceIndicator } from "./AudienceIndicator";
7
9
  export { SectionWrapper } from "./SectionWrapper";
8
- export { StatusDots, deriveStatusDots } from "./StatusDots";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
@@ -4,7 +4,7 @@ interface PopoverProps {
4
4
  onClose: () => void;
5
5
  anchorRef: RefObject<HTMLElement | null>;
6
6
  children: ReactNode;
7
- align?: "start" | "end";
7
+ align?: "start" | "end" | "auto";
8
8
  className?: string;
9
9
  }
10
10
  export declare function Popover({ isOpen, onClose, anchorRef, children, align, className, }: PopoverProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/components/shared/Popover.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAI1E,UAAU,YAAY;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzC,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,OAAO,CAAC,EACtB,MAAM,EACN,OAAO,EACP,SAAS,EACT,QAAQ,EACR,KAAe,EACf,SAAS,GACV,EAAE,YAAY,kDAwCd"}
1
+ {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/components/shared/Popover.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIrG,UAAU,YAAY;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzC,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,OAAO,CAAC,EACtB,MAAM,EACN,OAAO,EACP,SAAS,EACT,QAAQ,EACR,KAAc,EACd,SAAS,GACV,EAAE,YAAY,kDA8Dd"}
@@ -0,0 +1,9 @@
1
+ interface BuildStatusIndicatorProps {
2
+ state: "idle" | "building" | "ready" | "error";
3
+ deployUrl: string | null;
4
+ visible: boolean;
5
+ onDismiss: () => void;
6
+ }
7
+ export declare function BuildStatusIndicator({ state, deployUrl, visible, onDismiss, }: BuildStatusIndicatorProps): import("react/jsx-runtime").JSX.Element | null;
8
+ export {};
9
+ //# sourceMappingURL=BuildStatusIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BuildStatusIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/shell/BuildStatusIndicator.tsx"],"names":[],"mappings":"AAGA,UAAU,yBAAyB;IACjC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;IAC/C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAoBD,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,SAAS,EACT,OAAO,EACP,SAAS,GACV,EAAE,yBAAyB,kDAiC3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAYjD,OAAO,sBAAsB,CAAC;AAiC9B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAcxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,GACZ,EAAE,KAAK,2CAkkBP"}
1
+ {"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAYjD,OAAO,sBAAsB,CAAC;AAmC9B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAcxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,GACZ,EAAE,KAAK,2CAykBP"}
@@ -1,4 +1,5 @@
1
1
  export { useActiveHeadings } from "./useActiveHeadings";
2
+ export { useBuildStatus } from "./useBuildStatus";
2
3
  export { useContentLifecycle } from "./useContentLifecycle";
3
4
  export { useEditorPersistence } from "./useEditorPersistence";
4
5
  export { useEditorPublish } from "./useEditorPublish";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,11 @@
1
+ type BuildState = "idle" | "building" | "ready" | "error";
2
+ interface BuildStatusResult {
3
+ state: BuildState;
4
+ deployUrl: string | null;
5
+ visible: boolean;
6
+ dismiss: () => void;
7
+ startTracking: () => void;
8
+ }
9
+ export declare function useBuildStatus(): BuildStatusResult;
10
+ export {};
11
+ //# sourceMappingURL=useBuildStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBuildStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/useBuildStatus.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;AAS1D,UAAU,iBAAiB;IACzB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAKD,wBAAgB,cAAc,IAAI,iBAAiB,CAoHlD"}
@@ -16,8 +16,9 @@ interface PublishDeps {
16
16
  pendingMediaDeletions: string[];
17
17
  onMediaPublished: (publishedItems: MediaItem[], publishedDeletions: string[]) => void;
18
18
  onShasUpdated: (savedSha: string | null, mainSha: string | null) => void;
19
+ onPublishComplete?: () => void;
19
20
  }
20
- export declare function useEditorPublish({ flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, sections, deletedSectionIds, onSuccess, mediaManifest, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, }: PublishDeps): {
21
+ export declare function useEditorPublish({ flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, sections, deletedSectionIds, onSuccess, mediaManifest, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, onPublishComplete, }: PublishDeps): {
21
22
  isPublishing: boolean;
22
23
  publishFeedback: string | null;
23
24
  handleSave: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"useEditorPublish.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPublish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAe/D,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC1E;AASD,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,GACd,EAAE,WAAW;;;;;;EAqSb"}
1
+ {"version":3,"file":"useEditorPublish.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPublish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAe/D,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAChC;AASD,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,EAAE,WAAW;;;;;;EAuSb"}
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  SessionSchema,
8
8
  SiteUserSchema,
9
9
  slugifyAudienceName
10
- } from "./chunk-2YYC2VJY.js";
10
+ } from "./chunk-P24YUT3O.js";
11
11
  import {
12
12
  buildGoogleFontsUrl,
13
13
  cn,
@@ -27,7 +27,7 @@ import {
27
27
  safeRedirect,
28
28
  sanitizeHtml,
29
29
  toSectionId
30
- } from "./chunk-Q7OKHD6I.js";
30
+ } from "./chunk-46QI4FDZ.js";
31
31
  import {
32
32
  ColorItemSchema,
33
33
  ColorSpaceSchema,
@@ -48,7 +48,7 @@ import {
48
48
  getSectionSchema,
49
49
  registerSchema,
50
50
  registerSection
51
- } from "./chunk-PHCEJP7I.js";
51
+ } from "./chunk-EAEX6DS7.js";
52
52
  import {
53
53
  AUDIENCE_COOKIE,
54
54
  LastOwnerError,
package/dist/lib/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  safeRedirect,
18
18
  sanitizeHtml,
19
19
  toSectionId
20
- } from "../chunk-Q7OKHD6I.js";
20
+ } from "../chunk-46QI4FDZ.js";
21
21
  import {
22
22
  clearRegistry,
23
23
  createRegistry,
@@ -28,7 +28,7 @@ import {
28
28
  getSection,
29
29
  registerSchema,
30
30
  registerSection
31
- } from "../chunk-PHCEJP7I.js";
31
+ } from "../chunk-EAEX6DS7.js";
32
32
  import "../chunk-F3Z6RISI.js";
33
33
  import "../chunk-UMSFICAC.js";
34
34
  export {
@@ -7,7 +7,7 @@ import {
7
7
  SessionSchema,
8
8
  SiteUserSchema,
9
9
  slugifyAudienceName
10
- } from "../chunk-2YYC2VJY.js";
10
+ } from "../chunk-P24YUT3O.js";
11
11
  import {
12
12
  ColorItemSchema,
13
13
  ColorSpaceSchema,
@@ -19,7 +19,7 @@ import {
19
19
  TextLineSchema,
20
20
  getSectionContentSchema,
21
21
  getSectionSchema
22
- } from "../chunk-PHCEJP7I.js";
22
+ } from "../chunk-EAEX6DS7.js";
23
23
  import {
24
24
  ImageManifestSchema,
25
25
  MediaConfigSchema,
@@ -1,11 +1,12 @@
1
1
  import { z } from "zod";
2
2
  export declare const SectionMetaSchema: z.ZodObject<{
3
3
  type: z.ZodString;
4
- status: z.ZodEnum<{
4
+ status: z.ZodPipe<z.ZodEnum<{
5
5
  draft: "draft";
6
6
  live: "live";
7
7
  archived: "archived";
8
- }>;
8
+ published: "published";
9
+ }>, z.ZodTransform<"draft" | "live" | "archived", "draft" | "live" | "archived" | "published">>;
9
10
  access: z.ZodArray<z.ZodString>;
10
11
  }, z.core.$strip>;
11
12
  export type SectionMeta = z.infer<typeof SectionMetaSchema>;
@@ -14,11 +15,12 @@ export declare const IndexSchema: z.ZodObject<{
14
15
  order: z.ZodArray<z.ZodString>;
15
16
  sections: z.ZodRecord<z.ZodString, z.ZodObject<{
16
17
  type: z.ZodString;
17
- status: z.ZodEnum<{
18
+ status: z.ZodPipe<z.ZodEnum<{
18
19
  draft: "draft";
19
20
  live: "live";
20
21
  archived: "archived";
21
- }>;
22
+ published: "published";
23
+ }>, z.ZodTransform<"draft" | "live" | "archived", "draft" | "live" | "archived" | "published">>;
22
24
  access: z.ZodArray<z.ZodString>;
23
25
  }, z.core.$strip>>;
24
26
  }, z.core.$strip>;
@@ -1 +1 @@
1
- {"version":3,"file":"site-config.d.ts","sourceRoot":"","sources":["../../src/schemas/site-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,iBAAiB;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,WAAW;;;;;;;;;;;;iBAOvB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEpD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;iBAY3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"site-config.d.ts","sourceRoot":"","sources":["../../src/schemas/site-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,eAAO,MAAM,iBAAiB;;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,WAAW;;;;;;;;;;;;;iBAOvB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEpD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;iBAY3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawnagency/primitives",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./package.json": "./package.json",
@@ -1,22 +1,18 @@
1
- import { useRef, useState } from "react";
2
1
  import { Check } from "lucide-react";
3
2
  import { cn } from "../../lib/cn";
4
- import { Popover } from "../shared/Popover";
3
+ import { IndicatorPill } from "./IndicatorPill";
5
4
  import { PopoverItem } from "../shared/PopoverItem";
6
5
  import type { Audience } from "../../auth/types";
7
6
 
8
- interface Props {
7
+ interface AudienceIndicatorProps {
9
8
  access: string[];
10
9
  audiences: Audience[];
11
10
  onChange: (access: string[]) => void;
12
11
  }
13
12
 
14
- export function AudiencePicker({ access, audiences, onChange }: Props) {
15
- const [open, setOpen] = useState(false);
16
- const buttonRef = useRef<HTMLButtonElement>(null);
17
-
13
+ export function AudienceIndicator({ access, audiences, onChange }: AudienceIndicatorProps) {
18
14
  const selected = audiences.filter((a) => access.includes(a.name));
19
- const visibleCircles = selected.slice(0, 3);
15
+ const visibleDots = selected.slice(0, 3);
20
16
 
21
17
  function toggle(name: string) {
22
18
  const next = access.includes(name)
@@ -25,47 +21,27 @@ export function AudiencePicker({ access, audiences, onChange }: Props) {
25
21
  onChange(next);
26
22
  }
27
23
 
28
- return (
29
- <div className="relative">
30
- <button
31
- ref={buttonRef}
32
- type="button"
33
- onClick={() => setOpen((v) => !v)}
34
- className={cn(
35
- "cursor-pointer inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium",
36
- "border border-base-200 hover:bg-base-accent",
37
- selected.length === 0 && "text-base-contrast-light",
38
- )}
39
- >
40
- {selected.length === 0 && <span>No audience</span>}
41
- {selected.length >= 1 && (
42
- <span className="flex -space-x-1.5">
43
- {visibleCircles.map((a) => (
44
- <span
45
- key={a.name}
46
- className="h-3 w-3 rounded-full border border-base"
47
- style={{ backgroundColor: a.color ?? "#9ca3af" }}
48
- />
49
- ))}
50
- </span>
51
- )}
52
- {selected.length === 1 && <span>{selected[0].displayName}</span>}
53
- {selected.length >= 2 && <span>{selected.length} audiences</span>}
54
- </button>
24
+ const pillDots = visibleDots.map((a) => ({
25
+ color: a.color ?? "#9ca3af",
26
+ }));
55
27
 
56
- <Popover
57
- isOpen={open}
58
- onClose={() => setOpen(false)}
59
- anchorRef={buttonRef}
60
- align="end"
61
- className="w-56"
62
- >
63
- {audiences.length === 0 ? (
64
- <div className="px-3 py-2 text-xs text-base-contrast-light">
28
+ let labelText: string;
29
+ if (selected.length === 0) labelText = "No audience";
30
+ else if (selected.length === 1) labelText = selected[0].displayName;
31
+ else labelText = `${selected.length} audiences`;
32
+
33
+ return (
34
+ <IndicatorPill
35
+ dots={pillDots}
36
+ label={labelText}
37
+ buttonClassName={selected.length === 0 ? "text-base-contrast-light" : undefined}
38
+ clickContent={
39
+ audiences.length === 0 ? (
40
+ <div className="px-3 py-2 text-xs text-base-contrast-light whitespace-nowrap">
65
41
  No audiences configured. Add audiences in Site Settings → Viewer Access.
66
42
  </div>
67
43
  ) : (
68
- <ul role="list" className="py-1">
44
+ <ul role="list" className="w-full overflow-hidden py-1">
69
45
  {audiences.map((a) => {
70
46
  const checked = access.includes(a.name);
71
47
  return (
@@ -90,14 +66,14 @@ export function AudiencePicker({ access, audiences, onChange }: Props) {
90
66
  className="h-3 w-3 shrink-0 rounded-full border border-base-200"
91
67
  style={{ backgroundColor: a.color ?? "#9ca3af" }}
92
68
  />
93
- <span className="text-sm font-medium text-base-contrast">{a.displayName}</span>
69
+ <span className="font-medium text-base-contrast">{a.displayName}</span>
94
70
  </PopoverItem>
95
71
  </li>
96
72
  );
97
73
  })}
98
74
  </ul>
99
- )}
100
- </Popover>
101
- </div>
75
+ )
76
+ }
77
+ />
102
78
  );
103
79
  }
@@ -0,0 +1,119 @@
1
+ import { useRef, useState, useCallback, type ReactNode } from "react";
2
+ import { cn } from "../../lib/cn";
3
+ import { Popover } from "../shared/Popover";
4
+
5
+ interface DotDef {
6
+ color?: string;
7
+ className?: string;
8
+ }
9
+
10
+ interface IndicatorPillProps {
11
+ dots: DotDef[];
12
+ label: string;
13
+ /** Shown on hover above the pill. Currently unused — kept for planned tooltip feature. */
14
+ hoverContent?: ReactNode;
15
+ clickContent?: ReactNode | ((onClose: () => void) => ReactNode);
16
+ className?: string;
17
+ buttonClassName?: string;
18
+ ariaLabel?: string;
19
+ }
20
+
21
+ export function IndicatorPill({
22
+ dots,
23
+ label,
24
+ hoverContent,
25
+ clickContent,
26
+ className,
27
+ buttonClassName,
28
+ ariaLabel,
29
+ }: IndicatorPillProps) {
30
+ const [hoverOpen, setHoverOpen] = useState(false);
31
+ const [clickOpen, setClickOpen] = useState(false);
32
+ const buttonRef = useRef<HTMLButtonElement>(null);
33
+ const hoverTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
34
+
35
+ const clearHoverTimeout = useCallback(() => {
36
+ if (hoverTimeout.current) {
37
+ clearTimeout(hoverTimeout.current);
38
+ hoverTimeout.current = null;
39
+ }
40
+ }, []);
41
+
42
+ function handleMouseEnter() {
43
+ clearHoverTimeout();
44
+ if (!clickOpen && hoverContent) {
45
+ setHoverOpen(true);
46
+ }
47
+ }
48
+
49
+ function handleMouseLeave() {
50
+ clearHoverTimeout();
51
+ hoverTimeout.current = setTimeout(() => {
52
+ setHoverOpen(false);
53
+ }, 150);
54
+ }
55
+
56
+ function handleClick() {
57
+ if (!clickContent) return;
58
+ setHoverOpen(false);
59
+ clearHoverTimeout();
60
+ setClickOpen((v) => !v);
61
+ }
62
+
63
+ function handleClickClose() {
64
+ setClickOpen(false);
65
+ }
66
+
67
+ return (
68
+ <div className={cn("relative", className)}>
69
+ <button
70
+ ref={buttonRef}
71
+ type="button"
72
+ onClick={handleClick}
73
+ onMouseEnter={handleMouseEnter}
74
+ onMouseLeave={handleMouseLeave}
75
+ aria-haspopup={clickContent ? "true" : undefined}
76
+ aria-expanded={clickContent ? clickOpen : undefined}
77
+ aria-label={ariaLabel}
78
+ className={cn(
79
+ "cursor-pointer inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium",
80
+ "border border-base-200 hover:bg-base-accent",
81
+ buttonClassName,
82
+ )}
83
+ >
84
+ {dots.length > 0 && (
85
+ <span className="flex -space-x-1">
86
+ {dots.map((dot, i) => (
87
+ <span
88
+ key={i}
89
+ aria-hidden="true"
90
+ className={cn("h-3 w-3 rounded-full border border-base", dot.className)}
91
+ style={dot.color ? { backgroundColor: dot.color } : undefined}
92
+ />
93
+ ))}
94
+ </span>
95
+ )}
96
+ <span>{label}</span>
97
+ </button>
98
+
99
+ {/* Hover tooltip — above the button */}
100
+ {hoverOpen && hoverContent && (
101
+ <div
102
+ className="absolute bottom-full right-0 z-50 mb-1 rounded-full bg-base-accent px-3 py-1 text-xs text-base-contrast-light whitespace-nowrap"
103
+ >
104
+ {hoverContent}
105
+ </div>
106
+ )}
107
+
108
+ {/* Click dropdown — below the button */}
109
+ <Popover
110
+ isOpen={clickOpen}
111
+ onClose={handleClickClose}
112
+ anchorRef={buttonRef}
113
+ className="min-w-full max-w-xs"
114
+ >
115
+ {typeof clickContent === "function" ? clickContent(handleClickClose) : clickContent}
116
+ </Popover>
117
+ </div>
118
+ );
119
+ }
@@ -4,10 +4,8 @@ import { DragHandle } from "./DragHandle";
4
4
  import { InsertButton } from "./InsertButton";
5
5
  import { DeleteButton } from "./DeleteButton";
6
6
  import { SettingsButton } from "./SettingsButton";
7
- import { StatusBadge } from "./StatusBadge";
8
- import { StatusPicker } from "./StatusPicker";
9
- import { AudiencePicker } from "./AudiencePicker";
10
- import { StatusDots } from "./StatusDots";
7
+ import { StatusIndicator } from "./StatusIndicator";
8
+ import { AudienceIndicator } from "./AudienceIndicator";
11
9
  import { SettingsForm } from "./SettingsForm";
12
10
  import { useEditorContext } from "../shell/EditorContext";
13
11
  import { useEditorModal } from "../shell/EditorModalContext";
@@ -218,7 +216,17 @@ export function SectionWrapper({
218
216
  data-section-type={sectionType}
219
217
  >
220
218
  <div className="pointer-events-none absolute right-0 bottom-full z-30 mb-1">
221
- <StatusBadge status={status} dirty={dirty} />
219
+ <span
220
+ className={cn(
221
+ "rounded-full px-2 py-0.5 text-xs font-medium",
222
+ status === "live" ? "bg-status-live-bg text-status-live-text"
223
+ : status === "draft" ? "bg-status-draft-bg text-status-draft-text"
224
+ : "bg-status-archived-bg text-status-archived-text",
225
+ )}
226
+ >
227
+ {status}
228
+ {dirty && <span className="ml-1 opacity-70">· Unsaved</span>}
229
+ </span>
222
230
  </div>
223
231
  {children}
224
232
  </div>
@@ -279,27 +287,23 @@ export function SectionWrapper({
279
287
  )}
280
288
  >
281
289
  <div className="pointer-events-auto">
282
- <StatusDots
290
+ <StatusIndicator
283
291
  mainStatus={mainStatus ?? null}
284
292
  savedStatus={status as string}
285
293
  contentDiffers={contentDiffersFromMain ?? false}
286
294
  isLocalOnly={isLocalOnly ?? false}
295
+ status={status as "draft" | "live" | "archived"}
296
+ dirty={dirty}
297
+ onChange={(s) => onStatusChange?.(s)}
287
298
  />
288
299
  </div>
289
300
  <div className="pointer-events-auto">
290
- <AudiencePicker
301
+ <AudienceIndicator
291
302
  access={access}
292
303
  audiences={audiences}
293
304
  onChange={(newAccess) => onAccessChange?.(newAccess)}
294
305
  />
295
306
  </div>
296
- <div className="pointer-events-auto">
297
- <StatusPicker
298
- status={status as "draft" | "live" | "archived"}
299
- dirty={dirty}
300
- onChange={(s) => onStatusChange?.(s)}
301
- />
302
- </div>
303
307
 
304
308
  {hasSettings && (
305
309
  <SettingsButton onClick={handleSettingsClick} />