diff --git a/.changeset/dirty-geckos-rush.md b/.changeset/dirty-geckos-rush.md new file mode 100644 index 00000000..c5011162 --- /dev/null +++ b/.changeset/dirty-geckos-rush.md @@ -0,0 +1,5 @@ +--- +"@tinloof/sanity-studio": minor +--- + +Pages navigator filter diff --git a/packages/sanity-studio/README.md b/packages/sanity-studio/README.md index 9c42875c..e3d3d572 100644 --- a/packages/sanity-studio/README.md +++ b/packages/sanity-studio/README.md @@ -38,7 +38,7 @@ Pages is a plugin that wraps [Presentation](https://www.sanity.io/docs/presentat #### 1. Configure Pages: ```tsx -import { pages } from "@tinloof/sanity-studio"; +import { pages } from '@tinloof/sanity-studio'; export default defineConfig({ // ... other Sanity Studio config @@ -47,7 +47,7 @@ export default defineConfig({ // Presentation's configuration previewUrl: { previewMode: { - enable: "/api/draft", + enable: '/api/draft', }, }, }), @@ -58,14 +58,14 @@ export default defineConfig({ #### 2. Add a `pathname` field to page schemas using the `definePage` helper: ```tsx -import { definePathname } from "@tinloof/sanity-studio"; +import { definePathname } from '@tinloof/sanity-studio'; export default defineType({ - type: "document", - name: "modularPage", + type: 'document', + name: 'modularPage', fields: [ definePathname({ - name: "pathname", + name: 'pathname', }), ], }); @@ -76,16 +76,16 @@ Documents with a defined `pathname` field value are now recognized as pages and Like Sanity's native `slug` type, the `pathname` supports a `source` option which can be used to generate the pathname from another field on the document, eg. the title: ```tsx -import { definePathname } from "@tinloof/sanity-studio"; +import { definePathname } from '@tinloof/sanity-studio'; export default defineType({ - type: "document", - name: "modularPage", + type: 'document', + name: 'modularPage', fields: [ definePathname({ - name: "pathname", + name: 'pathname', options: { - source: "title", + source: 'title', }, }), ], @@ -104,17 +104,17 @@ When a page is created, it will automatically have the current folder in its pat ```tsx -import { pages } from "@tinloof/sanity-studio"; +import { pages } from '@tinloof/sanity-studio'; export default defineConfig({ // ... other Sanity Studio config plugins: [ pages({ // Add any documents you want to be creatable from the pages navigator - creatablePages: ["page"], + creatablePages: ['page'], previewUrl: { previewMode: { - enable: "/api/draft", + enable: '/api/draft', }, }, }), @@ -134,14 +134,14 @@ Pathnames are automatically validated to be unique accros locales. ```tsx -import { pages } from "@tinloof/sanity-studio"; +import { pages } from '@tinloof/sanity-studio'; const i18nConfig = { locales: [ - { id: "en", title: "English" }, - { id: "fr", title: "French" }, + { id: 'en', title: 'English' }, + { id: 'fr', title: 'French' }, ], - defaultLocaleId: "en", + defaultLocaleId: 'en', }; export default defineConfig({ @@ -151,7 +151,7 @@ export default defineConfig({ i18n: i18nConfig, previewUrl: { previewMode: { - enable: "/api/draft", + enable: '/api/draft', }, }, }), @@ -162,11 +162,11 @@ export default defineConfig({ * Don't forget to add i18n options and locale field to your document schema */ export default defineType({ - type: "document", - name: "page", + type: 'document', + name: 'page', fields: [ definePathname({ - name: "pathname", + name: 'pathname', options: { // Add i18n options i18n: { @@ -177,14 +177,44 @@ export default defineType({ }), // Add locale field defineField({ - type: "string", - name: "locale", + type: 'string', + name: 'locale', hidden: true, }), ], }); ``` +### Filtering pages based on user roles + +The `filterBasedOnRoles` option can be used to filter pages based on the current user's roles. + +```tsx +import { pages } from '@tinloof/sanity-studio'; + +export default defineConfig({ + // ... other Sanity Studio config + plugins: [ + pages({ + // Presentation's configuration + previewUrl: { + previewMode: { + enable: '/api/draft', + }, + }, + filterBasedOnRoles: [ + { role: 'all', filter: "!(_id match 'singleton*')" }, + { role: 'contributor', filter: "_type == 'blog.post'" }, + ], + }), + ], +}); +``` + +This allows you to build upon the base filter, `pathname.current != null`, to filter pages based on the current user's roles. + +Setting `role: "all"` will set the filter to all roles while anything else will filter based on the current user's roles. + #### Support documents without a locale By default, when internationalization is enabled, only pages whose `locale` field matches the currently selected locale will be shown in the list. If you have page types that are not translated but you still want them to show up in the list, you can set the `requireLocale` option to false in your `i18n` config: @@ -192,10 +222,10 @@ By default, when internationalization is enabled, only pages whose `locale` fiel ```ts const i18nConfig = { locales: [ - { id: "en", title: "English" }, - { id: "fr", title: "French" }, + { id: 'en', title: 'English' }, + { id: 'fr', title: 'French' }, ], - defaultLocaleId: "en", + defaultLocaleId: 'en', requireLocale: false, }; ``` @@ -207,14 +237,14 @@ Now all documents with a `pathname` field will show up in the list regardless of By default, folders can be renamed. Set the `folder.canUnlock` option to `false` to disable this. ```tsx -import { definePathname } from "@tinloof/sanity-studio"; +import { definePathname } from '@tinloof/sanity-studio'; export default defineType({ - type: "document", - name: "modularPage", + type: 'document', + name: 'modularPage', fields: [ definePathname({ - name: "pathname", + name: 'pathname', options: { folder: { canUnlock: false, @@ -231,25 +261,25 @@ Documents can have their preview customized on the pages navigator using the [Li ```tsx export default { - name: "movie", - type: "document", + name: 'movie', + type: 'document', fields: [ { - title: "Title", - name: "title", - type: "string", + title: 'Title', + name: 'title', + type: 'string', }, { - type: "image", - name: "image", - title: "Image", + type: 'image', + name: 'image', + title: 'Image', }, ], // Preview information preview: { select: { - title: "title", - media: "image", + title: 'title', + media: 'image', }, prepare({ title, image }) { return { @@ -272,12 +302,12 @@ export default defineConfig({ pages({ previewUrl: { previewMode: { - enable: "/api/draft", + enable: '/api/draft', }, }, folders: { - "/news": { - title: "Articles", + '/news': { + title: 'Articles', icon: NewspaperIcon, }, }, @@ -291,14 +321,14 @@ export default defineConfig({ By default, the `pathname` field comes with a "Preview" button which is used to navigate to the page within the Presentation iframe when the pathname changes. You can optionally disable this manual button and have the Presentation tool automatically navigate to the new pathname as it changes: ```tsx -import { definePathname } from "@tinloof/sanity-studio"; +import { definePathname } from '@tinloof/sanity-studio'; export default defineType({ - type: "document", - name: "modularPage", + type: 'document', + name: 'modularPage', fields: [ definePathname({ - name: "pathname", + name: 'pathname', options: { autoNavigate: true, }, @@ -321,9 +351,9 @@ The `defineSection` field lets you easily define a new section schema. Used in c ```tsx // @/sanity/schemas/sections/banner.tsx export const bannerSection = defineSection({ - name: "block.banner", - title: "Banner", - type: "object", + name: 'block.banner', + title: 'Banner', + type: 'object', options: { variants: [ { @@ -331,14 +361,14 @@ export const bannerSection = defineSection({ * Will be used to display a preview image * when opening the section picker */ - assetUrl: "/images/blocks/hero.png", + assetUrl: '/images/blocks/hero.png', }, ], }, fields: [ defineField({ - name: "bannerSection", - type: "string", + name: 'bannerSection', + type: 'string', }), ], }); @@ -349,7 +379,7 @@ export const bannerSection = defineSection({ ```tsx // @/sanity/schemas/sections/index.tsx -import { bannerSection } from "@/sanity/schemas/sections/banner"; +import { bannerSection } from '@/sanity/schemas/sections/banner'; export const sections = [bannerSection]; ``` @@ -390,8 +420,8 @@ export const sections = [bannerSection]; ```tsx // @/sanity/schemas/index.tsx -import { sections } from "@sanity/schemas/index"; -import page from "@/sanity/schemas/page"; +import { sections } from '@sanity/schemas/index'; +import page from '@/sanity/schemas/page'; const schemas = [page, ...sections]; @@ -443,11 +473,11 @@ You can include additional properties ```tsx const locales = [ - { id: "en", title: "English", countryCode: "US", isDefault: true }, - { id: "fr", title: "French", countryCode: "FR" }, + { id: 'en', title: 'English', countryCode: 'US', isDefault: true }, + { id: 'fr', title: 'French', countryCode: 'FR' }, ]; -localizedItem(S, "blog.post", "Blog posts", locales, BookIcon); +localizedItem(S, 'blog.post', 'Blog posts', locales, BookIcon); ``` The utility will create a nested structure with: @@ -463,27 +493,27 @@ Builds upon a string field with an options list to show a preview of the icon se ### Basic usage ```tsx -import { iconSchema } from "@tinloof/sanity-studio"; -import { defineType } from "sanity"; +import { iconSchema } from '@tinloof/sanity-studio'; +import { defineType } from 'sanity'; export default defineType({ - type: "document", - name: "page", + type: 'document', + name: 'page', fields: [ { - type: "string", - name: "title", + type: 'string', + name: 'title', }, { ...iconSchema, options: { list: [ - { title: "Calendar", value: "calendar" }, - { title: "Chat", value: "chat" }, - { title: "Clock", value: "clock" }, + { title: 'Calendar', value: 'calendar' }, + { title: 'Chat', value: 'chat' }, + { title: 'Clock', value: 'clock' }, ], - path: "/icons/select", - backgroundColor: "black", + path: '/icons/select', + backgroundColor: 'black', }, }, ], @@ -511,18 +541,18 @@ Plugin to disable the creation of doucments with the `disableCreation` option se ```tsx sanity.config.ts; -import { disableCreation } from "@tinloof/sanity-studio"; -import schemas from "@/sanity/schemas"; +import { disableCreation } from '@tinloof/sanity-studio'; +import schemas from '@/sanity/schemas'; export default defineConfig({ - name: "studio", - title: "Studio", - projectId: "12345678", - dataset: "production", + name: 'studio', + title: 'Studio', + projectId: '12345678', + dataset: 'production', schema: { types: schemas, }, - plugins: [disableCreation({ schemas: ["home", "header", "footer"] })], + plugins: [disableCreation({ schemas: ['home', 'header', 'footer'] })], }); ```