Why Doesn't Prepare Render Properly in Sanity.IO - sanity

I am trying to customize the prview section for a document insanity.io. To that extent, I have created the following document:
export default {
name: 'news',
type: 'document',
title: 'News',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
...
{
name: 'author',
title: 'Author',
type: 'string',
},
...
],
preview: {
select: {
title: 'title',
subtitle: 'author',
}
}
}
This works exactly as I want in Studio. The title section in the preview pane shows the title of the document and the subtitle section shows the name of the author.
However, if I try to modify the output of author by using prepare, then it no longer works. For instance, take a look at the following variation of the same document:
export default {
name: 'news',
type: 'document',
title: 'News',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
...
{
name: 'author',
title: 'Author',
type: 'string',
},
...
],
preview: {
select: {
title: 'title',
author: 'author',
}
},
prepare(selection) {
const { author } = selection
return {
...selection,
subtitle: author && `${author} is the author`
}
}
}
The title preview field is rendered, but nothing shows up in the subtitle section. However, as far as I understand -- this should work. And I wondering why not.
Any ideas?

prepare is actually a function called in preview. You have it as a seperate field of the root object. Move prepare inside preview like so:
preview: {
select: {
title: 'title',
author: 'author'
},
prepare(selection) {
const { author } = selection
return {
...selection,
subtitle: author && `${author} is the author`
}
}
}

Related

Sanity Array of Objects

I'm attempting to transform all my frontmatter from a legacy git based CMS into Sanity's ironically named CMS but I'm having difficulties with the arrays. For reference, here is my frontmatter:
resources.md
title: "Resources"
heading: "Check out our resources"
resources_list:
- title: User Manual
icon: "/assets/manual.jpg"
asset: "/assets/user-manual.pdf"
First I created a document type for the resources page and added the array to the fields:
resources.js
export default {
name: 'resourcesPage',
title: 'Resources Page',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string'
},
{
name: 'heading',
title: 'Heading',
type: 'string'
},
{
name: 'resourcesList',
title: 'Resources List',
type: 'array',
of: [
{
type: 'object',
fields: [
{
title: 'Title',
name: 'title',
type: 'string'
},
{
title: 'Icon',
name: 'icon',
type: 'image'
},
{
title: 'Asset',
name: 'asset',
type: 'file'
}
]
}
],
}
]
}
Then I get the follwoing error after I attempt to run sanity graphql deploy
Error: Encountered anonymous inline object "object" for field/type
"resourcesList". To use this field with GraphQL you will need to create
a top-level schema type for it. See
https://docs.sanity.io/help/schema-lift-anonymous-object-type
I follow their vague docs by creating another schema type for the object I want to place in my array:
resourceObj.js
export default {
type: 'object',
title: 'Resource',
name: 'resourceObj',
fields: [
{
title: 'Title',
name: 'title',
type: 'string'
},
{
title: 'Icon',
name: 'icon',
type: 'image'
},
{
title: 'Asset',
name: 'asset',
type: 'file'
}
]
}
Then I add it to the resources page schema:
export default {
name: 'resourcesPage',
title: 'Resources Page',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string'
},
{
name: 'heading',
title: 'Heading',
type: 'string'
},
{
name: 'resourcesList',
title: 'Resources List',
type: 'array',
of: [
{
type: 'resourceObj',
}
],
}
]
}
When I run sanity graphql deploy again I get the following error:
Error: resourcesPage - (document) / fields / resourcesList - (array) / of / <unnamed_type_#_index_0> - (resourcesObj)
Why would sanity not recognize my object?
In order to use objects in an array, you need to create a separate file for the object in the schema directory and make sure to import it on schema.js:
// First, we must import the schema creator
import createSchema from 'part:#sanity/base/schema-creator'
// Then import schema types from any plugins that might expose them
import schemaTypes from 'all:part:#sanity/base/schema-type'
import resourcesPage from './ownerGarage'
import resourceObj from './resourceObj'
// Then we give our schema to the builder and provide the result to Sanity
export default createSchema({
// We name our schema
name: "default",
// Then proceed to concatenate our document type
// to the ones provided by any plugins that are installed
types: schemaTypes.concat([
/* Your types here! */
resourcesPage,
resourceObj
]),
});

How to filter Sanity.io dataset based on a field on references

How to get all posts by a category slug in GROQ?
You can see that a post is added to one or more categories. I would like to get all posts by a category slug to show the posts on a category page. I am new to Sanity.io's GROQ. All the tutorials I have found on creating a blog with sanity.io and next.js have not covered it to show a category page showing posts from a category.
Post schema:
export default {
name: 'post',
title: 'Post',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96,
},
},
{
name: 'author',
title: 'Author',
type: 'reference',
to: {type: 'author'},
},
{
name: 'mainImage',
title: 'Main image',
type: 'image',
options: {
hotspot: true,
},
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [{type: 'reference', to: {type: 'category'}}],
},
{
name: 'publishedAt',
title: 'Published at',
type: 'datetime',
},
{
name: 'body',
title: 'Body',
type: 'blockContent',
},
],
preview: {
select: {
title: 'title',
author: 'author.name',
media: 'mainImage',
},
prepare(selection) {
const {author} = selection
return Object.assign({}, selection, {
subtitle: author && `by ${author}`,
})
},
},
}
I have tried the following:
const query = `*[_type == 'post' && $slug in [categories[]-> {slug}] ]{ _id, title, slug, publishedAt, categories[]-> {title,slug}} | order(publishedAt) [0...10]`;
const posts = await client.fetch(
query,
{ slug }
);
console.log("posts", posts);
I got the solution at Sanity's slack channel. The following code helps to get the posts from a category by it's slug.
`*[_type == 'post' && $slug in categories[]->slug.current ]`;

Filter query result by field value inside array of objects [Sanity.io & GROQ]

I'm trying to find a product variant inside my list of products(on sanity.io using GROQ), to do so, I have the sku of the variant that I want.
The query I'm using is
*[_type == "product" && variants[].sku.current =="kit-kat-wasabi-5" ]
But this query returns an empty array. I'm sure that the sku is correct because if I leave the filter aside, and fetch all I can find it.
I tried replacing the "==" with match, but the result is the same.
my schemas are
procuct
export default {
name: 'product',
title: 'Product',
type: 'document',
fields: [
{
name: 'title',
title: 'Inner Title',
type: 'string'
},
{
title: 'SKU',
name: 'sku',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
validation: Rule => Rule.required()
},
{
name: 'titleWebsite',
title: 'Title Website',
type: 'localeString'
},
{
name: 'active',
title: 'Active',
type: 'boolean'
},
{
name: 'mainImage',
title: 'Imagem',
type:"image"
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96
}
},
{
title: 'Base Price',
name: 'basePrice',
type: 'localeCurrency'
},
{
title: 'Quantidade',
name: 'qty',
type: 'number'
},
/* {
title: 'Default variant',
name: 'defaultProductVariant',
type: 'productVariant'
},*/
{
title: 'Variants',
name: 'variants',
type: 'array',
of: [
{
title: 'Variant',
type: 'productVariant'
}
]
},
{
title: 'Tags',
name: 'tags',
type: 'array',
of: [
{
type: 'string'
}
],
options: {
layout: 'tags'
}
},
{
name: 'vendor',
title: 'Vendor',
type: 'reference',
to: {type: 'vendor'}
},
{
name: 'blurb',
title: 'Blurb',
type: 'localeString'
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [
{
type: 'reference',
to: {type: 'category'}
}
]
},
{
name: 'body',
title: 'Body',
type: 'localeBlockContent'
}
],
preview: {
select: {
title: 'title',
manufactor: 'manufactor.title',
media: 'mainImage'
}
}
}
And productVariant
export default {
title: 'Product variant',
name: 'productVariant',
type: 'object',
fields: [
{
title: 'Title',
name: 'title',
type: 'string'
},
{
title: 'Title Website',
name: 'titleWebsite',
type: 'localeString'
},
{
title: 'Weight in grams',
name: 'grams',
type: 'number'
},
{
title: 'Price',
name: 'price',
type: 'localeCurrency'
},
{
title: 'SKU',
name: 'sku',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
validation: Rule => Rule.required()
},
{
title: 'Taxable',
name: 'taxable',
type: 'boolean'
},
{
name: 'blurb',
title: 'Blurb',
type: 'localeString'
},
{
name: 'images',
title: 'Images',
type: 'array',
of: [
{
type: 'image',
options: {
hotspot: true
}
}
]
},
{
title: 'Quantidade',
name: 'qty',
type: 'number'
},
{
title: 'Bar code',
name: 'barcode',
type: 'barcode'
}
]
}
This is a known bug in GROQ when traversing arrays. This will introduce breaking changes if it were to be fixed in GROQ v1. It will therefore be fixed in GROQ v2.
Here is a bug report explaining the issue: https://github.com/sanity-io/sanity/issues/1557. You can show your interest in this problem here.
There's a working draft for version two here: https://github.com/sanity-io/groq.
Regarding your schema, I would consider to change the type of the sku field to be something else, for example a string, and create a new field for the slug which has its source property set to the SKU to be automatically be generated by that field. Documentation for that can be found here: https://www.sanity.io/docs/slug-type.

sanity.io - Adding color the text editor for the "block" type

I have an object of type block to get a WYSIWYG editor. It looks like this:
{
title: "Block",
type: "block",
styles: [
{ title: "Normal", value: "normal" },
{ title: "H1", value: "h1" },
{ title: "H2", value: "h2" },
{ title: "H3", value: "h3" },
{ title: "H4", value: "h4" },
{ title: "Quote", value: "blockquote" }
],
lists: [{ title: "Bullet", value: "bullet" }],
marks: {
decorators: [
{ title: "Strong", value: "strong" },
{ title: "Emphasis", value: "em" }
],
annotations: [
{
title: "URL",
name: "link",
type: "object",
fields: [
{
title: "URL",
name: "href",
type: "url"
}
]
}
]
}
}
But I see no option to be able to choose the color of the text. Is there a way to enable this? Maybe a plugin?
There is indeed a plugin for this. In your terminal, cd to you Sanity Content Studio folder, then run:
sanity install #sanity/color-input
This will append #sanity/color-input to the plugins array in your sanity.json file and locally install the #sanity/color-input npm package.
Then, go ahead and add the color type to the annotations array in the block content where you want to enable text color. E.g.:
export default {
name: 'blockContent',
type: 'array',
title: 'Block Content with Color',
of: [
{
type: 'block',
marks: {
annotations: [
{name: 'color', title: 'Color', type: 'color'}
]
}
}
]
}
Also, keep in mind that you'll now get text annotated with color specifics. How (and if) your front-end(s) choose to render the structured text is up to you.

Preview a reference

I want to preview a reference name in the studio
I have and icon type, for example one which has the title 'facebook'
export default {
name: 'icon',
title: 'Icon',
type: 'document',
fields: [
{
name: 'name',
title: 'Name',
type: 'string'
},
]
}
I reference this in a menu elsewhere like this
{
name: 'icon',
title: 'Icon',
type: 'reference',
to: [{ type: 'icon' }]
},
and then try to preview like this
preview: {
select: {
title: 'icon',
},
prepare(selection) {
const { title } = selection;
return {
title: title.name,
}
}
}
but my selection returns the reference object, with _ref etc. not the object itself. Is there a way to preview this reference?
You can dot your way into the property on the reference that you'd like to use in the preview like this:
preview: {
select: {
title: 'icon.name',
},
prepare(selection) {
const { title } = selection;
return {
title: title.name,
}
}
}
Side note: Since the prepare function now just passes through its input, you can remove it altogether. This would be sufficient:
preview: {
select: {
title: 'icon.name'
}
}