@drawnagency/primitives 0.1.84 → 0.1.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-665DW3HR.js → chunk-6VOIZP2O.js} +3 -3
- package/dist/{chunk-YKOLOZB2.js → chunk-DRCPDOW3.js} +14 -0
- package/dist/{chunk-MBJUWOM2.js → chunk-EO7K45GV.js} +1 -1
- package/dist/{chunk-DKXISNJ2.js → chunk-NEDOJHHR.js} +2 -2
- package/dist/{chunk-DO3ZENLN.js → chunk-OEL57NYV.js} +1 -1
- package/dist/{chunk-FDBZZ4AT.js → chunk-PTVY3Q7P.js} +1 -1
- package/dist/{chunk-56J4QMF4.js → chunk-VY5V4HBV.js} +7 -7
- package/dist/{chunk-EP3LVOXZ.js → chunk-WA3HFN54.js} +1 -1
- package/dist/{chunk-Q6LZOH5M.js → chunk-XDG2K6UT.js} +2 -2
- package/dist/{chunk-E3MTIMOG.js → chunk-XPUBUR64.js} +10 -0
- package/dist/collab/rebase.d.ts +23 -0
- package/dist/collab/rebase.d.ts.map +1 -1
- package/dist/collab/rebase.js +12 -1
- package/dist/components/editor/index.js +7 -7
- package/dist/components/primitives/index.js +5 -5
- package/dist/components/sections/brand-guide.js +5 -5
- package/dist/components/sections/register-schemas.js +8 -8
- package/dist/components/sections/register.js +8 -8
- package/dist/components/shared/Navigation.d.ts +6 -1
- package/dist/components/shared/Navigation.d.ts.map +1 -1
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/components/shell/{ChatbotConfigModal.d.ts → SiteSettingsChatbot.d.ts} +2 -4
- package/dist/components/shell/SiteSettingsChatbot.d.ts.map +1 -0
- package/dist/components/shell/SiteSettingsDisplay.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsModal.d.ts +3 -1
- package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
- package/dist/hooks/useMediaPipeline.d.ts +2 -1
- package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/lib/image-refs.d.ts +9 -0
- package/dist/lib/image-refs.d.ts.map +1 -1
- package/dist/lib/index.js +2 -2
- package/dist/media/index.js +4 -2
- package/dist/media/resolve.d.ts +25 -0
- package/dist/media/resolve.d.ts.map +1 -1
- package/dist/schemas/index.js +2 -2
- package/dist/schemas/site-config.d.ts +10 -0
- package/dist/schemas/site-config.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/collab/rebase.ts +33 -0
- package/src/components/editor/ChildBlockWrapper.tsx +1 -1
- package/src/components/editor/PagesModal.tsx +39 -31
- package/src/components/editor/SectionWrapper.tsx +3 -3
- package/src/components/shared/Navigation.tsx +20 -2
- package/src/components/shared/Tabs.tsx +1 -1
- package/src/components/shell/EditorShell.tsx +29 -76
- package/src/components/shell/SiteSettingsChatbot.tsx +188 -0
- package/src/components/shell/SiteSettingsDisplay.tsx +106 -0
- package/src/components/shell/SiteSettingsModal.tsx +29 -11
- package/src/hooks/useMediaPipeline.ts +16 -3
- package/src/lib/image-refs.ts +19 -0
- package/src/media/resolve.ts +34 -0
- package/src/schemas/site-config.ts +13 -0
- package/dist/components/shell/ChatbotConfigModal.d.ts.map +0 -1
- package/src/components/shell/ChatbotConfigModal.tsx +0 -193
package/dist/media/index.js
CHANGED
|
@@ -12,11 +12,12 @@ import {
|
|
|
12
12
|
hashFileBuffer,
|
|
13
13
|
mimeToExt,
|
|
14
14
|
rebindImageRef,
|
|
15
|
+
resolveLogo,
|
|
15
16
|
resolveManifestReferences,
|
|
16
17
|
resolveMedia,
|
|
17
18
|
sanitizeMediaName,
|
|
18
19
|
setMediaProvider
|
|
19
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-DRCPDOW3.js";
|
|
20
21
|
import "../chunk-YBVK254P.js";
|
|
21
22
|
import {
|
|
22
23
|
ImageManifestSchema,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
MediaFolderSchema,
|
|
25
26
|
MediaItemSchema,
|
|
26
27
|
VariantSchema
|
|
27
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-XPUBUR64.js";
|
|
28
29
|
import "../chunk-FM4M4Q2W.js";
|
|
29
30
|
import "../chunk-JSBRDJBE.js";
|
|
30
31
|
export {
|
|
@@ -46,6 +47,7 @@ export {
|
|
|
46
47
|
hashFileBuffer,
|
|
47
48
|
mimeToExt,
|
|
48
49
|
rebindImageRef,
|
|
50
|
+
resolveLogo,
|
|
49
51
|
resolveManifestReferences,
|
|
50
52
|
resolveMedia,
|
|
51
53
|
sanitizeMediaName,
|
package/dist/media/resolve.d.ts
CHANGED
|
@@ -26,4 +26,29 @@ export declare const BAKED_MEDIA_KEYS: readonly ["src", "srcset", "alt", "width"
|
|
|
26
26
|
export declare function rebindImageRef<T extends {
|
|
27
27
|
imageId?: string;
|
|
28
28
|
}>(ref: T, imageId: string): T;
|
|
29
|
+
export interface ResolvedLogo {
|
|
30
|
+
lightUrl: string;
|
|
31
|
+
darkUrl: string | null;
|
|
32
|
+
invertInDark: boolean;
|
|
33
|
+
showInNav: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolves a SiteConfig["logo"] entry into concrete URLs. Returns null when
|
|
37
|
+
* there is no logo configured, when the light variant's imageId can't be
|
|
38
|
+
* resolved against the manifest, or when the light variant resolves to a
|
|
39
|
+
* video (an `<img>` can't render mp4/webm) — callers should fall back to
|
|
40
|
+
* rendering the site name as text rather than a broken image. Still-image and
|
|
41
|
+
* animated (gif) picks are both fine — only a video pick is rejected, since
|
|
42
|
+
* both those tags resolve to `tag: "img"`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveLogo(logo: {
|
|
45
|
+
light: {
|
|
46
|
+
imageId: string;
|
|
47
|
+
};
|
|
48
|
+
dark: {
|
|
49
|
+
imageId: string;
|
|
50
|
+
} | null;
|
|
51
|
+
invertInDark: boolean;
|
|
52
|
+
showInNav: boolean;
|
|
53
|
+
} | null, manifest: MediaManifest, provider: MediaProvider): ResolvedLogo | null;
|
|
29
54
|
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/media/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wBAAgB,YAAY,CAC1B,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,EACxC,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,EAAE,aAAa,GACtB,aAAa,GAAG,IAAI,CAKtB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,EAAE,aAAa,GACtB,OAAO,CA0CT;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,gEAAiE,CAAC;AAE/F;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAIzF"}
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/media/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wBAAgB,YAAY,CAC1B,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,EACxC,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,EAAE,aAAa,GACtB,aAAa,GAAG,IAAI,CAKtB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,EAAE,aAAa,GACtB,OAAO,CA0CT;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,gEAAiE,CAAC;AAE/F;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAIzF;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE;IAAE,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,EACxH,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,aAAa,GACtB,YAAY,GAAG,IAAI,CAYrB"}
|
package/dist/schemas/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
AudienceNameSchema,
|
|
4
4
|
MediaGridOptionsSchema,
|
|
5
5
|
slugifyAudienceName
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-WA3HFN54.js";
|
|
7
7
|
import {
|
|
8
8
|
AudienceSchema,
|
|
9
9
|
RoleSchema,
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
TextLineSchema,
|
|
41
41
|
VariantSchema,
|
|
42
42
|
normalizeSiteIndex
|
|
43
|
-
} from "../chunk-
|
|
43
|
+
} from "../chunk-XPUBUR64.js";
|
|
44
44
|
import "../chunk-VKAGMEKE.js";
|
|
45
45
|
import "../chunk-FM4M4Q2W.js";
|
|
46
46
|
import "../chunk-NSCT3AMV.js";
|
|
@@ -456,6 +456,16 @@ export declare const SiteConfigSchema: z.ZodObject<{
|
|
|
456
456
|
uppercaseNavHeadings: z.ZodDefault<z.ZodBoolean>;
|
|
457
457
|
googleFontsUrl: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
458
458
|
favicon: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
459
|
+
logo: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
460
|
+
light: z.ZodObject<{
|
|
461
|
+
imageId: z.ZodString;
|
|
462
|
+
}, z.core.$strip>;
|
|
463
|
+
dark: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
464
|
+
imageId: z.ZodString;
|
|
465
|
+
}, z.core.$strip>>>;
|
|
466
|
+
invertInDark: z.ZodDefault<z.ZodBoolean>;
|
|
467
|
+
showInNav: z.ZodDefault<z.ZodBoolean>;
|
|
468
|
+
}, z.core.$strip>>>;
|
|
459
469
|
media: z.ZodDefault<z.ZodObject<{
|
|
460
470
|
sizes: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
|
|
461
471
|
maxFileSize: z.ZodDefault<z.ZodNumber>;
|
|
@@ -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;AAaxB,eAAO,MAAM,iBAAiB;;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAQ5D,eAAO,MAAM,cAAc,8EAA+E,CAAC;AAW3G,eAAO,MAAM,gBAAgB;;;EAA+B,CAAC;AAE7D,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AA0C9C,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6CtB,CAAC;AAEL,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAyE,CAAC;AAElG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE7D,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAE1D;AAMD,eAAO,MAAM,iBAAiB;;;;;iBAM5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,mBAAmB;;;;;;;;;;;iBAwB5B,CAAC;AACL,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,gBAAgB
|
|
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;AAaxB,eAAO,MAAM,iBAAiB;;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAQ5D,eAAO,MAAM,cAAc,8EAA+E,CAAC;AAW3G,eAAO,MAAM,gBAAgB;;;EAA+B,CAAC;AAE7D,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AA0C9C,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6CtB,CAAC;AAEL,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAyE,CAAC;AAElG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE7D,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAE1D;AAMD,eAAO,MAAM,iBAAiB;;;;;iBAM5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,mBAAmB;;;;;;;;;;;iBAwB5B,CAAC;AACL,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyC3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
|
package/package.json
CHANGED
package/src/collab/rebase.ts
CHANGED
|
@@ -46,6 +46,39 @@ export interface RebaseResult {
|
|
|
46
46
|
* structure in both branches), and the result partitions: every section in
|
|
47
47
|
* `sections` is reachable from `index`; a dirty section deleted remotely is
|
|
48
48
|
* kept, re-linked into the index, and reported in `conflictIds`. */
|
|
49
|
+
/** Fold a peer's live (pre-save) index broadcast under our current index — the
|
|
50
|
+
* live-collab `onRemoteIndexUpdate` path, applied ONLY when we hold no unsaved
|
|
51
|
+
* structural work (so our index equals the last-saved branch: every id in it is
|
|
52
|
+
* a real, branch-backed section).
|
|
53
|
+
*
|
|
54
|
+
* Keep every peer entry whose id our current index already knows; withhold the
|
|
55
|
+
* rest, which is one of:
|
|
56
|
+
* (a) the peer's unsaved ADD — its section file is not on the branch yet, so
|
|
57
|
+
* letting it into our index would poison our next save with a dangling
|
|
58
|
+
* ref the server rejects (its live appearance is deferred to the peer's
|
|
59
|
+
* save event, which arrives via the saved-event sync); or
|
|
60
|
+
* (b) a section WE deleted unsaved — absent from our index; our deletion
|
|
61
|
+
* stands until save-time arbitration.
|
|
62
|
+
*
|
|
63
|
+
* The keep-set is our INDEX's section ids, NOT the section bodies we managed to
|
|
64
|
+
* load. A live, branch-backed section whose body was skipped by the client
|
|
65
|
+
* loader (schema/registry miss, missing file, depth trip) is still in our index
|
|
66
|
+
* and MUST survive — otherwise our next save posts an index missing it and the
|
|
67
|
+
* server rejects with "section … not found in site index" (or the write drops
|
|
68
|
+
* the live section). Taking the whole `localIndex` here, rather than a
|
|
69
|
+
* caller-computed id set, is deliberate: it makes passing the loaded-bodies set
|
|
70
|
+
* (the original bug) unrepresentable. Neither input is mutated. */
|
|
71
|
+
export function reconcileRemoteIndex(remoteIndex: SiteIndex, localIndex: SiteIndex): SiteIndex {
|
|
72
|
+
const knownIds = new Set(Object.keys(localIndex.sections));
|
|
73
|
+
return {
|
|
74
|
+
...remoteIndex,
|
|
75
|
+
pages: remoteIndex.pages.map((p) => ({ ...p, order: p.order.filter((id) => knownIds.has(id)) })),
|
|
76
|
+
sections: Object.fromEntries(
|
|
77
|
+
Object.entries(remoteIndex.sections).filter(([id]) => knownIds.has(id)),
|
|
78
|
+
),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
49
82
|
export function rebaseContent(args: RebaseArgs): RebaseResult {
|
|
50
83
|
const localById = new Map(args.localSections.map((s) => [s.section.id, s]));
|
|
51
84
|
const remoteIds = new Set(args.remoteSections.map((s) => s.section.id));
|
|
@@ -53,7 +53,7 @@ export const ChildBlockWrapper = forwardRef<HTMLDivElement, ChildBlockWrapperPro
|
|
|
53
53
|
<div
|
|
54
54
|
ref={ref}
|
|
55
55
|
className={cn(
|
|
56
|
-
"group/childblock relative h-full rounded-
|
|
56
|
+
"group/childblock relative h-full rounded-inner",
|
|
57
57
|
isDragging && "opacity-50",
|
|
58
58
|
"hover:outline hover:outline-2 hover:outline-primary/30",
|
|
59
59
|
)}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect } from "react";
|
|
2
|
-
import { Check } from "lucide-react";
|
|
2
|
+
import { Check, ChevronDown, Home } from "lucide-react";
|
|
3
3
|
import type { SiteIndex, Page } from "../../schemas/site-config";
|
|
4
4
|
import type { Audience } from "../../auth/types";
|
|
5
5
|
// Sanctioned outside->inside import: document/ is a sealed subtree, but the
|
|
@@ -8,7 +8,7 @@ import type { Audience } from "../../auth/types";
|
|
|
8
8
|
import type { DocumentOptions } from "../../document/engine/settings";
|
|
9
9
|
import { Button } from "../shared/Button";
|
|
10
10
|
import { Input } from "../shared/Input";
|
|
11
|
-
import {
|
|
11
|
+
import { Toggle } from "../shared/Toggle";
|
|
12
12
|
import { AudienceIndicator } from "./AudienceIndicator";
|
|
13
13
|
import { DragHandle } from "./DragHandle";
|
|
14
14
|
import { useSortableRow } from "../../hooks/useSortableRow";
|
|
@@ -208,30 +208,35 @@ function PageRow({
|
|
|
208
208
|
className={cn("relative rounded-md border border-base-200", isDragging && "opacity-50")}
|
|
209
209
|
>
|
|
210
210
|
<DropEdgeIndicator edge={closestEdge} />
|
|
211
|
-
<div className="flex items-
|
|
211
|
+
<div className="flex items-stretch gap-2 pl-3">
|
|
212
212
|
{draggable && (
|
|
213
|
-
<div className="shrink-0 [&_[role=tooltip]]:hidden">
|
|
213
|
+
<div className="flex shrink-0 items-center py-2 [&_[role=tooltip]]:hidden">
|
|
214
214
|
<DragHandle ref={handleRef} />
|
|
215
215
|
</div>
|
|
216
216
|
)}
|
|
217
|
-
<div className="min-w-0 flex-1">
|
|
218
|
-
<div className="flex items-center gap-2">
|
|
219
|
-
<span className={cn("truncate text-sm font-medium text-base-contrast", !page.title && "italic text-base-contrast/60")}>
|
|
220
|
-
{pageDisplayTitle(page.title)}
|
|
221
|
-
</span>
|
|
222
|
-
{page.isHome && <span className="rounded bg-primary px-1.5 py-0.5 text-xs font-medium text-primary-contrast">Home page</span>}
|
|
223
|
-
{!page.showInNav && <span className="rounded bg-base-100 px-1.5 py-0.5 text-xs font-medium text-base-contrast">Hidden</span>}
|
|
224
|
-
{page.status === "archived" && <span className="rounded bg-base-100 px-1.5 py-0.5 text-xs font-medium text-base-contrast">Archived</span>}
|
|
225
|
-
</div>
|
|
226
|
-
<div className="text-xs text-base-contrast/70">{page.isHome ? "/" : `/${page.slug}`}</div>
|
|
227
|
-
</div>
|
|
228
217
|
<button
|
|
229
218
|
type="button"
|
|
230
219
|
aria-label={`Edit settings for ${pageDisplayTitle(page.title)}`}
|
|
220
|
+
aria-expanded={expanded}
|
|
231
221
|
onClick={handleHeaderClick}
|
|
232
|
-
className="cursor-pointer
|
|
222
|
+
className="flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded py-2 pr-3 pl-4 text-left hover:bg-base-accent"
|
|
233
223
|
>
|
|
234
|
-
|
|
224
|
+
<div className="min-w-0 flex-1">
|
|
225
|
+
<div className="flex items-center gap-2">
|
|
226
|
+
<span className={cn("truncate text-sm font-medium text-base-contrast", !page.title && "italic text-base-contrast/60")}>
|
|
227
|
+
{pageDisplayTitle(page.title)}
|
|
228
|
+
</span>
|
|
229
|
+
{page.isHome && <Home size={14} aria-label="Home page" className="shrink-0 text-base-contrast/60" />}
|
|
230
|
+
{!page.showInNav && <span className="rounded bg-base-100 px-1.5 py-0.5 text-xs font-medium text-base-contrast">Hidden</span>}
|
|
231
|
+
{page.status === "archived" && <span className="rounded bg-base-100 px-1.5 py-0.5 text-xs font-medium text-base-contrast">Archived</span>}
|
|
232
|
+
</div>
|
|
233
|
+
<div className="text-xs text-base-contrast/70">{page.isHome ? "/" : `/${page.slug}`}</div>
|
|
234
|
+
</div>
|
|
235
|
+
<ChevronDown
|
|
236
|
+
size={16}
|
|
237
|
+
aria-hidden="true"
|
|
238
|
+
className={cn("shrink-0 text-base-contrast/50 transition-transform", expanded && "rotate-180")}
|
|
239
|
+
/>
|
|
235
240
|
</button>
|
|
236
241
|
</div>
|
|
237
242
|
|
|
@@ -254,7 +259,7 @@ function PageRow({
|
|
|
254
259
|
onChange={handleSlugChange}
|
|
255
260
|
/>
|
|
256
261
|
)}
|
|
257
|
-
<div className="flex
|
|
262
|
+
<div className="flex flex-col gap-3">
|
|
258
263
|
<div>
|
|
259
264
|
<label className="mb-1 block text-sm text-base-contrast">Audience</label>
|
|
260
265
|
<AudienceIndicator access={page.access} audiences={audiences} onChange={onSetAudience} />
|
|
@@ -264,20 +269,23 @@ function PageRow({
|
|
|
264
269
|
</p>
|
|
265
270
|
)}
|
|
266
271
|
</div>
|
|
267
|
-
<
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
<div className="flex flex-col divide-y divide-base-200 rounded-inner border border-base-200">
|
|
273
|
+
<div className="flex items-center justify-between gap-4 px-3 py-2.5">
|
|
274
|
+
<div className="min-w-0">
|
|
275
|
+
<div className="text-sm text-base-contrast">Show in menu</div>
|
|
276
|
+
<div className="text-xs text-base-contrast/70">List this page in the site navigation.</div>
|
|
277
|
+
</div>
|
|
278
|
+
<Toggle label="Show in menu" checked={page.showInNav} onChange={(v) => onSetFields({ showInNav: v })} />
|
|
279
|
+
</div>
|
|
280
|
+
<div className="flex items-center justify-between gap-4 px-3 py-2.5">
|
|
281
|
+
<div className="min-w-0">
|
|
282
|
+
<div className="text-sm text-base-contrast">Document mode</div>
|
|
283
|
+
<div className="text-xs text-base-contrast/70">Adds a presentation view of this page.</div>
|
|
284
|
+
</div>
|
|
285
|
+
<Toggle label="Document mode" checked={page.document?.enabled ?? false} onChange={(enabled) => onSetDocument({ enabled })} />
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
274
288
|
</div>
|
|
275
|
-
<Checkbox
|
|
276
|
-
label="Document mode"
|
|
277
|
-
description="Adds a presentation view of this page."
|
|
278
|
-
checked={page.document?.enabled ?? false}
|
|
279
|
-
onChange={(enabled) => onSetDocument({ enabled })}
|
|
280
|
-
/>
|
|
281
289
|
<div className="flex items-center gap-2">
|
|
282
290
|
<Button
|
|
283
291
|
variant="secondary"
|
|
@@ -246,12 +246,12 @@ export function SectionWrapper({
|
|
|
246
246
|
"relative",
|
|
247
247
|
isDragging && "opacity-50",
|
|
248
248
|
isLocked && "opacity-60",
|
|
249
|
-
isActive && "outline outline-2 outline-primary/50 rounded-
|
|
249
|
+
isActive && "outline outline-2 outline-primary/50 rounded-outer",
|
|
250
250
|
!isActive &&
|
|
251
251
|
showAllChrome &&
|
|
252
|
-
"outline outline-2 outline-primary/20 rounded-
|
|
252
|
+
"outline outline-2 outline-primary/20 rounded-outer",
|
|
253
253
|
!alwaysShow &&
|
|
254
|
-
"group-hover:outline group-hover:outline-2 group-hover:outline-primary/20 group-hover:rounded-
|
|
254
|
+
"group-hover:outline group-hover:outline-2 group-hover:outline-primary/20 group-hover:rounded-outer",
|
|
255
255
|
)}
|
|
256
256
|
data-section-id={sectionId}
|
|
257
257
|
data-section-type={sectionType}
|
|
@@ -14,12 +14,13 @@ interface Props {
|
|
|
14
14
|
siteName: string;
|
|
15
15
|
darkMode: "light" | "dark" | "optional";
|
|
16
16
|
lastUpdated: string | null;
|
|
17
|
+
logo?: { lightUrl: string; darkUrl: string | null; invertInDark: boolean } | null;
|
|
17
18
|
// Optional same-island handler (tests). In production the editor nav is a
|
|
18
19
|
// separate island from EditorShell, so a click dispatches pageSelectEvent.
|
|
19
20
|
onPageSelect?: (pageId: string) => void;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
export default function Navigation({ siteNav: initialNav, siteName, darkMode, lastUpdated, onPageSelect }: Props) {
|
|
23
|
+
export default function Navigation({ siteNav: initialNav, siteName, darkMode, lastUpdated, logo, onPageSelect }: Props) {
|
|
23
24
|
const [isOpen, setIsOpen] = useState(false);
|
|
24
25
|
const [isEditMode, setIsEditMode] = useState(false);
|
|
25
26
|
const [currentDarkMode, setCurrentDarkMode] = useState(darkMode);
|
|
@@ -135,6 +136,19 @@ export default function Navigation({ siteNav: initialNav, siteName, darkMode, la
|
|
|
135
136
|
</ul>
|
|
136
137
|
);
|
|
137
138
|
|
|
139
|
+
const logoMark = logo ? (
|
|
140
|
+
<>
|
|
141
|
+
<img
|
|
142
|
+
src={logo.lightUrl}
|
|
143
|
+
alt={currentSiteName}
|
|
144
|
+
className={logo.darkUrl ? "block h-8 w-auto object-contain dark:hidden" : logo.invertInDark ? "h-8 w-auto object-contain dark:invert" : "h-8 w-auto object-contain"}
|
|
145
|
+
/>
|
|
146
|
+
{logo.darkUrl && (
|
|
147
|
+
<img src={logo.darkUrl} alt={currentSiteName} className="hidden h-8 w-auto object-contain dark:block" />
|
|
148
|
+
)}
|
|
149
|
+
</>
|
|
150
|
+
) : null;
|
|
151
|
+
|
|
138
152
|
const handlePageClick = useCallback((id: string) => {
|
|
139
153
|
if (onPageSelect) onPageSelect(id);
|
|
140
154
|
else pageSelectEvent.dispatch(id);
|
|
@@ -193,7 +207,10 @@ export default function Navigation({ siteNav: initialNav, siteName, darkMode, la
|
|
|
193
207
|
<>
|
|
194
208
|
<header className="fixed top-0 left-0 right-0 z-50 bg-base lg:hidden">
|
|
195
209
|
<div className="mx-auto max-w-screen-xl flex h-16 items-center justify-between px-4">
|
|
196
|
-
<
|
|
210
|
+
<div className="flex flex-col items-start gap-1">
|
|
211
|
+
{logoMark}
|
|
212
|
+
<span className="text-lg font-bold text-primary">{currentSiteName}</span>
|
|
213
|
+
</div>
|
|
197
214
|
<button onClick={() => setIsOpen(!isOpen)} className="cursor-pointer p-2 text-base-contrast" aria-label="Toggle navigation">
|
|
198
215
|
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
|
199
216
|
{isOpen
|
|
@@ -209,6 +226,7 @@ export default function Navigation({ siteNav: initialNav, siteName, darkMode, la
|
|
|
209
226
|
<nav className={cn("fixed top-0 left-0 lg:left-auto z-40 h-full w-64 flex flex-col overflow-y-auto border-r border-base-200 bg-base pt-16 transition-transform lg:translate-x-0 nav-sidebar",
|
|
210
227
|
isOpen ? "translate-x-0" : "-translate-x-full")}>
|
|
211
228
|
<div className="hidden px-4 py-4 lg:block">
|
|
229
|
+
{logoMark}
|
|
212
230
|
<span className="text-lg font-bold text-primary">{currentSiteName}</span>
|
|
213
231
|
</div>
|
|
214
232
|
|
|
@@ -60,7 +60,7 @@ export function Tabs({ tabs, defaultTabId, activeTabId, onTabChange, fullBleedTa
|
|
|
60
60
|
{/* px-px: the root's overflow-hidden would clip the 1px focus ring of
|
|
61
61
|
inputs that span the full panel width (rings are box-shadows drawn
|
|
62
62
|
outside the border box) — give them 1px to paint into. */}
|
|
63
|
-
<div role="tabpanel" className={cn("px-px", fullBleedTabBar && "pt-4")}>{activeTab?.content}</div>
|
|
63
|
+
<div role="tabpanel" className={cn("flex min-h-0 flex-1 flex-col px-px", fullBleedTabBar && "pt-4")}>{activeTab?.content}</div>
|
|
64
64
|
</div>
|
|
65
65
|
);
|
|
66
66
|
}
|
|
@@ -23,7 +23,6 @@ import type { BlockMove } from "../../lib/block-move";
|
|
|
23
23
|
import { EditorModalProvider, useEditorModal } from "./EditorModalContext";
|
|
24
24
|
import { EditorModal } from "./EditorModal";
|
|
25
25
|
import { SiteSettingsModal } from "./SiteSettingsModal";
|
|
26
|
-
import { ChatbotConfigModal } from "./ChatbotConfigModal";
|
|
27
26
|
import ChatWidget from "../chat/ChatWidget";
|
|
28
27
|
import { MediaLibraryModal } from "./MediaLibraryModal";
|
|
29
28
|
import { MediaLibraryContext } from "./MediaLibraryContext";
|
|
@@ -69,7 +68,7 @@ import {
|
|
|
69
68
|
deleteSectionRows,
|
|
70
69
|
preserveEdit,
|
|
71
70
|
} from "../../lib/dexie";
|
|
72
|
-
import { rebaseContent } from "../../collab/rebase";
|
|
71
|
+
import { rebaseContent, reconcileRemoteIndex } from "../../collab/rebase";
|
|
73
72
|
import { deriveRecoveryInputs, applyConflictChoices } from "../../collab/recovery";
|
|
74
73
|
import { getCollabProvider } from "../../collab/provider-registry";
|
|
75
74
|
import type { CollabBootstrap, CollabPeer, CollabStatus, SavedMessage, TakeoverMessage } from "../../collab/types";
|
|
@@ -100,7 +99,7 @@ import { IconButton } from "../shared/IconButton";
|
|
|
100
99
|
import { SegmentedControl } from "../shared/SegmentedControl";
|
|
101
100
|
import { computeDisplaySections } from "./view-branch";
|
|
102
101
|
import { SettingsIcon } from "../shared/icons";
|
|
103
|
-
import { ImageIcon, ListOrderedIcon, FilesIcon,
|
|
102
|
+
import { ImageIcon, ListOrderedIcon, FilesIcon, JoystickIcon, X } from "lucide-react";
|
|
104
103
|
import { ErrorBoundary } from "../shared/ErrorBoundary";
|
|
105
104
|
import { HistoryToolbar } from "./HistoryToolbar";
|
|
106
105
|
import { RestoreModal } from "./RestoreModal";
|
|
@@ -201,7 +200,6 @@ export default function EditorShell({
|
|
|
201
200
|
const [showRestoreModal, setShowRestoreModal] = useState(false);
|
|
202
201
|
const [showOrderingModal, setShowOrderingModal] = useState(false);
|
|
203
202
|
const [showPagesModal, setShowPagesModal] = useState(false);
|
|
204
|
-
const [showChatbotConfig, setShowChatbotConfig] = useState(false);
|
|
205
203
|
const [showDocumentEditor, setShowDocumentEditor] = useState(false);
|
|
206
204
|
const [isRestoring, setIsRestoring] = useState(false);
|
|
207
205
|
const [rejectedUploads, setRejectedUploads] = useState<{ name: string; reason: "size" | "type" }[]>([]);
|
|
@@ -365,6 +363,10 @@ export default function EditorShell({
|
|
|
365
363
|
markSectionDirty: persistence.markSectionDirty,
|
|
366
364
|
onUploadError: (message) => setUploadErrorMessage(message),
|
|
367
365
|
onUploadNotice: setUploadNotice,
|
|
366
|
+
onSiteConfigChange: (updater) => {
|
|
367
|
+
if (!siteConfig) return;
|
|
368
|
+
handleSiteConfigChange(updater(siteConfig));
|
|
369
|
+
},
|
|
368
370
|
});
|
|
369
371
|
|
|
370
372
|
const buildStatus = useBuildStatus();
|
|
@@ -634,22 +636,16 @@ export default function EditorShell({
|
|
|
634
636
|
if (persistence.hasUnsavedIndex()) return;
|
|
635
637
|
const parsed = IndexSchema.safeParse(msg.index);
|
|
636
638
|
if (!parsed.success) return;
|
|
637
|
-
//
|
|
638
|
-
//
|
|
639
|
-
//
|
|
640
|
-
//
|
|
641
|
-
//
|
|
642
|
-
//
|
|
643
|
-
//
|
|
644
|
-
//
|
|
645
|
-
|
|
646
|
-
const pruned
|
|
647
|
-
...parsed.data,
|
|
648
|
-
pages: parsed.data.pages.map((p) => ({ ...p, order: p.order.filter((id) => localIds.has(id)) })),
|
|
649
|
-
sections: Object.fromEntries(
|
|
650
|
-
Object.entries(parsed.data.sections).filter(([id]) => localIds.has(id)),
|
|
651
|
-
),
|
|
652
|
-
};
|
|
639
|
+
// Withhold ids our current index doesn't know before applying the peer's:
|
|
640
|
+
// (a) the peer's unsaved ADD — its file isn't on the branch yet, so letting
|
|
641
|
+
// it into siteIndexRef would poison OUR next save with a dangling index ref
|
|
642
|
+
// the server rejects (its live appearance is deferred to the peer's save,
|
|
643
|
+
// via the saved-event sync); or (b) a section WE deleted unsaved — our
|
|
644
|
+
// deletion stands until save-time arbitration. Keyed on our INDEX, not the
|
|
645
|
+
// loaded section bodies: a live section whose body the loader skipped
|
|
646
|
+
// (schema/registry miss, depth trip) is still indexed and must survive —
|
|
647
|
+
// guaranteed because we only reach here with no unsaved index work.
|
|
648
|
+
const pruned = reconcileRemoteIndex(parsed.data, siteIndexRef.current);
|
|
653
649
|
setSiteIndex(pruned);
|
|
654
650
|
siteIndexRef.current = pruned;
|
|
655
651
|
},
|
|
@@ -1445,7 +1441,6 @@ export default function EditorShell({
|
|
|
1445
1441
|
onRestoreClick={() => setShowRestoreModal(true)}
|
|
1446
1442
|
onOrderingClick={() => setShowOrderingModal(true)}
|
|
1447
1443
|
onPagesClick={() => setShowPagesModal(true)}
|
|
1448
|
-
onChatbotClick={() => setShowChatbotConfig(true)}
|
|
1449
1444
|
collabPeers={collab.peers}
|
|
1450
1445
|
collabSelfId={collabBootstrap?.userId ?? null}
|
|
1451
1446
|
collabStatus={collab.status}
|
|
@@ -1577,19 +1572,11 @@ export default function EditorShell({
|
|
|
1577
1572
|
siteConfig={siteConfig!}
|
|
1578
1573
|
onSiteConfigChange={handleSiteConfigChange}
|
|
1579
1574
|
onAudiencesChange={setAudiences}
|
|
1575
|
+
audiences={audiences}
|
|
1576
|
+
chatbotPlatformEnabled={chatbotPlatformEnabled}
|
|
1580
1577
|
capabilities={capabilities}
|
|
1581
1578
|
currentUser={currentUser}
|
|
1582
1579
|
/>
|
|
1583
|
-
{siteConfig && (
|
|
1584
|
-
<ChatbotConfigModal
|
|
1585
|
-
isOpen={showChatbotConfig}
|
|
1586
|
-
onClose={() => setShowChatbotConfig(false)}
|
|
1587
|
-
siteConfig={siteConfig}
|
|
1588
|
-
onSiteConfigChange={handleSiteConfigChange}
|
|
1589
|
-
audiences={audiences}
|
|
1590
|
-
platformEnabled={chatbotPlatformEnabled}
|
|
1591
|
-
/>
|
|
1592
|
-
)}
|
|
1593
1580
|
<EditorModal
|
|
1594
1581
|
isOpen={pendingDeleteSectionId !== null}
|
|
1595
1582
|
onClose={() => setPendingDeleteSectionId(null)}
|
|
@@ -2280,7 +2267,6 @@ function EditorToolbar({
|
|
|
2280
2267
|
onRestoreClick,
|
|
2281
2268
|
onOrderingClick,
|
|
2282
2269
|
onPagesClick,
|
|
2283
|
-
onChatbotClick,
|
|
2284
2270
|
collabPeers,
|
|
2285
2271
|
collabSelfId,
|
|
2286
2272
|
collabStatus,
|
|
@@ -2303,7 +2289,6 @@ function EditorToolbar({
|
|
|
2303
2289
|
onRestoreClick: () => void;
|
|
2304
2290
|
onOrderingClick: () => void;
|
|
2305
2291
|
onPagesClick: () => void;
|
|
2306
|
-
onChatbotClick: () => void;
|
|
2307
2292
|
collabPeers: CollabPeer[];
|
|
2308
2293
|
collabSelfId: string | null;
|
|
2309
2294
|
collabStatus: CollabStatus;
|
|
@@ -2377,42 +2362,11 @@ function EditorToolbar({
|
|
|
2377
2362
|
</div>
|
|
2378
2363
|
<div className="flex items-center justify-end gap-2">
|
|
2379
2364
|
<ProcessingIndicator items={processingItems} />
|
|
2380
|
-
<IconButton
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
size="md"
|
|
2384
|
-
onClick={onOrderingClick}
|
|
2385
|
-
className="border border-base-200 bg-base-accent"
|
|
2386
|
-
/>
|
|
2387
|
-
<IconButton
|
|
2388
|
-
icon={<ImageIcon size={16} />}
|
|
2389
|
-
label="Media library"
|
|
2390
|
-
size="md"
|
|
2391
|
-
onClick={onMediaClick}
|
|
2392
|
-
className="border border-base-200 bg-base-accent"
|
|
2393
|
-
/>
|
|
2394
|
-
<IconButton
|
|
2395
|
-
icon={<FilesIcon size={16} />}
|
|
2396
|
-
label="Pages"
|
|
2397
|
-
size="md"
|
|
2398
|
-
onClick={onPagesClick}
|
|
2399
|
-
className="border border-base-200 bg-base-accent"
|
|
2400
|
-
/>
|
|
2401
|
-
<IconButton
|
|
2402
|
-
icon={<MessageCircleIcon size={16} />}
|
|
2403
|
-
label="Chatbot"
|
|
2404
|
-
size="md"
|
|
2405
|
-
onClick={onChatbotClick}
|
|
2406
|
-
className="border border-base-200 bg-base-accent"
|
|
2407
|
-
/>
|
|
2408
|
-
<IconButton
|
|
2409
|
-
icon={<SettingsIcon size={16} />}
|
|
2410
|
-
label="Site settings"
|
|
2411
|
-
size="md"
|
|
2412
|
-
onClick={onSettingsClick}
|
|
2413
|
-
className="border border-base-200 bg-base-accent"
|
|
2414
|
-
/>
|
|
2365
|
+
<IconButton icon={<ImageIcon size={16} />} label="Media library" size="md" onClick={onMediaClick} className="border border-base-200 bg-base-accent" />
|
|
2366
|
+
<IconButton icon={<ListOrderedIcon size={16} />} label="Reorder sections" size="md" onClick={onOrderingClick} className="border border-base-200 bg-base-accent" />
|
|
2367
|
+
<IconButton icon={<FilesIcon size={16} />} label="Pages" size="md" onClick={onPagesClick} className="border border-base-200 bg-base-accent" />
|
|
2415
2368
|
<ShowAllChromeToggle />
|
|
2369
|
+
<IconButton icon={<SettingsIcon size={16} />} label="Site settings" size="md" onClick={onSettingsClick} className="border border-base-200 bg-base-accent" />
|
|
2416
2370
|
</div>
|
|
2417
2371
|
</div>
|
|
2418
2372
|
</div>
|
|
@@ -2457,14 +2411,13 @@ function ShowAllChromeToggle() {
|
|
|
2457
2411
|
const { showAllChrome, toggleShowAllChrome } = useEditorContext();
|
|
2458
2412
|
|
|
2459
2413
|
return (
|
|
2460
|
-
<
|
|
2461
|
-
|
|
2462
|
-
|
|
2414
|
+
<IconButton
|
|
2415
|
+
icon={<JoystickIcon size={16} />}
|
|
2416
|
+
label="Toggle editor chrome visibility"
|
|
2417
|
+
size="md"
|
|
2463
2418
|
onClick={toggleShowAllChrome}
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
{showAllChrome ? "Hide Controls" : "Show Controls"}
|
|
2468
|
-
</Button>
|
|
2419
|
+
aria-pressed={showAllChrome}
|
|
2420
|
+
className="border border-base-200 bg-base-accent"
|
|
2421
|
+
/>
|
|
2469
2422
|
);
|
|
2470
2423
|
}
|