Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@tinloof/sanity-kit
Advanced tools
Components and utils to extend Sanity
Pages navigator to use in the new Presentation framework as "unstable_navigator".
This plugin is in beta
Required dependencies and minimum versions
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sanity": "^3.23.1"
"@sanity/overlays": "^2.3.0",
"@sanity/react-loader": "^1.6.4",
"@sanity/vision": "^3.23.1",
Note: The package is meant to be used with projects that use the new fetching system of loaders and overlays that is compatinble with presentation. Read more here →
This is the official Next.js starter from Sanity that uses this new updated system for reference
Install
npm i @tinloof/sanity-kit
Wrap your Studio with NavigatorProvider
'use client'
import { NavigatorProvider } from '@tinloof/sanity-kit/navigator'
import { NextStudio } from 'next-sanity/studio'
export default function Studio() {
return (
<NavigatorProvider>
<NextStudio config={config} />
</NavigatorProvider>
)
}
In your Sanity folder, wherever you keep your Sanity related config and files, create a React component called PagesNavigator
(you can actually call it whatever you prefer, this is simply a suggested name becasue of how will be shown later in these instructions)
Start by importing the Navigator and all the needed hooks from the plugin
import Navigator, {
ThemeProvider,
useNavigator,
useSanityFetch,
useUpdateTree
} from '@tinloof/sanity-kit/navigator'
At this point you will need to import a query to fetch your pages and an array of locales (if you use multi locales, it is not required).
import { pagesRoutesQuery } from '@/sanity/lib/queries'
import locales from '@/sanity/schemas/locales'
To work with the Navigator, pages need to have these fields as required
_id: string → // Sanity _id
_type: string → // e.g "page" or "home" for home page singleton without slug
_updatedAt: string → // From Sanity
_createdAt: string → // From Sanity
title: string → // Page title
routePath: string → // Slug field from Sanity
While the locales array should look like this (if you are using locales); it goes without sayng that these locales should be reflecting and mirroring your locales in Sanity
[
{ title: 'English', value: 'en' },
{ title: 'French', value: 'fr' },
{ title: 'Spanish', value: 'es' },
]
Once these are setup, you can start composing your PagesNavigator
// ...imports from before
export default function PagesNavigator() {
const { items, locale } = useNavigator()
const availableLocales = locales
// Custom hook to fetch data: add your query and its variables
const [data, loading] = useSanityFetch({
query: pagesRoutesQuery,
variables: {
types: ['page', 'home'],
locale: !!locale ? locale : availableLocales[0].value,
},
})
// This hook takes care of creating a tree with nested url segments pages
useUpdateTree(data)
function renderPages() {
if(items.length) {
return <Navigator.List items={items} />
} else {
<Navigator.EmptySearchResults />
}
}
return (
<ThemeProvider>
<Navigator.Header title="Pages Navigator">
<Navigator.SearchBox />
{availableLocales.length ? (
<Navigator.LocaleSelect locales={availableLocales} />
) : null}
</Navigator.Header>
{loading ? <Navigator.SkeletonListItems items={40} /> : null}
{renderPages()}
</ThemeProvider>
)
}
At this point all is left is to go to your sanity.config.ts
and add the PagesNavigator as unstable_component
in your presentationTool
plugin
import PagesNavigator from "./sanity/components/PagesNavigator";
export default defineConfig({
// ...
plugins: [
// ...
presentationTool({
previewUrl: {
origin:
typeof location === "undefined"
? "http://localhost:3000"
: location.origin,
draftMode: {
enable: "/api/draft",
},
},
components: {
unstable_navigator: {
component: PagesNavigator,
minWidth: 360,
maxWidth: 480,
},
},
}),
// ...
],
});
Once all is in plance you should be able to see your pages and navigate through them easily.
Getting started
Install
npm i @tinloof/sanity-kit
RoutePathField integrates with the navigator to simplify the task of creating route paths or slugs with nested segments/folders. It generates and appends the segments/folder structure of the URL, leaving only the last part of the slug (the actual last segment of the page) for the editor. For example, if the slug of a page is "/content/nested/page", the "content/nested" part will be an editable button that displays the current path up to the actual last segment of the page.
It takes 3 props, including the value coming from Sanity:
value: Spread the value obtained from component.field
(refer to the example below).
siteDomain: The domain of the production URL, used for display purposes.
defaultLocale: The default locale for the site. It is used to exclude the default locale from the URL and only include the locales that require recognition.
In your Sanity schema, import the RoutePathField custom field:
import { RoutePathField } from '@tinloof/sanity-kit/utils'
// ... rest of your schema
defineField({
type: 'slug',
name: 'routePath',
title: 'Route path',
components: {
field: (value) =>
RoutePathField({
...value,
siteDomain: 'https://example.com',
defaultLocale: "en",
}),
},
validation: (rule) => rule.required(),
}),
// ... rest of your schema
Blocks wizard is an abstraction in both UI and logic to build pages with a "blocks" mindset. The major abstraction in the UI is a modal picker to preview and select blocks visually.
The logic is abstracted using blockSchema
, which lets you simply create your blocks wrapping this utility around it to make it work automatically, and BlockArrayField
, which is the component to use in your page body field, also referred to in the following examples as blocksBody
.
How to use it:
Step 1: Create your first block using the blockSchema
utility. In this example we create a basic Hero block and we create a file in theblocks folder to export all blocks that we will use in the next steps:
// schemas/blocks/hero.ts
import { StarIcon } from '@sanity/icons'
import { blockSchema } from '@tinloof/sanity-kit/utils'
export const blockHero = blockSchema({
name: 'block.hero',
title: 'Hero',
type: 'object',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
validation: (Rule) => Rule.required(),
},
],
})
We use the name convention block.*
for consistency.
// schemas/blocks/index.ts
import { hero } from './hero'
const blocks = [
hero,
]
export default blocks
Step 2: create a body
object to render all your blocks in a page
import { BlockArrayField } from '@tinloof/sanity-kit/utils'
import { defineType } from 'sanity'
// These are our previously created blocks!
import blocks from '../blocks'
// Differs from ptBody in that it specializes in adding & reordering blocks/modules.
export const body = defineType({
name: 'body',
title: 'Content',
type: 'array',
of: blocks.map((block) => ({
type: block.name,
})),
components: {
input: BlockArrayField,
},
})
Step 3: Add your newly created schemas to Sanity config
export default defineConfig({
basePath: studioUrl,
projectId: projectId || '',
dataset: dataset || '',
title,
schema: {
// If you want more content types, you can add them to this array
types: [
// ... all the rest of your schemas
body,
hero,
],
},
plugins: // ... your plugins,
})
Step 4: use your body object in any page you want:
export default defineType({
type: 'document',
name: 'page',
title: 'Page',
icon: DocumentIcon,
fields: [
// ... rest of your fields
defineField({
name: 'body',
title: 'Content / body of the page',
type: 'body',
}),
],
// ... rest of your fields
})
FAQs
Components and utils to extend Sanity
The npm package @tinloof/sanity-kit receives a total of 0 weekly downloads. As such, @tinloof/sanity-kit popularity was classified as not popular.
We found that @tinloof/sanity-kit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.