@pezak/hui-sanity v1.0.2
hui-sanity
Harry's UI (hui) sanity package. Configures @nuxtjs/sanity under the hood. Provides composables, etc.
Depends on hui-i18n for localization of fields, so you need to install and configure @pezak/hui-i18n
in order to use the sanity module.
Installation
Install the module to your Nuxt application with one command:
npx nuxi module add @pezak/hui-sanity
Sanity Config
In your /config folder create a sanity.config.ts
to configure the hui module and @nuxtjs/sanity
used behind-the-scenes.
Update id to point to your project and apiVersion to today's date.
export default {
projectId: "8m33196t",
apiVersion: "2024-04-01",
dataset: "production",
};
The package automatically loads this file and does the rest. If you need more custom config you can use the module key huiSanity
.
Usage
You can import multiple types from @pezak/hui-sanity/types
such as SanityDocument
, SanityImage
, SanityPage
.
Most frequently used queries are provided from @pezak/hui-sanity/query
like imageWithAsset
PageContent and sections
In order to use sanity provided sections for page content, create a component /components/PageContent.vue
.
Each section component that can be added as page content in Sanity, needs to be added in the components
object explicitly. The key matches the sanity doc type.
<script setup lang="ts">
defineProps<{ content: any[] }>();
const components = {
hero: resolveComponent("Hero"),
};
</script>
<template>
<component
:is="components[c._type as keyof typeof components]"
v-for="c in content"
:key="c._id"
v-bind="c"
></component>
</template>
Then in your main page [...slug].vue
:
<script setup lang="ts">
import type { SanityPage } from "@pezak/hui-sanity/types";
import { pageQuery } from "./page.query";
const { t } = useMessages();
// Handle Page Fetching
const route = useRoute();
const getPageData = async (
slug: string[],
): Promise<{
data: globalThis.Ref<SanityPage | null>;
pending: globalThis.Ref<boolean>;
type: "page";
}> => {
// Page is a generic page
const query = groq`
*[_type == "page" && slug.current == "${slug ? slug?.join("/") : "/"}"]{
${pageQuery}
}[0]
`;
const { data, pending } = await useSanityQueryWithPreview<SanityPage>(query);
return { data, pending, type: "page" };
};
const page = await getPageData(route.params.slug as string[]);
// Handle Page Seo Meta
useSeo(page.data.value?.seo);
// This is needed for sanity previewing.
useHead({
link: [{ rel: "canonical", href: getCanonicalUrl(page.data.value) }],
});
</script>
<template>
<div :key="route.fullPath">
<!-- 404 Not Found -->
<NotFound
:code="404"
:message="t('pageNotFound')"
v-if="!page.data?.value"
/>
<!-- Page -->
<PageContent
:content="page.data.value.content"
v-else-if="page.type === 'page'"
/>
</div>
</template>
Composables
const { data, pending } = await useSanityQueryWithPreview<SanityPage>(query);
In app.vue
const headerQuery = groq`
*[_id == "header"]{ ..., links[]{
..., page->
}}[0]
`;
const footerQuery = groq`
*[_id == "footer"]{ ..., topLinks[]{
..., page->
}}[0]
`;
const { data } = useSanityQuery<{
header: HeaderProps;
footer: FooterProps;
}>(
`{
"header": ${headerQuery},
"footer": ${footerQuery},
}`,
);