Skip to content

Instantly share code, notes, and snippets.

@bm-vs
Last active April 2, 2024 09:38
Show Gist options
  • Save bm-vs/975f118ce0ceb16562cec769d23c0cf1 to your computer and use it in GitHub Desktop.
Save bm-vs/975f118ce0ceb16562cec769d23c0cf1 to your computer and use it in GitHub Desktop.
Sanity schema and groq queries
import {
Article,
DocumentGroup,
DoorType,
GlassFunction,
GlassOption,
Guide,
GuideArticle,
GuideStep,
InspirationalStory,
Material,
MuntinBarStyle,
Page,
Profile,
UValue,
Vacancy,
WindowType,
} from '@/sanity/sanity.types';
export const internalReferenceFragment = `//groq
_id,
_type,
slug,
'title': coalesce(title, name, value),
_type == 'guideArticle' => {
'step': *[_type == 'guideStep' && ^._id in articles[]._ref][0] {
slug,
'guide': *[_type == 'guide' && ^._id in steps[]._ref][0] {
slug
}
}
},
_type in ['glassFunction', 'glassOption', 'material', 'muntinBarStyle', 'profile', 'uValue'] => {
'featureGroupPage': *[_type == 'page' && _id == ^.featureGroupPage._ref][0].slug
}
`;
type FeatureDocument = GlassFunction | GlassOption | Material | MuntinBarStyle | Profile | UValue;
type ReferrableDocument =
| Article
| DocumentGroup
| DoorType
| Guide
| InspirationalStory
| Page
| Vacancy
| WindowType;
export type SanityInternalReference =
| {
_id: ReferrableDocument['_id'];
_type: ReferrableDocument['_type'];
slug: ReferrableDocument['slug'];
title:
| Extract<ReferrableDocument, {name?: string}>['name']
| Extract<ReferrableDocument, {title?: string}>['title'];
}
| {
_id: FeatureDocument['_id'];
_type: FeatureDocument['_type'];
slug: FeatureDocument['slug'];
title: Exclude<FeatureDocument, UValue>['name'] | UValue['value'];
featureGroupPage: Page['slug'];
}
| {
_id: GuideArticle['_id'];
_type: GuideArticle['_type'];
slug: GuideArticle['slug'];
title: GuideArticle['title'];
step: {
slug: GuideStep['slug'];
guide: {
slug: Guide['slug'];
};
};
};
export const internalReference = defineType({
name: 'internalReference',
title: 'Internal reference',
type: 'reference',
description: 'Link to an internal page or other linkable document',
to: [
{type: 'article'},
{type: 'documentGroup'},
{type: 'doorType'},
{type: 'guide'},
{type: 'guideArticle'},
{type: 'inspirationalStory'},
{type: 'page'},
{type: 'vacancy'},
{type: 'windowType'},
{type: 'glassFunction'},
{type: 'glassOption'},
{type: 'material'},
{type: 'muntinBarStyle'},
{type: 'profile'},
{type: 'uValue'},
] as const,
});
import {defineField, defineType} from 'sanity';
import {linkExternalFields} from '@/sanity/schemas/fields/link-external-fields';
export const menuItemExternal = defineType({
name: 'menuItemExternal',
title: 'External link',
type: 'object',
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'description',
title: 'Description',
type: 'string',
}),
defineField({
name: 'href',
title: 'URL',
type: 'url',
validation: (Rule) =>
Rule.required().uri({
allowRelative: true,
scheme: ['https', 'http', 'mailto', 'tel'],
}),
}),
defineField({
name: 'targetBlank',
title: 'Open in new tab',
type: 'boolean',
initialValue: true,
description: 'Opens the link in a new browser tab',
validation: (Rule) => Rule.required(),
}),
],
});
import {defineField, defineType} from 'sanity';
import {linkInternalFields} from '@/sanity/schemas/fields/link-internal-fields';
export const menuItemInternal = defineType({
name: 'menuItemInternal',
title: 'Internal link',
type: 'object',
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'description',
title: 'Description',
type: 'string',
}),
defineField({
name: 'link',
title: 'Internal link',
type: 'internalReference',
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'targetBlank',
title: 'Open in new tab',
type: 'boolean',
initialValue: false,
description: 'Opens the link in a new browser tab',
validation: (Rule) => Rule.required(),
}),
],
});
import {OverrideProperties} from 'type-fest';
import {internalReferenceFragment, SanityInternalReference} from '@/groq/fields/internal-reference';
import {MenuItemExternal, MenuItemInternal} from '@/sanity/sanity.types';
export const menuItemFragment = `//groq
...,
_type, // NB: need to be explicit about this, otherwise typegen will not add this field
_type == 'menuItemInternal' => {
...,
'link': @.link->{
${internalReferenceFragment}
}
}
`;
export type SanityMenuItem =
| MenuItemExternal
| OverrideProperties<MenuItemInternal, {link: SanityInternalReference}>;
import {imageWebFragment} from '@/groq/fields/image-web';
import {internalReferenceFragment} from '@/groq/fields/internal-reference';
import {menuItemFragment} from '@/groq/fields/menu-item';
import {GetWebsiteQueryResult} from '@/sanity/sanity.types';
export const websiteFragment = `//groq
...,
mainMenu[] {
${menuItemFragment}
},
'pricingInformationPage': @.pricingInformationPage->{
${internalReferenceFragment}
},
footerMenuItemGroups[] {
...,
items[] {
${menuItemFragment},
_type // NB: need to be explicit about this, otherwise typegen will not add this field
}
}
`;
export const getWebsiteQuery = groq`
*[_type == 'website' && _id == 'websiteSingleton'][0] {
${websiteFragment}
}
`;
export type SanityWebsite = NonNullable<GetWebsiteQueryResult>;
import {defineArrayMember, defineField, defineType} from 'sanity';
export const website = defineType({
name: 'website',
title: 'Website',
type: 'document',
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'mainMenu',
title: 'Main menu',
description: 'The most prominent menu displayed in the header',
type: 'array',
of: [
defineArrayMember({type: 'menuItemInternal'}),
defineArrayMember({type: 'menuItemExternal'}),
],
}),
defineField({
name: 'pricingInformationPage',
title: 'Pricing information page',
description:
'Link to the page that describes why pricing is complicated and directs the user to contact a dealer.',
type: 'internalReference',
}),
defineField({
name: 'footerMenuItemGroups',
title: 'Footer menu',
type: 'array',
of: [
defineArrayMember({
title: 'Menu item group',
type: 'object',
fields: [
defineField({
name: 'title',
title: 'Title',
description: 'The title of this menu item group',
type: 'string',
validation: (Rule) => Rule.required(),
}),
defineField({
name: 'hideTitle',
title: 'Hide title',
description: 'Hides the title of this menu item group',
type: 'boolean',
initialValue: false,
}),
defineField({
name: 'items',
title: 'Items',
description: 'The menu items to list in this menu group',
type: 'array',
of: [
defineArrayMember({type: 'menuItemInternal'}),
defineArrayMember({type: 'menuItemExternal'}),
],
}),
],
}),
],
}),
],
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment