diff --git a/app/(site)/[locale]/[...slug]/page.tsx b/app/(site)/[locale]/[...slug]/page.tsx index fa4626161..4b2d276f6 100644 --- a/app/(site)/[locale]/[...slug]/page.tsx +++ b/app/(site)/[locale]/[...slug]/page.tsx @@ -1,5 +1,7 @@ import CategoryPage from '@/components/pages/category-page'; import ProductPage from '@/components/pages/product-page'; +import SearchPage from '@/components/pages/search-page'; +import SearchPagePreview from '@/components/pages/search-page-preview'; import SinglePage from '@/components/pages/single-page'; import SinglePagePreview from '@/components/pages/single-page-preview'; import PreviewProvider from '@/components/preview-provider'; @@ -55,6 +57,8 @@ export default async function Page({ params }: PageParams) { pageData = await getCachedClient()(query, queryParams); } else if (docType === 'category') { pageData = await getCachedClient()(query, queryParams); + } else if (docType === 'search') { + pageData = await getCachedClient()(query, queryParams); } else { return; } @@ -65,6 +69,7 @@ export default async function Page({ params }: PageParams) { return ( {docType === 'page' && } + {docType === 'search' && } ); } @@ -74,6 +79,7 @@ export default async function Page({ params }: PageParams) { {docType === 'page' && } {docType === 'product' && } {docType === 'category' && } + {docType === 'search' && } ); } diff --git a/app/api/preview/route.ts b/app/api/preview/route.ts index 092ff8336..5f1dce999 100644 --- a/app/api/preview/route.ts +++ b/app/api/preview/route.ts @@ -22,9 +22,7 @@ export async function GET(request: Request) { Location: `/${locale}`, }, }) - } - - if (type === 'page') { + } else { return new Response(null, { status: 307, headers: { diff --git a/components/pages/search-page-preview.tsx b/components/pages/search-page-preview.tsx new file mode 100644 index 000000000..ab080523d --- /dev/null +++ b/components/pages/search-page-preview.tsx @@ -0,0 +1,26 @@ +'use client'; + +import PreviewBanner from '@/components/ui/preview-banner'; +import { searchPageQuery } from '@/lib/sanity/queries'; +import { useLiveQuery } from '@sanity/preview-kit'; +import SearchPage from './search-page'; + +interface SearchPagePreviewParams { + initialData: []; + params: { + locale: string; + slug: string; + }; +} + +export default function SearchPagePreview({ initialData, params }: SearchPagePreviewParams) { + const [data] = useLiveQuery(initialData, searchPageQuery, params); + + return ( + <> + + {/* @ts-ignore */} + + + ); +} diff --git a/app/(site)/[locale]/sok/page.tsx b/components/pages/search-page.tsx similarity index 71% rename from app/(site)/[locale]/sok/page.tsx rename to components/pages/search-page.tsx index 2e8e43f2c..868ffb416 100644 --- a/app/(site)/[locale]/sok/page.tsx +++ b/components/pages/search-page.tsx @@ -1,17 +1,16 @@ -'use client'; - import Search from '@/components/search/search'; import SearchResult from '@/components/search/search-result'; import Text from '@/components/ui/text/text'; -import { useTranslations } from 'next-intl'; -export default function SearchPage() { - const t = useTranslations('search'); +interface SearchPageParams { + data: object | any; +} +export default function SearchPage({ data }: SearchPageParams) { return (
- {t('search')} + {data?.title} diff --git a/helpers/get-query-from-slug.ts b/helpers/get-query-from-slug.ts index 83657ca3f..3a9a64001 100644 --- a/helpers/get-query-from-slug.ts +++ b/helpers/get-query-from-slug.ts @@ -1,7 +1,8 @@ import { categoryQuery, pageQuery, - productQuery + productQuery, + searchPageQuery } from '@/lib/sanity/queries'; import { groq } from 'next-sanity'; @@ -10,6 +11,7 @@ const getQueryFromSlug = (slugArray: string[], locale: string) => { 'product': groq`${productQuery}`, 'category': groq`${categoryQuery}`, 'page': groq`${pageQuery}`, + 'search': groq`${searchPageQuery}` } let docType = '' @@ -26,6 +28,8 @@ const getQueryFromSlug = (slugArray: string[], locale: string) => { docType = `product` } else if (slugStart === `kategori` || slugStart === `category`) { docType = `category` + } else if (slugStart === `sok` || slugStart === `search`) { + docType = `search` } else { docType = `page` } diff --git a/lib/sanity/desk/index.ts b/lib/sanity/desk/index.ts index 3bcb06d55..2128da084 100644 --- a/lib/sanity/desk/index.ts +++ b/lib/sanity/desk/index.ts @@ -1,16 +1,17 @@ /** * Desk structure overrides */ -import {ListItemBuilder, StructureResolver} from 'sanity/desk' +import { ListItemBuilder, StructureResolver } from 'sanity/desk' +import blurbs from './blurb-structure' import categories from './category-structure' import home from './home-structure' +import navigation from './navigation-structure' import pages from './page-structure' import products from './product-structure' -import settings from './settings-structure' -import blurbs from './blurb-structure' +import search from './search-structure' import sections from './section-structure' +import settings from './settings-structure' import usps from './usp-structure' -import navigation from './navigation-structure' /** * Desk structure overrides @@ -46,7 +47,8 @@ const hiddenDocTypes = (listItem: ListItemBuilder) => { 'usp', 'navigation', 'footerMenu', - 'utilityMenu' + 'utilityMenu', + 'search' ].includes(id) } @@ -64,9 +66,9 @@ export const structure: StructureResolver = (S, context) => usps(S, context), sections(S, context), S.divider(), - navigation(S, context), - S.divider(), settings(S, context), + search(S, context), + navigation(S, context), S.divider(), ...S.documentTypeListItems().filter(hiddenDocTypes), S.divider(), diff --git a/lib/sanity/desk/search-structure.ts b/lib/sanity/desk/search-structure.ts new file mode 100644 index 000000000..83c9c1415 --- /dev/null +++ b/lib/sanity/desk/search-structure.ts @@ -0,0 +1,34 @@ +import { EyeOpenIcon, MasterDetailIcon } from '@sanity/icons' +import { SanityDocument } from 'sanity' +import Iframe from 'sanity-plugin-iframe-pane' +import { ListItemBuilder } from 'sanity/desk' +import defineStructure from '../utils/define-structure' +import getPreviewUrl from '../utils/get-preview-url' + +export default defineStructure((S) => + S.listItem() + .title('Search pages') + .schemaType('search') + .child ( + S.documentList() + .title('Search pages') + .filter('_type == "search"') + .child(id => + S.document() + .schemaType("search") + .id(id) + .views([ + S.view + .form() + .icon(MasterDetailIcon), + S.view + .component(Iframe) + .icon(EyeOpenIcon) + .options({ + url: (doc: SanityDocument) => getPreviewUrl(doc), + }) + .title('Preview') + ]) + ) + ) +) diff --git a/lib/sanity/queries.tsx b/lib/sanity/queries.tsx index 4e3e5bae3..fb8a0cd4c 100644 --- a/lib/sanity/queries.tsx +++ b/lib/sanity/queries.tsx @@ -178,6 +178,19 @@ export const homePageQuery = `*[_type == "home" && language == $locale][0] { } }`; +export const searchPageQuery = `*[_type == "search" && language == $locale][0] { + _type, + title, + "locale": language, + "translations": *[_type == "translation.metadata" && references(^._id)].translations[].value->{ + title, + "locale": language + }, + seo { + ${seoFields} + } +}`; + // Page query export const pageQuery = `*[_type == "page" && slug.current == $slug && language == $locale][0] { _type, diff --git a/lib/sanity/schemas/documents/category.tsx b/lib/sanity/schemas/documents/category.tsx index 493df701c..e7d6da08d 100644 --- a/lib/sanity/schemas/documents/category.tsx +++ b/lib/sanity/schemas/documents/category.tsx @@ -1,19 +1,19 @@ -import {TagIcon} from '@sanity/icons' -import {defineField, defineType} from 'sanity' -import {slugWithLocalizedType} from './slugWithLocalizedType' -import {languages} from '../../languages' -import {validateImage} from '../../utils/validation' +import { TagIcon } from '@sanity/icons'; +import { defineField, defineType } from 'sanity'; +import { languages } from '../../languages'; +import { validateImage } from '../../utils/validation'; +import { slugWithLocalizedType } from '../slugWithLocalizedType'; const GROUPS = [ { name: 'editorial', - title: 'Editorial', + title: 'Editorial' }, { name: 'seo', - title: 'SEO', - }, -] + title: 'SEO' + } +]; export default defineType({ name: 'category', @@ -27,7 +27,7 @@ export default defineType({ name: 'language', type: 'string', readOnly: true, - description: 'Language of this document.', + description: 'Language of this document.' // hidden: true, }), // Title @@ -35,7 +35,7 @@ export default defineType({ name: 'title', title: 'Title', type: 'string', - description: 'Category title.', + description: 'Category title.' }), // Slug slugWithLocalizedType('category', 'title'), @@ -60,67 +60,67 @@ export default defineType({ name: 'image', type: 'mainImage', title: 'Image', - validation: (Rule) => validateImage(Rule, true), + validation: (Rule) => validateImage(Rule, true) }), defineField({ name: 'description', title: 'Description', type: 'text', rows: 5, - description: 'Description of this category.', + description: 'Description of this category.' }), defineField({ name: 'id', title: 'ID', type: 'number', - description: 'Unique ID.', + description: 'Unique ID.' }), defineField({ name: 'categoryId', title: 'Category ID', type: 'number', - description: 'Unique category ID.', + description: 'Unique category ID.' }), defineField({ name: 'parentId', title: 'Parent ID', type: 'number', - description: 'Unique parent category ID.', + description: 'Unique parent category ID.' }), // SEO defineField({ name: 'seo', title: 'SEO', type: 'seo', - group: 'seo', - }), + group: 'seo' + }) ], orderings: [ { name: 'titleAsc', title: 'Title (A-Z)', - by: [{field: 'title', direction: 'asc'}], + by: [{ field: 'title', direction: 'asc' }] }, { name: 'titleDesc', title: 'Title (Z-A)', - by: [{field: 'title', direction: 'desc'}], - }, + by: [{ field: 'title', direction: 'desc' }] + } ], preview: { select: { title: 'title', - language: 'language', + language: 'language' }, prepare(selection) { - const {title, language} = selection - const currentLang = languages.find((lang) => lang.id === language) + const { title, language } = selection; + const currentLang = languages.find((lang) => lang.id === language); return { title, subtitle: `${currentLang ? currentLang.title : ''}`, - media: TagIcon, - } - }, - }, -}) + media: TagIcon + }; + } + } +}); diff --git a/lib/sanity/schemas/documents/page.tsx b/lib/sanity/schemas/documents/page.tsx index 7b040327b..6301f0fe6 100644 --- a/lib/sanity/schemas/documents/page.tsx +++ b/lib/sanity/schemas/documents/page.tsx @@ -1,8 +1,8 @@ -import {DocumentIcon} from '@sanity/icons' -import {defineField} from 'sanity' -import {languages} from '../../languages' -import {COMPONENT_REFERENCES} from '../../constants' -import {slugWithLocalizedType} from './slugWithLocalizedType' +import { DocumentIcon } from '@sanity/icons'; +import { defineField } from 'sanity'; +import { COMPONENT_REFERENCES } from '../../constants'; +import { languages } from '../../languages'; +import { slugWithLocalizedType } from '../slugWithLocalizedType'; export default defineField({ name: 'page', @@ -12,19 +12,19 @@ export default defineField({ groups: [ { name: 'editorial', - title: 'Editorial', + title: 'Editorial' }, { name: 'seo', - title: 'SEO', - }, + title: 'SEO' + } ], fields: [ defineField({ name: 'language', type: 'string', readOnly: true, - description: 'Language of this document.', + description: 'Language of this document.' // hidden: true, }), // Title @@ -33,7 +33,7 @@ export default defineField({ title: 'Title', type: 'string', description: 'Page title.', - validation: (Rule) => Rule.required(), + validation: (Rule) => Rule.required() }), // Slug slugWithLocalizedType('page', 'title'), @@ -44,32 +44,32 @@ export default defineField({ type: 'array', group: 'editorial', description: 'Add, reorder, edit or delete page sections.', - of: COMPONENT_REFERENCES, + of: COMPONENT_REFERENCES }), // SEO defineField({ name: 'seo', title: 'SEO', type: 'seo', - group: 'seo', - }), + group: 'seo' + }) ], preview: { select: { seoImage: 'seo.image', title: 'title', - language: 'language', + language: 'language' }, prepare(selection) { - const {seoImage, title, language} = selection + const { seoImage, title, language } = selection; - const currentLang = languages.find((lang) => lang.id === language) + const currentLang = languages.find((lang) => lang.id === language); return { media: seoImage, title, - subtitle: `${currentLang ? currentLang.title : ''}`, - } - }, - }, -}) + subtitle: `${currentLang ? currentLang.title : ''}` + }; + } + } +}); diff --git a/lib/sanity/schemas/documents/product.tsx b/lib/sanity/schemas/documents/product.tsx index 8f3b94d33..3859a2bba 100644 --- a/lib/sanity/schemas/documents/product.tsx +++ b/lib/sanity/schemas/documents/product.tsx @@ -1,8 +1,8 @@ import { PackageIcon } from '@sanity/icons'; import { defineField, defineType } from 'sanity'; -import { slugWithLocalizedType } from './slugWithLocalizedType'; import { languages } from '../../languages'; import { validateImage } from '../../utils/validation'; +import { slugWithLocalizedType } from '../slugWithLocalizedType'; const GROUPS = [ { diff --git a/lib/sanity/schemas/index.ts b/lib/sanity/schemas/index.ts index ba83b7160..026ce0831 100644 --- a/lib/sanity/schemas/index.ts +++ b/lib/sanity/schemas/index.ts @@ -12,14 +12,14 @@ // ] // Document types +import blurb from './documents/blurb' import category from './documents/category' +import footerMenu from './documents/footerMenu' import page from './documents/page' import product from './documents/product' import productVariant from './documents/productVariant' -import blurb from './documents/blurb' import section from './documents/section' import usp from './documents/usp' -import footerMenu from './documents/footerMenu' const documents = [ category, @@ -34,11 +34,11 @@ const documents = [ // Singleton document types import home from './singletons/home' +import search from './singletons/search' import settings from './singletons/settings' import utilityMenu from './singletons/utilityMenu' -// import navigation from './singletons/navigation' -const singletons = [home, settings, utilityMenu] +const singletons = [home, settings, utilityMenu, search] // Block content import body from './blocks/body' @@ -47,17 +47,17 @@ const blocks = [body] // Object types import banner from './objects/banner' -import linkExternal from './objects/linkExternal' -import linkInternal from './objects/linkInternal' -import hero from './objects/hero' -import seo from './objects/seo' -import mainImage from './objects/mainImage' -import slider from './objects/slider' import blurbSection from './objects/blurbSection' import filteredProductList from './objects/filteredProductList' -import uspSection from './objects/uspSection' -import reusableSection from './objects/reusableSection' +import hero from './objects/hero' +import linkExternal from './objects/linkExternal' +import linkInternal from './objects/linkInternal' +import mainImage from './objects/mainImage' import menu from './objects/menu' +import reusableSection from './objects/reusableSection' +import seo from './objects/seo' +import slider from './objects/slider' +import uspSection from './objects/uspSection' const objects = [ linkExternal, diff --git a/lib/sanity/schemas/singletons/search.tsx b/lib/sanity/schemas/singletons/search.tsx new file mode 100644 index 000000000..0d8bc25e2 --- /dev/null +++ b/lib/sanity/schemas/singletons/search.tsx @@ -0,0 +1,52 @@ +import { SearchIcon } from '@sanity/icons'; +import { defineField } from 'sanity'; +import { languages } from '../../languages'; +import { slugWithLocalizedType } from '../slugWithLocalizedType'; + +export default defineField({ + name: 'search', + title: 'Search', + type: 'document', + icon: SearchIcon, + fields: [ + defineField({ + name: 'language', + type: 'string', + readOnly: true, + description: 'Language of this document.' + // hidden: true, + }), + // Title + { + name: 'title', + title: 'Title', + type: 'string', + description: 'Page title.', + validation: (Rule) => Rule.required() + }, + // Slug + slugWithLocalizedType('search', 'title'), + // SEO + defineField({ + name: 'seo', + title: 'SEO', + type: 'seo' + }) + ], + preview: { + select: { + title: 'title', + language: 'language' + }, + prepare(selection) { + const { title, language } = selection; + + const currentLang = languages.find((lang) => lang.id === language); + + return { + title: `${title}`, + subtitle: `${currentLang ? currentLang.title : ''}` + }; + } + } +}); diff --git a/lib/sanity/schemas/documents/slugWithLocalizedType.ts b/lib/sanity/schemas/slugWithLocalizedType.ts similarity index 91% rename from lib/sanity/schemas/documents/slugWithLocalizedType.ts rename to lib/sanity/schemas/slugWithLocalizedType.ts index d2880d440..1b64aea34 100644 --- a/lib/sanity/schemas/documents/slugWithLocalizedType.ts +++ b/lib/sanity/schemas/slugWithLocalizedType.ts @@ -1,7 +1,7 @@ -import {Rule, Slug} from 'sanity' +import { Rule, Slug } from 'sanity'; import slugify from "slugify"; -import { i18n } from "../../languages"; -import { localizedTypes } from "../../localizedTypes"; +import { i18n } from "../languages"; +import { localizedTypes } from "../localizedTypes"; const MAX_LENGTH = 96 diff --git a/sanity.config.ts b/sanity.config.ts index 06a27533e..e38c99e73 100644 --- a/sanity.config.ts +++ b/sanity.config.ts @@ -13,7 +13,7 @@ const devOnlyPlugins = [visionTool()] const singletonActions = new Set(["publish", "discardChanges", "restore"]) // Define the singleton document types -const singletonTypes = new Set(["settings", "home", "utilityMenu", "media.tag"]) +const singletonTypes = new Set(["settings", "home", "utilityMenu", "media.tag", ]) // console.log(process.env.SANITY_API_READ_TOKEN) @@ -45,7 +45,8 @@ export default defineConfig({ 'section', 'usp', 'footerMenu', - 'utilityMenu' + 'utilityMenu', + 'search' ], // Optional // languageField: `language`, // defauts to "language"