@driftime/sanity-plugin-handbook 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -16
- package/dist/index.d.ts +70 -77
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +215 -255
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, createElement, useContext, useEffect, useRef, useState } from "react";
|
|
2
|
-
import { CommandList, PreviewCard, SanityDefaultPreview, defineArrayMember, defineField, definePlugin, defineType,
|
|
2
|
+
import { CommandList, PreviewCard, SanityDefaultPreview, defineArrayMember, defineField, definePlugin, defineType, useCurrentUser, useDocumentStore, useSchema } from "sanity";
|
|
3
3
|
import { c } from "react/compiler-runtime";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { Box, Button, Card, Flex, Heading, Layer, LayerProvider, Stack, Text, useClickOutsideEvent, useElementSize, useTheme_v2 } from "@sanity/ui";
|
|
@@ -11,21 +11,18 @@ import { ChevronRightIcon } from "@sanity/icons/ChevronRight";
|
|
|
11
11
|
import { Popover } from "@sanity/ui/popover";
|
|
12
12
|
import { PortableText } from "@portabletext/react";
|
|
13
13
|
import { Code } from "@sanity/ui/code";
|
|
14
|
-
/**
|
|
15
|
-
* Properties the plugin's own icons are drawn with. Icons taken from `@sanity/icons` are left alone,
|
|
16
|
-
* since they already carry the sizing and stroke the rest of the Studio uses.
|
|
17
|
-
*/
|
|
14
|
+
/** Default props for the plugin's own icons. Icons from `@sanity/icons` already match the Studio. */
|
|
18
15
|
const defaultIconProps = {
|
|
19
16
|
width: "1em",
|
|
20
17
|
height: "1em",
|
|
21
18
|
strokeWidth: 1.5
|
|
22
19
|
};
|
|
23
20
|
/**
|
|
24
|
-
*
|
|
21
|
+
* Wraps an SVG icon component for use in the Studio.
|
|
25
22
|
*
|
|
26
|
-
* @param icon - The icon
|
|
27
|
-
* @param props -
|
|
28
|
-
* @returns
|
|
23
|
+
* @param icon - The icon to wrap.
|
|
24
|
+
* @param props - Props that override the Studio icon defaults.
|
|
25
|
+
* @returns An icon component.
|
|
29
26
|
*/
|
|
30
27
|
function createSanityIcon(icon, props) {
|
|
31
28
|
let Icon = icon;
|
|
@@ -37,38 +34,45 @@ function createSanityIcon(icon, props) {
|
|
|
37
34
|
}
|
|
38
35
|
return SanityIcon;
|
|
39
36
|
}
|
|
40
|
-
/** Whether
|
|
37
|
+
/** Whether this is a development build, the only kind in which the plugin logs. */
|
|
41
38
|
const isDevelopment = process.env.NODE_ENV === "development", prefixStyle = "color: #2276fc";
|
|
42
39
|
/**
|
|
43
|
-
* Creates
|
|
44
|
-
*
|
|
45
|
-
* Studio's own messages are; a terminal ignores the styling and prints it plain.
|
|
40
|
+
* Creates a logger that prefixes messages with the plugin's name and only logs in development builds.
|
|
41
|
+
* Browser consoles show the prefix in blue.
|
|
46
42
|
*
|
|
47
|
-
* @param name -
|
|
48
|
-
* @returns Functions that
|
|
43
|
+
* @param name - The package name to prefix messages with.
|
|
44
|
+
* @returns Functions that log progress, a warning, or an error, or format a message to throw.
|
|
49
45
|
*/
|
|
50
46
|
function createLogger(name) {
|
|
51
47
|
let prefix = `[${name}]`;
|
|
52
48
|
/**
|
|
53
|
-
*
|
|
49
|
+
* Prefixes a message with the package name.
|
|
54
50
|
*
|
|
55
|
-
* @param message - The message
|
|
56
|
-
* @returns The message
|
|
51
|
+
* @param message - The message.
|
|
52
|
+
* @returns The prefixed message.
|
|
57
53
|
*/
|
|
58
54
|
function format(message) {
|
|
59
55
|
return `${prefix} ${message}`;
|
|
60
56
|
}
|
|
61
57
|
return {
|
|
62
58
|
/**
|
|
63
|
-
*
|
|
59
|
+
* Logs progress worth seeing, such as what a build step did, in development builds only.
|
|
60
|
+
*
|
|
61
|
+
* @param message - What happened.
|
|
62
|
+
*/
|
|
63
|
+
info(message) {
|
|
64
|
+
isDevelopment && console.info(`%c${prefix}%c ${message}`, prefixStyle, "");
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Logs a warning about something the plugin recovered from, in development builds only.
|
|
64
68
|
*
|
|
65
|
-
* @param message - What
|
|
69
|
+
* @param message - What happened and what to do about it.
|
|
66
70
|
*/
|
|
67
71
|
warn(message) {
|
|
68
72
|
isDevelopment && console.warn(`%c${prefix}%c ${message}`, prefixStyle, "");
|
|
69
73
|
},
|
|
70
74
|
/**
|
|
71
|
-
*
|
|
75
|
+
* Logs an error the plugin couldn't recover from, in development builds only.
|
|
72
76
|
*
|
|
73
77
|
* @param message - What went wrong and what to do about it.
|
|
74
78
|
*/
|
|
@@ -78,7 +82,7 @@ function createLogger(name) {
|
|
|
78
82
|
format
|
|
79
83
|
};
|
|
80
84
|
}
|
|
81
|
-
/**
|
|
85
|
+
/** Package name, used as the prefix on every logged message. */
|
|
82
86
|
const pluginName = "@driftime/sanity-plugin-handbook", logger = createLogger(pluginName), guideTypeName = "handbook.guide", handbookTypeName = "handbook.handbook", imageTypeName = "handbook.image", videoTypeName = "handbook.video", codeTypeName = "handbook.code", calloutTypeName = "handbook.callout", horizontalRuleTypeName = "handbook.horizontalRule", singletonTypes = /* @__PURE__ */ new Set([handbookTypeName]), documentTypes = /* @__PURE__ */ new Set([handbookTypeName, guideTypeName]);
|
|
83
87
|
function BookTextIcon(props) {
|
|
84
88
|
let $ = c(5), t0, t1, t2;
|
|
@@ -103,12 +107,11 @@ function BookTextIcon(props) {
|
|
|
103
107
|
}), $[3] = props, $[4] = t3), t3;
|
|
104
108
|
}
|
|
105
109
|
/**
|
|
106
|
-
* Checks whether a value is
|
|
107
|
-
*
|
|
108
|
-
* built from a class counts as present on existence alone. Not intended for boolean flags.
|
|
110
|
+
* Checks whether a value is present. `false`, blank strings, and empty plain objects count as absent,
|
|
111
|
+
* as does an array with no present elements.
|
|
109
112
|
*
|
|
110
113
|
* @param value - The value to check.
|
|
111
|
-
* @returns True if the value is
|
|
114
|
+
* @returns True if the value is present.
|
|
112
115
|
*/
|
|
113
116
|
function isDefined(value) {
|
|
114
117
|
if (value == null || value === !1) return !1;
|
|
@@ -121,10 +124,10 @@ function isDefined(value) {
|
|
|
121
124
|
return !0;
|
|
122
125
|
}
|
|
123
126
|
/**
|
|
124
|
-
* Converts a string
|
|
127
|
+
* Converts a string to another case.
|
|
125
128
|
*
|
|
126
129
|
* @param value - The string to convert.
|
|
127
|
-
* @param format - The
|
|
130
|
+
* @param format - The case to convert to.
|
|
128
131
|
* @returns The converted string.
|
|
129
132
|
*/
|
|
130
133
|
function convertCase(value, format) {
|
|
@@ -140,21 +143,20 @@ function convertCase(value, format) {
|
|
|
140
143
|
}
|
|
141
144
|
}
|
|
142
145
|
/**
|
|
143
|
-
* Checks whether a value
|
|
146
|
+
* Checks whether a value is an object whose keys can be read.
|
|
144
147
|
*
|
|
145
148
|
* @param value - The value to check.
|
|
146
|
-
* @returns True if the value
|
|
149
|
+
* @returns True if the value is an object.
|
|
147
150
|
*/
|
|
148
151
|
function isRecord(value) {
|
|
149
152
|
return typeof value == "object" && !!value;
|
|
150
153
|
}
|
|
151
154
|
/**
|
|
152
|
-
* Reads a
|
|
153
|
-
* inside a shape it does not otherwise know.
|
|
155
|
+
* Reads a nested value by following a path of keys.
|
|
154
156
|
*
|
|
155
157
|
* @param value - The object to read from.
|
|
156
|
-
* @param path -
|
|
157
|
-
* @returns The value
|
|
158
|
+
* @param path - The keys to follow.
|
|
159
|
+
* @returns The value, or undefined when the path doesn't exist.
|
|
158
160
|
*/
|
|
159
161
|
function readPath(value, path) {
|
|
160
162
|
let current = value;
|
|
@@ -164,7 +166,7 @@ function readPath(value, path) {
|
|
|
164
166
|
}
|
|
165
167
|
return current;
|
|
166
168
|
}
|
|
167
|
-
/** Share of the
|
|
169
|
+
/** Share of the space the content pane takes relative to the sidebar. */
|
|
168
170
|
const contentSpacing = {
|
|
169
171
|
section: 48,
|
|
170
172
|
paragraph: 16,
|
|
@@ -175,80 +177,53 @@ const contentSpacing = {
|
|
|
175
177
|
list: 32,
|
|
176
178
|
nestedList: 12,
|
|
177
179
|
rule: 40
|
|
178
|
-
}, assetUrlFragment = "\"asset\": { \"url\": asset.asset->url }",
|
|
179
|
-
...,
|
|
180
|
-
content[] { ..., ${`
|
|
181
|
-
_type == "${imageTypeName}" => { ..., ${assetUrlFragment} },
|
|
182
|
-
_type == "${videoTypeName}" => { ..., ${assetUrlFragment} }
|
|
183
|
-
`} }
|
|
184
|
-
}`;
|
|
185
|
-
/**
|
|
186
|
-
* Brands a GROQ query with the shape of the data it returns, so a fetch can infer its result type
|
|
187
|
-
* instead of being told it at every call site.
|
|
188
|
-
*
|
|
189
|
-
* @param query - The GROQ query string.
|
|
190
|
-
* @returns The query, typed to the given result shape.
|
|
191
|
-
*/
|
|
192
|
-
function defineTypedQuery(query) {
|
|
193
|
-
return query;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Runs a branded query against the dataset, resolving a missing document to undefined.
|
|
197
|
-
*
|
|
198
|
-
* @param client - The Sanity client to query with.
|
|
199
|
-
* @param query - The branded query to run.
|
|
200
|
-
* @returns The result, or undefined when the query matched nothing.
|
|
201
|
-
*/
|
|
202
|
-
async function fetchQuery(client, query) {
|
|
203
|
-
return await client.fetch(query) ?? void 0;
|
|
204
|
-
}
|
|
205
|
-
/** Fetches the Handbook singleton with expanded guide references. */
|
|
206
|
-
const handbookQuery = defineTypedQuery(`
|
|
180
|
+
}, assetUrlFragment = "\"asset\": { \"url\": asset.asset->url }", handbookQuery = `
|
|
207
181
|
*[_type == "${handbookTypeName}"][0] {
|
|
208
182
|
...,
|
|
209
183
|
groups[] {
|
|
210
184
|
...,
|
|
211
185
|
guides[] {
|
|
212
186
|
...,
|
|
213
|
-
${
|
|
187
|
+
${`...@-> {
|
|
188
|
+
...,
|
|
189
|
+
content[] { ..., ${`
|
|
190
|
+
_type == "${imageTypeName}" => { ..., ${assetUrlFragment} },
|
|
191
|
+
_type == "${videoTypeName}" => { ..., ${assetUrlFragment} }
|
|
192
|
+
`} }
|
|
193
|
+
}`}
|
|
214
194
|
}
|
|
215
195
|
}
|
|
216
196
|
}
|
|
217
|
-
|
|
197
|
+
`, handbookDocumentsQuery = `*[_type == "${handbookTypeName}" || _type == "${guideTypeName}"]`;
|
|
218
198
|
/**
|
|
219
|
-
*
|
|
220
|
-
* whenever one of the documents it draws on changes.
|
|
199
|
+
* Reads the published Handbook document with its guides expanded, updating when any Handbook document is published.
|
|
221
200
|
*
|
|
222
|
-
* @returns The Handbook
|
|
201
|
+
* @returns The Handbook document, or undefined while it loads or when there isn't one.
|
|
223
202
|
*/
|
|
224
203
|
function useHandbookDocument() {
|
|
225
|
-
let $ = c(
|
|
226
|
-
$[0] ===
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
204
|
+
let $ = c(3), documentStore = useDocumentStore(), [handbook, setHandbook] = useState(), t0, t1;
|
|
205
|
+
return $[0] === documentStore ? (t0 = $[1], t1 = $[2]) : (t0 = () => {
|
|
206
|
+
let subscription = documentStore.listenQuery({
|
|
207
|
+
fetch: handbookQuery,
|
|
208
|
+
listen: handbookDocumentsQuery
|
|
209
|
+
}, {}, {
|
|
210
|
+
apiVersion: "2026-01-01",
|
|
211
|
+
perspective: "published",
|
|
212
|
+
throttleTime: 1e3
|
|
213
|
+
}).subscribe((result) => {
|
|
214
|
+
setHandbook(result ?? void 0);
|
|
235
215
|
});
|
|
236
216
|
return () => {
|
|
237
217
|
subscription.unsubscribe();
|
|
238
218
|
};
|
|
239
|
-
},
|
|
240
|
-
let t3;
|
|
241
|
-
return $[4] !== handbook || $[5] !== loading ? (t3 = {
|
|
242
|
-
handbook,
|
|
243
|
-
loading
|
|
244
|
-
}, $[4] = handbook, $[5] = loading, $[6] = t3) : t3 = $[6], t3;
|
|
219
|
+
}, t1 = [documentStore], $[0] = documentStore, $[1] = t0, $[2] = t1), useEffect(t0, t1), handbook;
|
|
245
220
|
}
|
|
246
221
|
const HandbookContext = createContext(void 0);
|
|
247
222
|
/**
|
|
248
|
-
*
|
|
223
|
+
* Reads the Handbook context.
|
|
249
224
|
*
|
|
250
|
-
* @returns The
|
|
251
|
-
* @throws
|
|
225
|
+
* @returns The plugin configuration and the shared pane state.
|
|
226
|
+
* @throws When used outside the provider.
|
|
252
227
|
*/
|
|
253
228
|
function useHandbookContext() {
|
|
254
229
|
let handbookContext = useContext(HandbookContext);
|
|
@@ -256,30 +231,29 @@ function useHandbookContext() {
|
|
|
256
231
|
return handbookContext;
|
|
257
232
|
}
|
|
258
233
|
/**
|
|
259
|
-
* Provides the
|
|
260
|
-
*
|
|
234
|
+
* Provides the plugin configuration, the Handbook document, and the tab state shared by the sidebar and
|
|
235
|
+
* content panes.
|
|
261
236
|
*
|
|
262
|
-
* @returns The provider
|
|
237
|
+
* @returns The provider.
|
|
263
238
|
*/
|
|
264
239
|
function HandbookProvider(t0) {
|
|
265
|
-
let $ = c(
|
|
266
|
-
$[0] !== activeTab || $[1] !== blocks || $[2] !== handbook || $[3] !==
|
|
240
|
+
let $ = c(11), { sidebarTitle, roles, blocks, undocumentedFieldMessage, children } = t0, [activeTab, setActiveTab] = useState(void 0), [sidebarExpanded, setSidebarExpanded] = useState(!0), handbook = useHandbookDocument(), t1;
|
|
241
|
+
$[0] !== activeTab || $[1] !== blocks || $[2] !== handbook || $[3] !== roles || $[4] !== sidebarExpanded || $[5] !== sidebarTitle || $[6] !== undocumentedFieldMessage ? (t1 = {
|
|
267
242
|
sidebarTitle,
|
|
268
243
|
roles,
|
|
269
244
|
blocks,
|
|
270
245
|
undocumentedFieldMessage,
|
|
271
246
|
activeTab,
|
|
272
247
|
sidebarExpanded,
|
|
273
|
-
loading,
|
|
274
248
|
handbook,
|
|
275
249
|
setActiveTab,
|
|
276
250
|
setSidebarExpanded
|
|
277
|
-
}, $[0] = activeTab, $[1] = blocks, $[2] = handbook, $[3] =
|
|
251
|
+
}, $[0] = activeTab, $[1] = blocks, $[2] = handbook, $[3] = roles, $[4] = sidebarExpanded, $[5] = sidebarTitle, $[6] = undocumentedFieldMessage, $[7] = t1) : t1 = $[7];
|
|
278
252
|
let t2;
|
|
279
|
-
return $[
|
|
253
|
+
return $[8] !== children || $[9] !== t1 ? (t2 = /* @__PURE__ */ jsx(HandbookContext, {
|
|
280
254
|
value: t1,
|
|
281
255
|
children
|
|
282
|
-
}), $[
|
|
256
|
+
}), $[8] = children, $[9] = t1, $[10] = t2) : t2 = $[10], t2;
|
|
283
257
|
}
|
|
284
258
|
function PaneHeader(t0) {
|
|
285
259
|
let $ = c(46), backButton, props, style, title;
|
|
@@ -571,7 +545,7 @@ function TriangleAlertIcon(props) {
|
|
|
571
545
|
]
|
|
572
546
|
}), $[3] = props, $[4] = t3), t3;
|
|
573
547
|
}
|
|
574
|
-
/** Hint kinds
|
|
548
|
+
/** Hint kinds, in display order. */
|
|
575
549
|
const hintKinds = [
|
|
576
550
|
{
|
|
577
551
|
name: "tip",
|
|
@@ -626,10 +600,9 @@ function FieldHints(t0) {
|
|
|
626
600
|
}), $[16] = T0, $[17] = t1, $[18] = t2, $[19] = t3, $[20] = t4, $[21] = t5) : t5 = $[21], t5;
|
|
627
601
|
}
|
|
628
602
|
/**
|
|
629
|
-
*
|
|
630
|
-
* title and falling back to a title-cased name.
|
|
603
|
+
* Works out a schema type's label: its Handbook title, then its schema title, then its name in title case.
|
|
631
604
|
*
|
|
632
|
-
* @param type - The schema type or field
|
|
605
|
+
* @param type - The schema type or field.
|
|
633
606
|
* @returns The label.
|
|
634
607
|
*/
|
|
635
608
|
function resolveTitle(type) {
|
|
@@ -637,28 +610,27 @@ function resolveTitle(type) {
|
|
|
637
610
|
return handbook?.title ?? title ?? convertCase(name, "title");
|
|
638
611
|
}
|
|
639
612
|
/**
|
|
640
|
-
*
|
|
641
|
-
*
|
|
613
|
+
* Works out a schema type's description, preferring its Handbook description and ignoring non-string
|
|
614
|
+
* schema descriptions.
|
|
642
615
|
*
|
|
643
|
-
* @param type - The schema type or field
|
|
644
|
-
* @returns The description, or undefined when
|
|
616
|
+
* @param type - The schema type or field.
|
|
617
|
+
* @returns The description, or undefined when there isn't one.
|
|
645
618
|
*/
|
|
646
619
|
function resolveDescription(type) {
|
|
647
620
|
let { description, handbook } = type;
|
|
648
621
|
return handbook?.description ?? (typeof description == "string" ? description : void 0);
|
|
649
622
|
}
|
|
650
623
|
/**
|
|
651
|
-
*
|
|
652
|
-
*
|
|
653
|
-
* built-in ones rather than at its own library's default size.
|
|
624
|
+
* Gets a schema type's icon as a component, redrawn at the plugin's icon size to match the built-in icons.
|
|
625
|
+
* String icons are ignored.
|
|
654
626
|
*
|
|
655
|
-
* @param type - The schema type
|
|
656
|
-
* @returns The icon component, or undefined when
|
|
627
|
+
* @param type - The schema type.
|
|
628
|
+
* @returns The icon component, or undefined when there isn't one.
|
|
657
629
|
*/
|
|
658
630
|
function resolveIcon(type) {
|
|
659
631
|
return typeof type.icon == "function" ? createSanityIcon(type.icon) : void 0;
|
|
660
632
|
}
|
|
661
|
-
/**
|
|
633
|
+
/** Types whose subfields aren't shown. */
|
|
662
634
|
const opaqueTypes = /* @__PURE__ */ new Set([
|
|
663
635
|
"block",
|
|
664
636
|
"boolean",
|
|
@@ -697,7 +669,7 @@ const opaqueTypes = /* @__PURE__ */ new Set([
|
|
|
697
669
|
slug: /* @__PURE__ */ new Set(["current", "source"])
|
|
698
670
|
};
|
|
699
671
|
/**
|
|
700
|
-
* Checks whether a value is a compiled schema field with a
|
|
672
|
+
* Checks whether a value is a compiled schema field with a type object.
|
|
701
673
|
*
|
|
702
674
|
* @param value - The value to check.
|
|
703
675
|
* @returns True if the value is a compiled field.
|
|
@@ -706,49 +678,49 @@ function isCompiledField(value) {
|
|
|
706
678
|
return !isRecord(value) || !("name" in value) || !("type" in value) ? !1 : isRecord(value.type);
|
|
707
679
|
}
|
|
708
680
|
/**
|
|
709
|
-
* Checks whether a value has a `fields` array
|
|
681
|
+
* Checks whether a value has a `fields` array.
|
|
710
682
|
*
|
|
711
683
|
* @param value - The value to check.
|
|
712
|
-
* @returns True if the value
|
|
684
|
+
* @returns True if the value has a `fields` array.
|
|
713
685
|
*/
|
|
714
686
|
function hasFieldsArray(value) {
|
|
715
687
|
return isRecord(value) && Array.isArray(value.fields);
|
|
716
688
|
}
|
|
717
689
|
/**
|
|
718
|
-
* Checks whether a value has an `of` array
|
|
690
|
+
* Checks whether a value has an `of` array.
|
|
719
691
|
*
|
|
720
692
|
* @param value - The value to check.
|
|
721
|
-
* @returns True if the value
|
|
693
|
+
* @returns True if the value has an `of` array.
|
|
722
694
|
*/
|
|
723
695
|
function hasOfArray(value) {
|
|
724
696
|
return isRecord(value) && Array.isArray(value.of);
|
|
725
697
|
}
|
|
726
698
|
/**
|
|
727
|
-
*
|
|
699
|
+
* Reads the type name a value declares.
|
|
728
700
|
*
|
|
729
|
-
* @param value - The value
|
|
730
|
-
* @returns The type name, or undefined when
|
|
701
|
+
* @param value - The value.
|
|
702
|
+
* @returns The type name, or undefined when there isn't one.
|
|
731
703
|
*/
|
|
732
704
|
function getTypeName(value) {
|
|
733
705
|
let typeName = readPath(value, ["type"]);
|
|
734
706
|
return typeof typeName == "string" ? typeName : void 0;
|
|
735
707
|
}
|
|
736
708
|
/**
|
|
737
|
-
*
|
|
709
|
+
* Reads the parent type name from a compiled schema type.
|
|
738
710
|
*
|
|
739
|
-
* @param resolvedType - The compiled schema type
|
|
740
|
-
* @returns The parent type name, or undefined when
|
|
711
|
+
* @param resolvedType - The compiled schema type.
|
|
712
|
+
* @returns The parent type name, or undefined when there isn't one.
|
|
741
713
|
*/
|
|
742
714
|
function getParentTypeName(resolvedType) {
|
|
743
715
|
let parentName = readPath(resolvedType, ["type", "name"]);
|
|
744
716
|
return isDefined(parentName) ? String(parentName) : void 0;
|
|
745
717
|
}
|
|
746
718
|
/**
|
|
747
|
-
*
|
|
748
|
-
*
|
|
719
|
+
* Converts a compiled schema field into the shape the Handbook renders. Types already seen are tracked,
|
|
720
|
+
* so a type that refers to itself doesn't recurse forever.
|
|
749
721
|
*
|
|
750
|
-
* @param field - A compiled
|
|
751
|
-
* @param visited - Type names already seen
|
|
722
|
+
* @param field - A compiled field or a plain field definition.
|
|
723
|
+
* @param visited - Type names already seen.
|
|
752
724
|
* @returns The normalised field.
|
|
753
725
|
*/
|
|
754
726
|
function normalizeField(field, visited = /* @__PURE__ */ new Set()) {
|
|
@@ -758,7 +730,7 @@ function normalizeField(field, visited = /* @__PURE__ */ new Set()) {
|
|
|
758
730
|
type: typeName,
|
|
759
731
|
title: field.title ?? field.type.title,
|
|
760
732
|
description: field.description ?? field.type.description,
|
|
761
|
-
handbook: field.handbook
|
|
733
|
+
handbook: field.handbook ?? field.type.handbook
|
|
762
734
|
};
|
|
763
735
|
if (!visited.has(typeName)) {
|
|
764
736
|
let next = !opaqueTypes.has(typeName) && typeName !== "object" && typeName !== "array" ? /* @__PURE__ */ new Set([...visited, typeName]) : visited, fieldSource = hasFieldsArray(field) ? field : field.type, ofSource = hasOfArray(field) ? field : field.type;
|
|
@@ -769,12 +741,11 @@ function normalizeField(field, visited = /* @__PURE__ */ new Set()) {
|
|
|
769
741
|
return field;
|
|
770
742
|
}
|
|
771
743
|
/**
|
|
772
|
-
*
|
|
773
|
-
* base type contributes of its own accord.
|
|
744
|
+
* Lists the fields a custom type adds to an opaque base type, leaving out the base type's own.
|
|
774
745
|
*
|
|
775
746
|
* @param resolvedType - The compiled or normalised schema type.
|
|
776
|
-
* @param parentName - The opaque base type name.
|
|
777
|
-
* @returns The custom fields, or undefined when
|
|
747
|
+
* @param parentName - The opaque base type's name.
|
|
748
|
+
* @returns The custom fields, or undefined when there are none.
|
|
778
749
|
*/
|
|
779
750
|
function resolveCustomFields(resolvedType, parentName) {
|
|
780
751
|
if (!hasFieldsArray(resolvedType)) return;
|
|
@@ -782,32 +753,31 @@ function resolveCustomFields(resolvedType, parentName) {
|
|
|
782
753
|
return isDefined(customFields) ? customFields : void 0;
|
|
783
754
|
}
|
|
784
755
|
/**
|
|
785
|
-
* Normalises a list of raw
|
|
756
|
+
* Normalises a list of raw fields.
|
|
786
757
|
*
|
|
787
|
-
* @param items -
|
|
788
|
-
* @returns The normalised fields, or undefined when
|
|
758
|
+
* @param items - The raw fields.
|
|
759
|
+
* @returns The normalised fields, or undefined when there are none.
|
|
789
760
|
*/
|
|
790
761
|
function resolveNormalizedFields(items) {
|
|
791
762
|
let normalized = items.map((item) => normalizeField(item));
|
|
792
763
|
return isDefined(normalized) ? normalized : void 0;
|
|
793
764
|
}
|
|
794
765
|
/**
|
|
795
|
-
* Normalises array members
|
|
766
|
+
* Normalises array members, leaving out opaque types.
|
|
796
767
|
*
|
|
797
|
-
* @param members -
|
|
798
|
-
* @returns The normalised
|
|
768
|
+
* @param members - The raw array members.
|
|
769
|
+
* @returns The normalised members, or undefined when there are none.
|
|
799
770
|
*/
|
|
800
771
|
function resolveNormalizedMembers(members) {
|
|
801
772
|
let normalized = members.map((member) => normalizeField(member)).filter((member) => !opaqueTypes.has(member.type));
|
|
802
773
|
return isDefined(normalized) ? normalized : void 0;
|
|
803
774
|
}
|
|
804
775
|
/**
|
|
805
|
-
*
|
|
806
|
-
* carries nothing but a type name of its own.
|
|
776
|
+
* Works out a value's parent type name, looking it up in the schema when the value only names its type.
|
|
807
777
|
*
|
|
808
|
-
* @param value - The value
|
|
809
|
-
* @param schema - The Sanity schema
|
|
810
|
-
* @returns The parent type name, or undefined when
|
|
778
|
+
* @param value - The value.
|
|
779
|
+
* @param schema - The Sanity schema.
|
|
780
|
+
* @returns The parent type name, or undefined when there isn't one.
|
|
811
781
|
*/
|
|
812
782
|
function resolveParentName(value, schema) {
|
|
813
783
|
let direct = getParentTypeName(value);
|
|
@@ -818,12 +788,12 @@ function resolveParentName(value, schema) {
|
|
|
818
788
|
return isDefined(resolvedType) ? getParentTypeName(resolvedType) : void 0;
|
|
819
789
|
}
|
|
820
790
|
/**
|
|
821
|
-
*
|
|
822
|
-
*
|
|
791
|
+
* Works out the fields a value shows, whether it holds them directly, has array members that do, or
|
|
792
|
+
* names a type that does.
|
|
823
793
|
*
|
|
824
|
-
* @param value - The value
|
|
825
|
-
* @param schema - The Sanity schema
|
|
826
|
-
* @returns The
|
|
794
|
+
* @param value - The value.
|
|
795
|
+
* @param schema - The Sanity schema.
|
|
796
|
+
* @returns The fields, or undefined when there are none.
|
|
827
797
|
*/
|
|
828
798
|
function resolveFields(value, schema) {
|
|
829
799
|
if (hasFieldsArray(value)) {
|
|
@@ -846,11 +816,11 @@ function resolveFields(value, schema) {
|
|
|
846
816
|
}
|
|
847
817
|
}
|
|
848
818
|
/**
|
|
849
|
-
*
|
|
819
|
+
* Works out a field's visible subfields by looking through the schema.
|
|
850
820
|
*
|
|
851
|
-
* @param field - The
|
|
852
|
-
* @param schema - The Sanity schema
|
|
853
|
-
* @returns The
|
|
821
|
+
* @param field - The field.
|
|
822
|
+
* @param schema - The Sanity schema.
|
|
823
|
+
* @returns The subfields, or undefined when there are none.
|
|
854
824
|
*/
|
|
855
825
|
function getSubfields(field, schema) {
|
|
856
826
|
if (opaqueTypes.has(field.type)) return;
|
|
@@ -861,7 +831,7 @@ function getSubfields(field, schema) {
|
|
|
861
831
|
let parentName = getParentTypeName(resolvedType);
|
|
862
832
|
return isDefined(parentName) && opaqueTypes.has(parentName) ? resolveCustomFields(resolvedType, parentName) : resolveFields(resolvedType, schema);
|
|
863
833
|
}
|
|
864
|
-
/** Shared empty
|
|
834
|
+
/** Shared empty set, so the default prop keeps the same reference between renders. */
|
|
865
835
|
const noAncestors = /* @__PURE__ */ new Set();
|
|
866
836
|
function DocumentedField(t0) {
|
|
867
837
|
let $ = c(59), field, props, t1;
|
|
@@ -1014,10 +984,10 @@ function DocumentedField(t0) {
|
|
|
1014
984
|
return t6;
|
|
1015
985
|
}
|
|
1016
986
|
/**
|
|
1017
|
-
* Builds a section for each
|
|
987
|
+
* Builds a sidebar section for each document role.
|
|
1018
988
|
*
|
|
1019
|
-
* @param roles -
|
|
1020
|
-
* @returns One section per role,
|
|
989
|
+
* @param roles - The configured document roles.
|
|
990
|
+
* @returns One section per role, with an entry per document type.
|
|
1021
991
|
*/
|
|
1022
992
|
function documentTypesSections(roles) {
|
|
1023
993
|
return roles.map(({ title, documents }) => ({
|
|
@@ -1193,11 +1163,11 @@ function DocumentTypesOverview() {
|
|
|
1193
1163
|
children: t1
|
|
1194
1164
|
}), $[8] = t1, $[9] = t2), t2;
|
|
1195
1165
|
}
|
|
1196
|
-
/** What each hint kind
|
|
1166
|
+
/** What each hint kind means, shown next to its icon as a key. */
|
|
1197
1167
|
const hintDescriptions = {
|
|
1198
|
-
tip: "
|
|
1199
|
-
info: "
|
|
1200
|
-
caution: "
|
|
1168
|
+
tip: "Tips and suggested practices for people editing content.",
|
|
1169
|
+
info: "More detail about how and where the field is used.",
|
|
1170
|
+
caution: "Warnings about restrictions or problems the field can cause."
|
|
1201
1171
|
};
|
|
1202
1172
|
function HowToUse() {
|
|
1203
1173
|
let $ = c(8), t0;
|
|
@@ -1220,7 +1190,7 @@ function HowToUse() {
|
|
|
1220
1190
|
}), /* @__PURE__ */ jsx(Text, {
|
|
1221
1191
|
size: 1,
|
|
1222
1192
|
muted: !0,
|
|
1223
|
-
children: "The sidebar lists everything the Handbook
|
|
1193
|
+
children: "The sidebar lists everything in the Handbook: these introductory pages first, then the document types you can create, grouped by their role on the site, and then any guides your team has written. Select an entry to open it here."
|
|
1224
1194
|
})]
|
|
1225
1195
|
}), $[1] = t1) : t1 = $[1];
|
|
1226
1196
|
let t2;
|
|
@@ -1237,7 +1207,7 @@ function HowToUse() {
|
|
|
1237
1207
|
}), /* @__PURE__ */ jsx(Text, {
|
|
1238
1208
|
size: 1,
|
|
1239
1209
|
muted: !0,
|
|
1240
|
-
children: "Selecting a document type lists its fields, each
|
|
1210
|
+
children: "Selecting a document type lists its fields, with each field’s name, the kind of value it holds, and what it’s for. This documentation is generated from the content model, so it always matches what you see in the editor."
|
|
1241
1211
|
})]
|
|
1242
1212
|
}), $[2] = t2) : t2 = $[2];
|
|
1243
1213
|
let t3, t4;
|
|
@@ -1252,7 +1222,7 @@ function HowToUse() {
|
|
|
1252
1222
|
}), t4 = /* @__PURE__ */ jsx(Text, {
|
|
1253
1223
|
size: 1,
|
|
1254
1224
|
muted: !0,
|
|
1255
|
-
children: "Icons
|
|
1225
|
+
children: "Icons next to a field’s name hold extra guidance that would make its description too long. Hover over or click an icon to read it, and use the key below to see what each icon means."
|
|
1256
1226
|
}), $[3] = t3, $[4] = t4) : (t3 = $[3], t4 = $[4]);
|
|
1257
1227
|
let t5;
|
|
1258
1228
|
$[5] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsxs(Stack, {
|
|
@@ -1281,7 +1251,7 @@ function HowToUse() {
|
|
|
1281
1251
|
}), /* @__PURE__ */ jsx(Text, {
|
|
1282
1252
|
size: 1,
|
|
1283
1253
|
muted: !0,
|
|
1284
|
-
children: "Some fields
|
|
1254
|
+
children: "Some fields contain subfields, such as a content block with a heading and body text. A button below the description shows how many there are and expands to list them, each documented like any other field."
|
|
1285
1255
|
})]
|
|
1286
1256
|
}), $[6] = t6) : t6 = $[6];
|
|
1287
1257
|
let t7;
|
|
@@ -1305,7 +1275,7 @@ function HowToUse() {
|
|
|
1305
1275
|
}), /* @__PURE__ */ jsx(Text, {
|
|
1306
1276
|
size: 1,
|
|
1307
1277
|
muted: !0,
|
|
1308
|
-
children: "
|
|
1278
|
+
children: "Below the document types, you may find guides written by your team rather than generated from the content model. They cover things a field description can’t, such as house style, editorial process, and how everything fits together."
|
|
1309
1279
|
})]
|
|
1310
1280
|
})
|
|
1311
1281
|
]
|
|
@@ -1332,9 +1302,9 @@ function _temp$3(t0) {
|
|
|
1332
1302
|
}, name);
|
|
1333
1303
|
}
|
|
1334
1304
|
/**
|
|
1335
|
-
* Builds the section
|
|
1305
|
+
* Builds the section for the plugin's introductory pages.
|
|
1336
1306
|
*
|
|
1337
|
-
* @returns
|
|
1307
|
+
* @returns One section listing the built-in pages.
|
|
1338
1308
|
*/
|
|
1339
1309
|
function gettingStartedSections() {
|
|
1340
1310
|
return [{
|
|
@@ -1342,19 +1312,19 @@ function gettingStartedSections() {
|
|
|
1342
1312
|
entries: [{
|
|
1343
1313
|
id: "how-to-use-this-handbook",
|
|
1344
1314
|
title: "How to use the Handbook",
|
|
1345
|
-
description: "
|
|
1315
|
+
description: "How to find your way around the Handbook, read the documentation for each field, and understand its examples, hints, and subfields.",
|
|
1346
1316
|
icon: createSanityIcon(BookTextIcon),
|
|
1347
1317
|
render: () => /* @__PURE__ */ jsx(HowToUse, {})
|
|
1348
1318
|
}, {
|
|
1349
1319
|
id: "document-types",
|
|
1350
1320
|
title: "Document Types",
|
|
1351
|
-
description: "
|
|
1321
|
+
description: "A list of every document type, grouped by role. Select a document type to see its fields, descriptions, and examples.",
|
|
1352
1322
|
icon: createSanityIcon(LayoutGridIcon),
|
|
1353
1323
|
render: () => /* @__PURE__ */ jsx(DocumentTypesOverview, {})
|
|
1354
1324
|
}]
|
|
1355
1325
|
}];
|
|
1356
1326
|
}
|
|
1357
|
-
/**
|
|
1327
|
+
/** Icon and tone for each callout variant. */
|
|
1358
1328
|
const presentation = {
|
|
1359
1329
|
tip: {
|
|
1360
1330
|
icon: LightbulbIcon,
|
|
@@ -1442,7 +1412,7 @@ function PortableLink(t0) {
|
|
|
1442
1412
|
children
|
|
1443
1413
|
}), $[6] = children, $[7] = props, $[8] = t1, $[9] = t2) : t2 = $[9], t2;
|
|
1444
1414
|
}
|
|
1445
|
-
/** Overrides for
|
|
1415
|
+
/** Overrides for callout text, which uses the card's own text style and doesn't wrap paragraphs. */
|
|
1446
1416
|
const components$1 = {
|
|
1447
1417
|
block: { normal: ({ children }) => /* @__PURE__ */ jsx(Fragment, { children }) },
|
|
1448
1418
|
marks: {
|
|
@@ -1720,18 +1690,17 @@ function PortableParagraph(props) {
|
|
|
1720
1690
|
}), $[0] = props, $[1] = t0), t0;
|
|
1721
1691
|
}
|
|
1722
1692
|
/**
|
|
1723
|
-
*
|
|
1693
|
+
* Works out the vertical space around a list, which is smaller for nested lists.
|
|
1724
1694
|
*
|
|
1725
|
-
* @param level - Nesting depth
|
|
1726
|
-
* @returns The
|
|
1695
|
+
* @param level - Nesting depth, starting at 1.
|
|
1696
|
+
* @returns The space in pixels.
|
|
1727
1697
|
*/
|
|
1728
1698
|
function listSpacing(level) {
|
|
1729
1699
|
return level > 1 ? contentSpacing.nestedList : contentSpacing.list;
|
|
1730
1700
|
}
|
|
1731
1701
|
/**
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1734
|
-
* as the surrounding text.
|
|
1702
|
+
* Components for each block style, mark, and embedded type in a guide. Marks and list items not listed
|
|
1703
|
+
* here are left to the library's defaults on purpose.
|
|
1735
1704
|
*/
|
|
1736
1705
|
const components = {
|
|
1737
1706
|
block: {
|
|
@@ -1777,10 +1746,10 @@ const components = {
|
|
|
1777
1746
|
}
|
|
1778
1747
|
};
|
|
1779
1748
|
/**
|
|
1780
|
-
*
|
|
1781
|
-
*
|
|
1749
|
+
* Wraps a block component for Portable Text, passing only the block's value. Otherwise the library's
|
|
1750
|
+
* other props would reach the DOM.
|
|
1782
1751
|
*
|
|
1783
|
-
* @param Component -
|
|
1752
|
+
* @param Component - The block component.
|
|
1784
1753
|
* @returns A component Portable Text can render the type with.
|
|
1785
1754
|
*/
|
|
1786
1755
|
function blockRenderer(Component) {
|
|
@@ -1855,15 +1824,15 @@ function BookOpenTextIcon(props) {
|
|
|
1855
1824
|
}), $[6] = props, $[7] = t6), t6;
|
|
1856
1825
|
}
|
|
1857
1826
|
/**
|
|
1858
|
-
* Builds a section for each guide group
|
|
1827
|
+
* Builds a sidebar section for each guide group.
|
|
1859
1828
|
*
|
|
1860
|
-
* @param handbook - Handbook
|
|
1861
|
-
* @returns One section per group,
|
|
1829
|
+
* @param handbook - The Handbook document.
|
|
1830
|
+
* @returns One section per group, with an entry per published guide.
|
|
1862
1831
|
*/
|
|
1863
1832
|
function guidesSections(handbook) {
|
|
1864
|
-
return handbook.groups.map(({ title, guides }) => ({
|
|
1833
|
+
return (handbook.groups ?? []).map(({ title, guides }) => ({
|
|
1865
1834
|
title,
|
|
1866
|
-
entries: guides.map((guide) => ({
|
|
1835
|
+
entries: (guides ?? []).filter((guide) => isDefined(guide.title)).map((guide) => ({
|
|
1867
1836
|
id: guide._key,
|
|
1868
1837
|
title: guide.title,
|
|
1869
1838
|
description: guide.description,
|
|
@@ -1873,17 +1842,17 @@ function guidesSections(handbook) {
|
|
|
1873
1842
|
}));
|
|
1874
1843
|
}
|
|
1875
1844
|
/**
|
|
1876
|
-
*
|
|
1845
|
+
* Lists every page in the Handbook, in sidebar order.
|
|
1877
1846
|
*
|
|
1878
|
-
* @returns
|
|
1847
|
+
* @returns The built-in pages, the configured document roles, and the guide groups, as sections.
|
|
1879
1848
|
*/
|
|
1880
1849
|
function useSections() {
|
|
1881
|
-
let $ = c(
|
|
1882
|
-
return $[0] !== handbook || $[1] !==
|
|
1850
|
+
let $ = c(3), { roles, handbook } = useHandbookContext(), t0;
|
|
1851
|
+
return $[0] !== handbook || $[1] !== roles ? (t0 = [
|
|
1883
1852
|
...gettingStartedSections(),
|
|
1884
1853
|
...documentTypesSections(roles),
|
|
1885
|
-
...
|
|
1886
|
-
], $[0] = handbook, $[1] =
|
|
1854
|
+
...isDefined(handbook) ? guidesSections(handbook) : []
|
|
1855
|
+
], $[0] = handbook, $[1] = roles, $[2] = t0) : t0 = $[2], t0;
|
|
1887
1856
|
}
|
|
1888
1857
|
function Content(props) {
|
|
1889
1858
|
let $ = c(18), { activeTab } = useHandbookContext(), sections = useSections(), T0, t0, t1, t2, t3, t4;
|
|
@@ -2094,23 +2063,23 @@ function HandbookTool(t0) {
|
|
|
2094
2063
|
children: t7
|
|
2095
2064
|
}), $[7] = options, $[8] = t7, $[9] = t8) : t8 = $[9], t8;
|
|
2096
2065
|
}
|
|
2097
|
-
/** Editors the plugin
|
|
2066
|
+
/** Editors from the plugin configuration, so the structure helper doesn't need them passed again. */
|
|
2098
2067
|
let configuredEditors;
|
|
2099
2068
|
/**
|
|
2100
|
-
*
|
|
2101
|
-
*
|
|
2069
|
+
* Stores the editors from the plugin configuration. A Studio with several workspaces keeps only the last
|
|
2070
|
+
* workspace's list, so pass the list explicitly there.
|
|
2102
2071
|
*
|
|
2103
|
-
* @param editors - Email addresses
|
|
2072
|
+
* @param editors - Email addresses of the editors.
|
|
2104
2073
|
*/
|
|
2105
2074
|
function setConfiguredEditors(editors) {
|
|
2106
2075
|
configuredEditors = editors;
|
|
2107
2076
|
}
|
|
2108
2077
|
/**
|
|
2109
|
-
* Checks whether an email address
|
|
2078
|
+
* Checks whether an email address belongs to an editor. Without an editors list, everyone is an editor.
|
|
2110
2079
|
*
|
|
2111
|
-
* @param editors - Email addresses
|
|
2080
|
+
* @param editors - Email addresses of the editors, defaulting to the configured list.
|
|
2112
2081
|
* @param email - The email address to check.
|
|
2113
|
-
* @returns Whether the
|
|
2082
|
+
* @returns Whether the address belongs to an editor.
|
|
2114
2083
|
*/
|
|
2115
2084
|
function isPermittedEditor(editors, email) {
|
|
2116
2085
|
let permitted = editors ?? configuredEditors;
|
|
@@ -2208,7 +2177,7 @@ const linkAnnotation = defineArrayMember({
|
|
|
2208
2177
|
name: "href",
|
|
2209
2178
|
type: "url",
|
|
2210
2179
|
title: "URL",
|
|
2211
|
-
description: "Web address
|
|
2180
|
+
description: "Web address to link to. Use http, https, mailto, or tel.",
|
|
2212
2181
|
validation: (rule) => rule.uri({ scheme: [
|
|
2213
2182
|
"http",
|
|
2214
2183
|
"https",
|
|
@@ -2220,7 +2189,7 @@ const linkAnnotation = defineArrayMember({
|
|
|
2220
2189
|
name: calloutTypeName,
|
|
2221
2190
|
type: "object",
|
|
2222
2191
|
title: "Callout",
|
|
2223
|
-
description: "Highlighted
|
|
2192
|
+
description: "Highlighted tip, note, or warning.",
|
|
2224
2193
|
icon: createSanityIcon(MessageCircleIcon),
|
|
2225
2194
|
components: { preview: CalloutPreview },
|
|
2226
2195
|
preview: {
|
|
@@ -2240,7 +2209,7 @@ const linkAnnotation = defineArrayMember({
|
|
|
2240
2209
|
fields: [defineField({
|
|
2241
2210
|
name: "variant",
|
|
2242
2211
|
type: "string",
|
|
2243
|
-
description: "
|
|
2212
|
+
description: "Kind of callout, which sets its icon and color.",
|
|
2244
2213
|
initialValue: "tip",
|
|
2245
2214
|
validation: (rule) => rule.required(),
|
|
2246
2215
|
options: {
|
|
@@ -2264,7 +2233,7 @@ const linkAnnotation = defineArrayMember({
|
|
|
2264
2233
|
}), defineField({
|
|
2265
2234
|
name: "body",
|
|
2266
2235
|
type: "array",
|
|
2267
|
-
description: "
|
|
2236
|
+
description: "Text inside the callout, with inline formatting and links.",
|
|
2268
2237
|
of: [defineArrayMember({
|
|
2269
2238
|
name: "block",
|
|
2270
2239
|
type: "block",
|
|
@@ -2330,7 +2299,7 @@ const codeType = defineType({
|
|
|
2330
2299
|
name: codeTypeName,
|
|
2331
2300
|
type: "object",
|
|
2332
2301
|
title: "Code",
|
|
2333
|
-
description: "
|
|
2302
|
+
description: "Code block with syntax highlighting.",
|
|
2334
2303
|
icon: createSanityIcon(CodeIcon),
|
|
2335
2304
|
components: { preview: CodePreview },
|
|
2336
2305
|
preview: { select: {
|
|
@@ -2340,11 +2309,11 @@ const codeType = defineType({
|
|
|
2340
2309
|
fields: [defineField({
|
|
2341
2310
|
name: "code",
|
|
2342
2311
|
type: "text",
|
|
2343
|
-
description: "
|
|
2312
|
+
description: "Code to display."
|
|
2344
2313
|
}), defineField({
|
|
2345
2314
|
name: "language",
|
|
2346
2315
|
type: "string",
|
|
2347
|
-
description: "
|
|
2316
|
+
description: "Language used for syntax highlighting.",
|
|
2348
2317
|
options: { list: [
|
|
2349
2318
|
{
|
|
2350
2319
|
title: "CSS",
|
|
@@ -2415,7 +2384,7 @@ const horizontalRuleType = defineType({
|
|
|
2415
2384
|
name: horizontalRuleTypeName,
|
|
2416
2385
|
type: "object",
|
|
2417
2386
|
title: "Horizontal Rule",
|
|
2418
|
-
description: "
|
|
2387
|
+
description: "Divider between sections.",
|
|
2419
2388
|
icon: createSanityIcon(SeparatorHorizontalIcon),
|
|
2420
2389
|
components: { preview: HorizontalRulePreview },
|
|
2421
2390
|
preview: { prepare() {
|
|
@@ -2424,7 +2393,7 @@ const horizontalRuleType = defineType({
|
|
|
2424
2393
|
fields: [defineField({
|
|
2425
2394
|
name: "style",
|
|
2426
2395
|
type: "string",
|
|
2427
|
-
description: "
|
|
2396
|
+
description: "Unused placeholder field.",
|
|
2428
2397
|
hidden: !0
|
|
2429
2398
|
})]
|
|
2430
2399
|
});
|
|
@@ -2491,19 +2460,19 @@ const imageType = defineType({
|
|
|
2491
2460
|
name: "asset",
|
|
2492
2461
|
type: "image",
|
|
2493
2462
|
title: "Image",
|
|
2494
|
-
description: "
|
|
2463
|
+
description: "Image to show.",
|
|
2495
2464
|
options: { hotspot: !0 }
|
|
2496
2465
|
}),
|
|
2497
2466
|
defineField({
|
|
2498
2467
|
name: "caption",
|
|
2499
2468
|
type: "string",
|
|
2500
|
-
description: "
|
|
2469
|
+
description: "Text shown below the image, such as a credit."
|
|
2501
2470
|
}),
|
|
2502
2471
|
defineField({
|
|
2503
2472
|
name: "alt",
|
|
2504
2473
|
type: "string",
|
|
2505
2474
|
title: "Alternative Text",
|
|
2506
|
-
description: "
|
|
2475
|
+
description: "Description of the image for people who can't see it. Don't repeat the caption."
|
|
2507
2476
|
})
|
|
2508
2477
|
]
|
|
2509
2478
|
});
|
|
@@ -2567,12 +2536,12 @@ const videoType = defineType({
|
|
|
2567
2536
|
name: "asset",
|
|
2568
2537
|
type: "file",
|
|
2569
2538
|
title: "Video",
|
|
2570
|
-
description: "
|
|
2539
|
+
description: "Video to show.",
|
|
2571
2540
|
options: { accept: "video/*" }
|
|
2572
2541
|
}), defineField({
|
|
2573
2542
|
name: "caption",
|
|
2574
2543
|
type: "string",
|
|
2575
|
-
description: "
|
|
2544
|
+
description: "Text shown below the video, such as a credit."
|
|
2576
2545
|
})]
|
|
2577
2546
|
});
|
|
2578
2547
|
function ListItemStyle(t0) {
|
|
@@ -2586,11 +2555,10 @@ function ListItemStyle(t0) {
|
|
|
2586
2555
|
}), $[1] = children, $[2] = t2), t2;
|
|
2587
2556
|
}
|
|
2588
2557
|
/**
|
|
2589
|
-
* Creates the
|
|
2590
|
-
* any a consumer registered.
|
|
2558
|
+
* Creates the guide content field, offering the built-in blocks and any custom ones.
|
|
2591
2559
|
*
|
|
2592
|
-
* @param customBlocks - Custom
|
|
2593
|
-
* @returns
|
|
2560
|
+
* @param customBlocks - Custom blocks added by the site.
|
|
2561
|
+
* @returns The content field.
|
|
2594
2562
|
*/
|
|
2595
2563
|
function createGuideContentField(customBlocks = []) {
|
|
2596
2564
|
return defineField({
|
|
@@ -2678,43 +2646,33 @@ function createGuideContentField(customBlocks = []) {
|
|
|
2678
2646
|
});
|
|
2679
2647
|
}
|
|
2680
2648
|
/**
|
|
2681
|
-
* Creates the document type a
|
|
2682
|
-
* built-in blocks alongside any a consumer registered.
|
|
2649
|
+
* Creates the guide document type, with a content field offering the built-in blocks and any custom ones.
|
|
2683
2650
|
*
|
|
2684
|
-
* @param customBlocks - Custom
|
|
2685
|
-
* @returns
|
|
2651
|
+
* @param customBlocks - Custom blocks added by the site.
|
|
2652
|
+
* @returns The guide document type.
|
|
2686
2653
|
*/
|
|
2687
2654
|
function createGuideType(customBlocks = []) {
|
|
2688
2655
|
return defineType({
|
|
2689
2656
|
name: guideTypeName,
|
|
2690
2657
|
type: "document",
|
|
2691
2658
|
title: "Handbook Guide",
|
|
2692
|
-
description: "Handbook page
|
|
2659
|
+
description: "Handbook page written in rich text.",
|
|
2693
2660
|
icon: createSanityIcon(BookOpenTextIcon),
|
|
2694
|
-
preview: {
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
},
|
|
2699
|
-
prepare(selection) {
|
|
2700
|
-
let { title, description } = selection;
|
|
2701
|
-
return {
|
|
2702
|
-
title: title ?? "Untitled",
|
|
2703
|
-
subtitle: description
|
|
2704
|
-
};
|
|
2705
|
-
}
|
|
2706
|
-
},
|
|
2661
|
+
preview: { select: {
|
|
2662
|
+
title: "title",
|
|
2663
|
+
subtitle: "description"
|
|
2664
|
+
} },
|
|
2707
2665
|
fields: [
|
|
2708
2666
|
defineField({
|
|
2709
2667
|
name: "title",
|
|
2710
2668
|
type: "string",
|
|
2711
|
-
description: "
|
|
2669
|
+
description: "Title shown in the Handbook sidebar and as the guide heading.",
|
|
2712
2670
|
validation: (rule) => rule.required()
|
|
2713
2671
|
}),
|
|
2714
2672
|
defineField({
|
|
2715
2673
|
name: "description",
|
|
2716
2674
|
type: "string",
|
|
2717
|
-
description: "Short introduction
|
|
2675
|
+
description: "Short introduction shown below the heading."
|
|
2718
2676
|
}),
|
|
2719
2677
|
createGuideContentField(customBlocks)
|
|
2720
2678
|
]
|
|
@@ -2748,7 +2706,7 @@ const handbookType = defineType({
|
|
|
2748
2706
|
name: handbookTypeName,
|
|
2749
2707
|
type: "document",
|
|
2750
2708
|
title: "Handbook",
|
|
2751
|
-
description: "
|
|
2709
|
+
description: "Groups of guides shown in the Handbook sidebar, in order.",
|
|
2752
2710
|
icon: createSanityIcon(BookTextIcon),
|
|
2753
2711
|
preview: { prepare() {
|
|
2754
2712
|
return { title: "Handbook" };
|
|
@@ -2756,21 +2714,21 @@ const handbookType = defineType({
|
|
|
2756
2714
|
fields: [defineField({
|
|
2757
2715
|
name: "groups",
|
|
2758
2716
|
type: "array",
|
|
2759
|
-
description: "
|
|
2717
|
+
description: "Groups of guides shown in the Handbook sidebar, in order. Each group has a title and a list of guides, also in order.",
|
|
2760
2718
|
of: [defineArrayMember({
|
|
2761
2719
|
name: "group",
|
|
2762
2720
|
type: "object",
|
|
2763
|
-
description: "
|
|
2721
|
+
description: "Sidebar section holding a list of guides.",
|
|
2764
2722
|
icon: createSanityIcon(ListPlusIcon),
|
|
2765
2723
|
fields: [defineField({
|
|
2766
2724
|
name: "title",
|
|
2767
2725
|
type: "string",
|
|
2768
|
-
description: "Heading
|
|
2726
|
+
description: "Heading shown above the group in the sidebar.",
|
|
2769
2727
|
validation: (rule) => rule.required()
|
|
2770
2728
|
}), defineField({
|
|
2771
2729
|
name: "guides",
|
|
2772
2730
|
type: "array",
|
|
2773
|
-
description: "
|
|
2731
|
+
description: "Guides in the group, in order. Drag to reorder.",
|
|
2774
2732
|
of: [defineArrayMember({
|
|
2775
2733
|
name: "guide",
|
|
2776
2734
|
type: "reference",
|
|
@@ -2782,16 +2740,17 @@ const handbookType = defineType({
|
|
|
2782
2740
|
title: "title",
|
|
2783
2741
|
guide0: "guides.0.title",
|
|
2784
2742
|
guide1: "guides.1.title",
|
|
2785
|
-
guide2: "guides.2.title"
|
|
2743
|
+
guide2: "guides.2.title",
|
|
2744
|
+
guide3: "guides.3.title"
|
|
2786
2745
|
},
|
|
2787
2746
|
prepare(selection) {
|
|
2788
|
-
let { title, guide0, guide1, guide2 } = selection, shown = [
|
|
2747
|
+
let { title, guide0, guide1, guide2, guide3 } = selection, shown = [
|
|
2789
2748
|
guide0,
|
|
2790
2749
|
guide1,
|
|
2791
2750
|
guide2
|
|
2792
|
-
].filter((guide) => isDefined(guide))
|
|
2751
|
+
].filter((guide) => isDefined(guide));
|
|
2793
2752
|
function formatSubtitle() {
|
|
2794
|
-
return isDefined(shown) ?
|
|
2753
|
+
return isDefined(shown) ? isDefined(guide3) ? `${shown.slice(0, 2).join(", ")}, and others` : new Intl.ListFormat("en-US").format(shown) : "No guides selected";
|
|
2795
2754
|
}
|
|
2796
2755
|
return {
|
|
2797
2756
|
title: title ?? "Group",
|
|
@@ -2808,7 +2767,7 @@ const handbookType = defineType({
|
|
|
2808
2767
|
sidebarTitle: sidebarTitle ?? "Handbook",
|
|
2809
2768
|
roles,
|
|
2810
2769
|
blocks: blocks ?? [],
|
|
2811
|
-
undocumentedFieldMessage: undocumentedFieldMessage ?? "This field
|
|
2770
|
+
undocumentedFieldMessage: undocumentedFieldMessage ?? "This field isn't documented yet. Ask your development team for guidance."
|
|
2812
2771
|
}, guideType = createGuideType(resolved.blocks);
|
|
2813
2772
|
return {
|
|
2814
2773
|
name: pluginName,
|
|
@@ -2844,25 +2803,26 @@ const handbookType = defineType({
|
|
|
2844
2803
|
};
|
|
2845
2804
|
});
|
|
2846
2805
|
/**
|
|
2847
|
-
* Creates
|
|
2848
|
-
* not permitted to edit them.
|
|
2806
|
+
* Creates Structure tool items for the Handbook documents, or none when the current user can't edit them.
|
|
2849
2807
|
*
|
|
2850
|
-
* @param structureBuilder - The
|
|
2851
|
-
* @param context - The
|
|
2852
|
-
* @param editors - Email addresses
|
|
2853
|
-
* @returns
|
|
2808
|
+
* @param structureBuilder - The structure builder.
|
|
2809
|
+
* @param context - The structure context, with the current user.
|
|
2810
|
+
* @param editors - Email addresses of the editors, defaulting to the configured list.
|
|
2811
|
+
* @returns List items for the Handbook document and the guides list, oldest guide first.
|
|
2854
2812
|
* @public
|
|
2855
2813
|
*/
|
|
2856
2814
|
function handbookStructure(structureBuilder, context, editors) {
|
|
2857
2815
|
if (!isPermittedEditor(editors, context.currentUser?.email)) return [];
|
|
2858
2816
|
let { listItem, document, documentTypeList } = structureBuilder;
|
|
2859
|
-
return [listItem().title("Handbook").icon(createSanityIcon(BookTextIcon)).child(document().id(handbookTypeName).schemaType(handbookTypeName).title("Handbook")), listItem().title("Handbook Guides").icon(createSanityIcon(BookOpenTextIcon)).child(documentTypeList(guideTypeName).title("Handbook Guides")
|
|
2817
|
+
return [listItem().title("Handbook").icon(createSanityIcon(BookTextIcon)).child(document().id(handbookTypeName).schemaType(handbookTypeName).title("Handbook")), listItem().title("Handbook Guides").icon(createSanityIcon(BookOpenTextIcon)).child(documentTypeList(guideTypeName).title("Handbook Guides").defaultOrdering([{
|
|
2818
|
+
field: "_createdAt",
|
|
2819
|
+
direction: "asc"
|
|
2820
|
+
}]))];
|
|
2860
2821
|
}
|
|
2861
2822
|
/**
|
|
2862
|
-
* Checks whether the current user
|
|
2863
|
-
* unrestricted access.
|
|
2823
|
+
* Checks whether the current user can edit Handbook documents. Without an editors list, everyone can.
|
|
2864
2824
|
*
|
|
2865
|
-
* @param editors - Email addresses
|
|
2825
|
+
* @param editors - Email addresses of the editors, defaulting to the configured list.
|
|
2866
2826
|
* @returns Whether the current user can edit Handbook documents.
|
|
2867
2827
|
* @public
|
|
2868
2828
|
*/
|