bsmnt 0.5.0 → 0.6.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.
Files changed (123) hide show
  1. package/README.md +1 -0
  2. package/dist/application/add-hooks/index.d.ts.map +1 -1
  3. package/dist/application/add-hooks/index.js +1 -0
  4. package/dist/application/add-hooks/index.js.map +1 -1
  5. package/dist/application/add-integration/index.d.ts +13 -6
  6. package/dist/application/add-integration/index.d.ts.map +1 -1
  7. package/dist/application/add-integration/index.js +145 -62
  8. package/dist/application/add-integration/index.js.map +1 -1
  9. package/dist/application/create-project/build-context.d.ts +3 -1
  10. package/dist/application/create-project/build-context.d.ts.map +1 -1
  11. package/dist/application/create-project/build-context.js +2 -1
  12. package/dist/application/create-project/build-context.js.map +1 -1
  13. package/dist/application/create-project/index.d.ts +3 -1
  14. package/dist/application/create-project/index.d.ts.map +1 -1
  15. package/dist/application/create-project/index.js +4 -2
  16. package/dist/application/create-project/index.js.map +1 -1
  17. package/dist/application/install-skills/index.js +1 -1
  18. package/dist/application/install-skills/index.js.map +1 -1
  19. package/dist/core/create/execute-plan.d.ts +4 -0
  20. package/dist/core/create/execute-plan.d.ts.map +1 -1
  21. package/dist/core/create/execute-plan.js +8 -0
  22. package/dist/core/create/execute-plan.js.map +1 -1
  23. package/dist/core/create/types.d.ts +2 -0
  24. package/dist/core/create/types.d.ts.map +1 -1
  25. package/dist/domain/skills.d.ts +26 -0
  26. package/dist/domain/skills.d.ts.map +1 -1
  27. package/dist/domain/skills.js +13 -0
  28. package/dist/domain/skills.js.map +1 -1
  29. package/dist/index.js +26 -8
  30. package/dist/index.js.map +1 -1
  31. package/dist/infrastructure/create/executor.d.ts.map +1 -1
  32. package/dist/infrastructure/create/executor.js +5 -0
  33. package/dist/infrastructure/create/executor.js.map +1 -1
  34. package/dist/infrastructure/create/lifecycle-registry.d.ts.map +1 -1
  35. package/dist/infrastructure/create/lifecycle-registry.js +2 -0
  36. package/dist/infrastructure/create/lifecycle-registry.js.map +1 -1
  37. package/dist/infrastructure/create/setup-agent.d.ts +2 -0
  38. package/dist/infrastructure/create/setup-agent.d.ts.map +1 -1
  39. package/dist/infrastructure/create/setup-agent.js +9 -8
  40. package/dist/infrastructure/create/setup-agent.js.map +1 -1
  41. package/dist/infrastructure/create/setup-dotenvx.d.ts +41 -0
  42. package/dist/infrastructure/create/setup-dotenvx.d.ts.map +1 -0
  43. package/dist/infrastructure/create/setup-dotenvx.js +502 -0
  44. package/dist/infrastructure/create/setup-dotenvx.js.map +1 -0
  45. package/dist/infrastructure/create/setup-sanity.d.ts +13 -1
  46. package/dist/infrastructure/create/setup-sanity.d.ts.map +1 -1
  47. package/dist/infrastructure/create/setup-sanity.js +71 -31
  48. package/dist/infrastructure/create/setup-sanity.js.map +1 -1
  49. package/dist/modules/features/cms/sanity/config.d.ts.map +1 -1
  50. package/dist/modules/features/cms/sanity/config.js +2 -1
  51. package/dist/modules/features/cms/sanity/config.js.map +1 -1
  52. package/dist/modules/features/cms/sanity/mergers/layout.d.ts.map +1 -1
  53. package/dist/modules/features/cms/sanity/mergers/layout.js +10 -0
  54. package/dist/modules/features/cms/sanity/mergers/layout.js.map +1 -1
  55. package/dist/modules/features/env/dotenvx/config.d.ts +13 -0
  56. package/dist/modules/features/env/dotenvx/config.d.ts.map +1 -0
  57. package/dist/modules/features/env/dotenvx/config.js +47 -0
  58. package/dist/modules/features/env/dotenvx/config.js.map +1 -0
  59. package/dist/paths.d.ts +8 -0
  60. package/dist/paths.d.ts.map +1 -1
  61. package/dist/paths.js +8 -0
  62. package/dist/paths.js.map +1 -1
  63. package/package.json +5 -1
  64. package/src/agent-skills/json-ld/SKILL.md +85 -0
  65. package/src/agent-skills/manage-env/SKILL.md +67 -0
  66. package/src/modules/features/cms/sanity/files/app/blog/[slug]/page.tsx +48 -21
  67. package/src/modules/features/cms/sanity/files/components/sanity/structured-data.tsx +83 -0
  68. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/queries.ts +14 -0
  69. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/sanity.config.ts +19 -3
  70. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/sanity.types.ts +1 -0
  71. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/index.ts +36 -1
  72. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/metadata.ts +12 -1
  73. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/structured-data-blocks.ts +416 -0
  74. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/structured-data.ts +100 -0
  75. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/structure.ts +37 -2
  76. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/utils/page-json-ld.ts +208 -0
  77. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/same-as-input.tsx +66 -0
  78. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/layout.ts +20 -1
  79. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/icons.ts +17 -0
  80. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +22 -0
  81. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/index.ts +28 -0
  82. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/company-data.ts +8 -0
  83. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/structured-data.ts +124 -0
  84. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/metadata.ts +12 -1
  85. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/structured-data-blocks.ts +436 -0
  86. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/singletons.ts +13 -1
  87. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/page-json-ld.ts +208 -0
  88. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/json-ld.tsx +324 -15
  89. package/src/modules/features/env/dotenvx/files/decrypt-env.mjs +45 -0
  90. package/src/modules/features/env/dotenvx/files/gitleaks.yml +25 -0
  91. package/src/modules/features/env/dotenvx/files/instrumentation.ts +14 -0
  92. package/src/modules/features/env/dotenvx/files/push-keys.mjs +129 -0
  93. package/src/modules/features/env/dotenvx/files/save-key.mjs +108 -0
  94. package/src/modules/features/env/dotenvx/files/setup-env.mjs +67 -0
  95. package/src/modules/features/env/dotenvx/files/vercelignore +4 -0
  96. package/src/modules/features/env/dotenvx/files/write-env.mjs +47 -0
  97. package/src/templates/next-default/.env.example +14 -6
  98. package/src/templates/next-default/.github/workflows/ci.yml +22 -1
  99. package/src/templates/next-default/.vscode/extensions.json +3 -0
  100. package/src/templates/next-default/README.md +31 -0
  101. package/src/templates/next-default/lib/utils/json-ld.tsx +327 -21
  102. package/src/templates/next-default/next.config.ts +6 -0
  103. package/src/templates/next-experiments/.env.example +14 -6
  104. package/src/templates/next-experiments/.github/workflows/ci.yml +22 -1
  105. package/src/templates/next-experiments/.vscode/extensions.json +3 -0
  106. package/src/templates/next-experiments/README.md +31 -0
  107. package/src/templates/next-experiments/lib/utils/json-ld.tsx +327 -21
  108. package/src/templates/next-experiments/next.config.ts +6 -0
  109. package/src/templates/next-pagebuilder/.env.example +19 -1
  110. package/src/templates/next-pagebuilder/.github/workflows/ci.yml +21 -1
  111. package/src/templates/next-pagebuilder/.vscode/extensions.json +3 -0
  112. package/src/templates/next-pagebuilder/README.md +31 -0
  113. package/src/templates/next-pagebuilder/components/layout/json-ld/index.tsx +32 -19
  114. package/src/templates/next-pagebuilder/components/page-document/index.tsx +38 -0
  115. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +36 -2
  116. package/src/templates/next-pagebuilder/next.config.ts +6 -0
  117. package/src/templates/next-webgl/.env.example +14 -6
  118. package/src/templates/next-webgl/.github/workflows/ci.yml +22 -1
  119. package/src/templates/next-webgl/.vscode/extensions.json +3 -0
  120. package/src/templates/next-webgl/README.md +31 -0
  121. package/src/templates/next-webgl/lib/utils/json-ld.tsx +327 -21
  122. package/src/templates/next-webgl/next.config.ts +6 -0
  123. package/src/modules/features/cms/sanity/files/lib/utils/json-ld.tsx +0 -244
@@ -0,0 +1,416 @@
1
+ import { defineArrayMember, defineField, defineType } from "sanity";
2
+
3
+ /**
4
+ * Editor-selectable JSON-LD blocks (predefined schema.org types + a raw
5
+ * `customJsonLd` escape hatch), each emitted as its own script tag.
6
+ */
7
+
8
+ export const faqJsonLd = defineType({
9
+ name: "faqJsonLd",
10
+ title: "FAQ",
11
+ type: "object",
12
+ fields: [
13
+ defineField({
14
+ name: "questions",
15
+ title: "Questions",
16
+ type: "array",
17
+ validation: (Rule) => Rule.min(1),
18
+ of: [
19
+ defineArrayMember({
20
+ type: "object",
21
+ fields: [
22
+ defineField({
23
+ name: "question",
24
+ title: "Question",
25
+ type: "string",
26
+ validation: (Rule) => Rule.required(),
27
+ }),
28
+ defineField({
29
+ name: "answer",
30
+ title: "Answer",
31
+ type: "text",
32
+ rows: 3,
33
+ validation: (Rule) => Rule.required(),
34
+ }),
35
+ ],
36
+ preview: {
37
+ select: { title: "question", subtitle: "answer" },
38
+ },
39
+ }),
40
+ ],
41
+ }),
42
+ ],
43
+ preview: {
44
+ select: { questions: "questions" },
45
+ prepare: ({ questions }) => ({
46
+ title: "FAQ",
47
+ subtitle: `${Array.isArray(questions) ? questions.length : 0} question(s)`,
48
+ }),
49
+ },
50
+ });
51
+
52
+ export const jobPostingJsonLd = defineType({
53
+ name: "jobPostingJsonLd",
54
+ title: "Job Posting",
55
+ type: "object",
56
+ fields: [
57
+ defineField({
58
+ name: "title",
59
+ title: "Job Title",
60
+ type: "string",
61
+ validation: (Rule) => Rule.required(),
62
+ }),
63
+ defineField({
64
+ name: "description",
65
+ title: "Description",
66
+ type: "text",
67
+ rows: 4,
68
+ validation: (Rule) => Rule.required(),
69
+ }),
70
+ defineField({
71
+ name: "datePosted",
72
+ title: "Date Posted",
73
+ type: "datetime",
74
+ validation: (Rule) => Rule.required(),
75
+ }),
76
+ defineField({
77
+ name: "validThrough",
78
+ title: "Valid Through",
79
+ type: "datetime",
80
+ description: "When the posting expires.",
81
+ }),
82
+ defineField({
83
+ name: "employmentType",
84
+ title: "Employment Type",
85
+ type: "string",
86
+ options: {
87
+ list: [
88
+ { title: "Full-time", value: "FULL_TIME" },
89
+ { title: "Part-time", value: "PART_TIME" },
90
+ { title: "Contractor", value: "CONTRACTOR" },
91
+ { title: "Temporary", value: "TEMPORARY" },
92
+ { title: "Intern", value: "INTERN" },
93
+ { title: "Volunteer", value: "VOLUNTEER" },
94
+ { title: "Per diem", value: "PER_DIEM" },
95
+ { title: "Other", value: "OTHER" },
96
+ ],
97
+ },
98
+ }),
99
+ defineField({
100
+ name: "organizationName",
101
+ title: "Hiring Organization",
102
+ type: "string",
103
+ }),
104
+ defineField({
105
+ name: "organizationUrl",
106
+ title: "Organization URL",
107
+ type: "url",
108
+ }),
109
+ defineField({
110
+ name: "remote",
111
+ title: "Remote / Telecommute",
112
+ type: "boolean",
113
+ initialValue: false,
114
+ }),
115
+ defineField({ name: "locality", title: "City", type: "string" }),
116
+ defineField({ name: "region", title: "Region / State", type: "string" }),
117
+ defineField({ name: "country", title: "Country", type: "string" }),
118
+ ],
119
+ preview: {
120
+ select: { title: "title", subtitle: "organizationName" },
121
+ prepare: ({ title, subtitle }) => ({
122
+ title: title || "Job Posting",
123
+ subtitle: subtitle ? `Job · ${subtitle}` : "Job Posting",
124
+ }),
125
+ },
126
+ });
127
+
128
+ export const softwareApplicationJsonLd = defineType({
129
+ name: "softwareApplicationJsonLd",
130
+ title: "Software Application",
131
+ type: "object",
132
+ fields: [
133
+ defineField({
134
+ name: "name",
135
+ title: "Name",
136
+ type: "string",
137
+ validation: (Rule) => Rule.required(),
138
+ }),
139
+ defineField({
140
+ name: "description",
141
+ title: "Description",
142
+ type: "text",
143
+ rows: 2,
144
+ }),
145
+ defineField({
146
+ name: "applicationCategory",
147
+ title: "Application Category",
148
+ type: "string",
149
+ options: {
150
+ list: [
151
+ { title: "Web application", value: "WebApplication" },
152
+ { title: "Mobile application", value: "MobileApplication" },
153
+ { title: "Developer tool", value: "DeveloperApplication" },
154
+ { title: "Business application", value: "BusinessApplication" },
155
+ { title: "Design application", value: "DesignApplication" },
156
+ { title: "Game", value: "GameApplication" },
157
+ ],
158
+ },
159
+ }),
160
+ defineField({
161
+ name: "operatingSystem",
162
+ title: "Operating System",
163
+ type: "string",
164
+ description: "e.g. 'Web', 'macOS, Windows', 'iOS, Android'.",
165
+ }),
166
+ defineField({
167
+ name: "price",
168
+ title: "Price",
169
+ type: "number",
170
+ description: "Use 0 for free apps. Enables the rich result.",
171
+ }),
172
+ defineField({
173
+ name: "currency",
174
+ title: "Currency",
175
+ type: "string",
176
+ description: "ISO 4217 code, e.g. USD, EUR.",
177
+ initialValue: "USD",
178
+ }),
179
+ defineField({ name: "url", title: "URL", type: "url" }),
180
+ defineField({ name: "image", title: "Screenshot / Icon", type: "image" }),
181
+ ],
182
+ preview: {
183
+ select: { title: "name", subtitle: "applicationCategory" },
184
+ prepare: ({ title, subtitle }) => ({
185
+ title: title || "Software Application",
186
+ subtitle: subtitle ? `App · ${subtitle}` : "Software Application",
187
+ }),
188
+ },
189
+ });
190
+
191
+ export const itemListJsonLd = defineType({
192
+ name: "itemListJsonLd",
193
+ title: "Item List / Carousel",
194
+ type: "object",
195
+ description:
196
+ "An ordered list of links (e.g. a carousel of articles or products). Each item points to a page on your site.",
197
+ fields: [
198
+ defineField({
199
+ name: "name",
200
+ title: "List Name",
201
+ type: "string",
202
+ description: "Optional title for the list.",
203
+ }),
204
+ defineField({
205
+ name: "items",
206
+ title: "Items",
207
+ type: "array",
208
+ validation: (Rule) => Rule.min(1),
209
+ of: [
210
+ defineArrayMember({
211
+ type: "object",
212
+ fields: [
213
+ defineField({
214
+ name: "name",
215
+ title: "Name",
216
+ type: "string",
217
+ validation: (Rule) => Rule.required(),
218
+ }),
219
+ defineField({
220
+ name: "url",
221
+ title: "URL",
222
+ type: "url",
223
+ validation: (Rule) => Rule.required(),
224
+ }),
225
+ ],
226
+ preview: {
227
+ select: { title: "name", subtitle: "url" },
228
+ },
229
+ }),
230
+ ],
231
+ }),
232
+ ],
233
+ preview: {
234
+ select: { title: "name", items: "items" },
235
+ prepare: ({ title, items }) => ({
236
+ title: title || "Item List / Carousel",
237
+ subtitle: `${Array.isArray(items) ? items.length : 0} item(s)`,
238
+ }),
239
+ },
240
+ });
241
+
242
+ export const eventJsonLd = defineType({
243
+ name: "eventJsonLd",
244
+ title: "Event",
245
+ type: "object",
246
+ fields: [
247
+ defineField({
248
+ name: "name",
249
+ title: "Name",
250
+ type: "string",
251
+ validation: (Rule) => Rule.required(),
252
+ }),
253
+ defineField({
254
+ name: "description",
255
+ title: "Description",
256
+ type: "text",
257
+ rows: 2,
258
+ }),
259
+ defineField({
260
+ name: "startDate",
261
+ title: "Start Date",
262
+ type: "datetime",
263
+ validation: (Rule) => Rule.required(),
264
+ }),
265
+ defineField({ name: "endDate", title: "End Date", type: "datetime" }),
266
+ defineField({
267
+ name: "locationName",
268
+ title: "Location Name",
269
+ type: "string",
270
+ description: "Venue name, or leave blank for online events.",
271
+ }),
272
+ defineField({
273
+ name: "locationAddress",
274
+ title: "Location Address",
275
+ type: "string",
276
+ }),
277
+ defineField({ name: "url", title: "Event URL", type: "url" }),
278
+ defineField({ name: "image", title: "Image", type: "image" }),
279
+ ],
280
+ preview: {
281
+ select: { title: "name", subtitle: "startDate" },
282
+ prepare: ({ title, subtitle }) => ({
283
+ title: title || "Event",
284
+ subtitle: subtitle ? `Event · ${subtitle}` : "Event",
285
+ }),
286
+ },
287
+ });
288
+
289
+ export const videoJsonLd = defineType({
290
+ name: "videoJsonLd",
291
+ title: "Video",
292
+ type: "object",
293
+ fields: [
294
+ defineField({
295
+ name: "name",
296
+ title: "Name",
297
+ type: "string",
298
+ validation: (Rule) => Rule.required(),
299
+ }),
300
+ defineField({
301
+ name: "description",
302
+ title: "Description",
303
+ type: "text",
304
+ rows: 2,
305
+ validation: (Rule) => Rule.required(),
306
+ }),
307
+ defineField({
308
+ name: "thumbnail",
309
+ title: "Thumbnail",
310
+ type: "image",
311
+ validation: (Rule) => Rule.required(),
312
+ }),
313
+ defineField({
314
+ name: "uploadDate",
315
+ title: "Upload Date",
316
+ type: "datetime",
317
+ validation: (Rule) => Rule.required(),
318
+ }),
319
+ defineField({
320
+ name: "contentUrl",
321
+ title: "Content URL",
322
+ type: "url",
323
+ description: "Direct link to the video file (.mp4, etc.).",
324
+ }),
325
+ defineField({
326
+ name: "embedUrl",
327
+ title: "Embed URL",
328
+ type: "url",
329
+ description: "Player embed URL (YouTube, Vimeo, etc.).",
330
+ }),
331
+ ],
332
+ preview: {
333
+ select: { title: "name" },
334
+ prepare: ({ title }) => ({
335
+ title: title || "Video",
336
+ subtitle: "Video",
337
+ }),
338
+ },
339
+ });
340
+
341
+ export const customJsonLd = defineType({
342
+ name: "customJsonLd",
343
+ title: "Custom JSON-LD",
344
+ type: "object",
345
+ description:
346
+ "Optional JSON-LD block for advanced rich results (FAQ, Product, HowTo, etc.). Emits its own <script> tag. Validate snippets with https://search.google.com/test/rich-results — invalid blocks are skipped at render time.",
347
+ fields: [
348
+ defineField({
349
+ name: "label",
350
+ title: "Internal Label",
351
+ type: "string",
352
+ description:
353
+ "For your reference only (e.g. 'FAQ – pricing tiers'). Not emitted.",
354
+ validation: (Rule) => Rule.required(),
355
+ }),
356
+ defineField({
357
+ name: "json",
358
+ title: "JSON-LD",
359
+ type: "text",
360
+ rows: 10,
361
+ description:
362
+ "Paste a single schema.org JSON-LD object. Omit the <script> wrapper. Must include an @type (@context is added automatically if omitted).",
363
+ validation: (Rule) =>
364
+ Rule.required().custom((value) => {
365
+ if (typeof value !== "string" || value.trim() === "") {
366
+ return "JSON-LD is required";
367
+ }
368
+ try {
369
+ const parsed = JSON.parse(value);
370
+ if (Array.isArray(parsed)) {
371
+ return "Use one block per entry (split arrays into multiple blocks).";
372
+ }
373
+ if (typeof parsed !== "object" || parsed === null) {
374
+ return "Must be a JSON object.";
375
+ }
376
+ if (!("@type" in parsed)) {
377
+ return 'Must include an @type (e.g. "@type": "FAQPage").';
378
+ }
379
+ return true;
380
+ } catch {
381
+ return "Invalid JSON. Use https://jsonlint.com to debug.";
382
+ }
383
+ }),
384
+ }),
385
+ ],
386
+ preview: {
387
+ select: { title: "label", subtitle: "json" },
388
+ prepare: ({ title, subtitle }) => {
389
+ let type: string | undefined;
390
+ if (typeof subtitle === "string") {
391
+ try {
392
+ const parsed = JSON.parse(subtitle);
393
+ if (parsed && typeof parsed === "object" && "@type" in parsed) {
394
+ type = String(parsed["@type"]);
395
+ }
396
+ } catch {
397
+ // ignore — render-time skips invalid blocks
398
+ }
399
+ }
400
+ return {
401
+ title: title || "Custom JSON-LD",
402
+ subtitle: type ? `@type: ${type}` : "JSON-LD",
403
+ };
404
+ },
405
+ },
406
+ });
407
+
408
+ export const pageJsonLdMembers = [
409
+ faqJsonLd,
410
+ eventJsonLd,
411
+ videoJsonLd,
412
+ jobPostingJsonLd,
413
+ softwareApplicationJsonLd,
414
+ itemListJsonLd,
415
+ customJsonLd,
416
+ ] as const;
@@ -0,0 +1,100 @@
1
+ import { defineField, defineType } from "sanity";
2
+
3
+ export const structuredData = defineType({
4
+ name: "structuredData",
5
+ title: "Structured Data",
6
+ type: "document",
7
+ description:
8
+ "Site-wide identity emitted as JSON-LD (schema.org Organization + WebSite) on every page for search engines.",
9
+ fields: [
10
+ defineField({
11
+ name: "name",
12
+ title: "Organization Name",
13
+ type: "string",
14
+ description: "Public name of the organization (shown in rich results).",
15
+ validation: (Rule) => Rule.required(),
16
+ }),
17
+ defineField({
18
+ name: "legalName",
19
+ title: "Legal Name",
20
+ type: "string",
21
+ description:
22
+ "Registered legal entity name, if different from the public name.",
23
+ }),
24
+ defineField({
25
+ name: "logo",
26
+ title: "Logo",
27
+ type: "image",
28
+ description:
29
+ "Square or wide logo used in rich results. Min 112x112px, transparent PNG/SVG recommended.",
30
+ options: { hotspot: true },
31
+ }),
32
+ defineField({
33
+ name: "description",
34
+ title: "Description",
35
+ type: "text",
36
+ rows: 3,
37
+ description: "Short sentence describing the organization.",
38
+ }),
39
+ defineField({
40
+ name: "url",
41
+ title: "Canonical URL",
42
+ type: "url",
43
+ description:
44
+ "Optional override for the canonical site URL. Defaults to the deployed origin.",
45
+ }),
46
+ defineField({
47
+ name: "sameAs",
48
+ title: "Same-As Profiles",
49
+ type: "array",
50
+ description:
51
+ "Official profiles representing this organization (LinkedIn, X, GitHub, Crunchbase, Wikipedia, etc.).",
52
+ of: [{ type: "url" }],
53
+ }),
54
+ defineField({
55
+ name: "contactPoint",
56
+ title: "Contact Point",
57
+ type: "object",
58
+ options: { collapsible: true, collapsed: true },
59
+ fields: [
60
+ defineField({ name: "email", title: "Email", type: "string" }),
61
+ defineField({ name: "telephone", title: "Telephone", type: "string" }),
62
+ defineField({
63
+ name: "contactType",
64
+ title: "Contact Type",
65
+ type: "string",
66
+ description:
67
+ "e.g. 'customer support', 'sales', 'press'. See schema.org/ContactPoint.",
68
+ }),
69
+ ],
70
+ }),
71
+ defineField({
72
+ name: "address",
73
+ title: "Address",
74
+ type: "object",
75
+ options: { collapsible: true, collapsed: true },
76
+ fields: [
77
+ defineField({
78
+ name: "streetAddress",
79
+ title: "Street Address",
80
+ type: "string",
81
+ }),
82
+ defineField({ name: "locality", title: "City", type: "string" }),
83
+ defineField({
84
+ name: "region",
85
+ title: "Region / State",
86
+ type: "string",
87
+ }),
88
+ defineField({
89
+ name: "postalCode",
90
+ title: "Postal Code",
91
+ type: "string",
92
+ }),
93
+ defineField({ name: "country", title: "Country", type: "string" }),
94
+ ],
95
+ }),
96
+ ],
97
+ preview: {
98
+ prepare: () => ({ title: "Structured Data" }),
99
+ },
100
+ });
@@ -1,5 +1,40 @@
1
+ import {
2
+ ComponentIcon,
3
+ DocumentsIcon,
4
+ MenuIcon,
5
+ SchemaIcon,
6
+ ThLargeIcon,
7
+ } from "@sanity/icons";
1
8
  import type { StructureResolver } from "sanity/structure";
2
9
 
3
- // https://www.sanity.io/docs/structure-builder-cheat-sheet
10
+ // Explicit menu: new schema types must be listed here, which keeps plugin
11
+ // types (e.g. media.tag) out of the Studio.
4
12
  export const structure: StructureResolver = (S) =>
5
- S.list().title("Content").items(S.documentTypeListItems());
13
+ S.list()
14
+ .title("Content")
15
+ .items([
16
+ S.documentTypeListItem("article").title("Articles").icon(DocumentsIcon),
17
+ S.documentTypeListItem("example").title("Examples").icon(ComponentIcon),
18
+ S.documentTypeListItem("navigation").title("Navigation").icon(MenuIcon),
19
+ S.divider(),
20
+ // Layout — site-wide singletons.
21
+ S.listItem()
22
+ .title("Layout")
23
+ .id("layout")
24
+ .icon(ThLargeIcon)
25
+ .child(
26
+ S.list()
27
+ .title("Layout")
28
+ .items([
29
+ S.listItem()
30
+ .title("Structured Data")
31
+ .id("structuredData")
32
+ .icon(SchemaIcon)
33
+ .child(
34
+ S.document()
35
+ .schemaType("structuredData")
36
+ .documentId("structuredData"),
37
+ ),
38
+ ]),
39
+ ),
40
+ ]);