diff --git a/apps/astro/src/components/Components.astro b/apps/astro/src/components/Components.astro index 423baaa..6e3675d 100644 --- a/apps/astro/src/components/Components.astro +++ b/apps/astro/src/components/Components.astro @@ -23,6 +23,7 @@ import PeopleShowcase, { PeopleShowcase_Query } from '@/components/global/People import ImagesMarquee, { ImagesMarquee_Query } from '@/components/global/ImagesMarquee.astro' import TextBlockCtaAndImage, { TextBlockCtaAndImage_Query } from '@/components/global/TextBlockCtaAndImage.astro' import ContactForm, { ContactForm_Query } from '@/components/global/ContactForm' +import FeaturedProjects, { FeaturedProjects_Query } from '@/components/global/FeaturedProjects.astro' const components = { SimpleCtaSection, @@ -42,6 +43,7 @@ const components = { ImagesMarquee, TextBlockCtaAndImage, ContactForm, + FeaturedProjects, } type ComponentsMap = { @@ -55,9 +57,10 @@ export type ComponentsProps = Array type Props = { data: ComponentsProps hasPreviousSections?: boolean + [x: string]: string | ComponentsProps | boolean | undefined } -const { data, hasPreviousSections = false } = Astro.props +const { data, hasPreviousSections = false, ...attrProps } = Astro.props export const Components_Query = /* groq */ ` components[] { @@ -79,6 +82,7 @@ export const Components_Query = /* groq */ ` ${ImagesMarquee_Query} ${TextBlockCtaAndImage_Query} ${ContactForm_Query} + ${FeaturedProjects_Query} }, ` --- @@ -87,6 +91,6 @@ export const Components_Query = /* groq */ ` data?.map((item, i) => { const DynamicComponent = components[item._type] as any if (!DynamicComponent) return null - return + return }) } diff --git a/apps/astro/src/components/global/FeaturedProjects.astro b/apps/astro/src/components/global/FeaturedProjects.astro new file mode 100644 index 0000000..047901b --- /dev/null +++ b/apps/astro/src/components/global/FeaturedProjects.astro @@ -0,0 +1,116 @@ +--- +import PortableText, { PortableTextQuery, type PortableTextValue } from '@/components/ui/portable-text' +import Image, { ImageDataQuery, type ImageDataProps } from '@/src/components/ui/Image' +import Button, { ButtonDataQuery, type ButtonDataProps } from '@/components/ui/Button' + +export const ProjectCard_Query = ` + ${ImageDataQuery('img')} + name, + "slug": slug.current, +` + +export const FeaturedProjects_Query = ` + _type == "FeaturedProjects" => { + ${PortableTextQuery('heading')} + ${ButtonDataQuery('cta')} + "isSelectedProjects": projects != null, + "projects": select(projects != null => + projects[] -> { + ${ProjectCard_Query} + }, + *[_type == "Project_Collection"][] | order(endDate desc)[0..4] { + ${ProjectCard_Query} + }, + ), + }, +` + +export type Props = { + index: number + heading: PortableTextValue + cta: ButtonDataProps + isSelectedProjects: boolean + projects: Array<{ + img: ImageDataProps + name: string + slug: string + }> + excludeSlug?: string +} + +const { index, heading, cta, isSelectedProjects, projects: _projects, excludeSlug } = Astro.props + +const projects = isSelectedProjects + ? _projects.slice(0, 4) + : _projects.filter((project) => project.slug !== excludeSlug).slice(0, 4) +--- + +
+
+ +
+
+ { + projects.map(({ img, name, slug }) => ( + + )) + } +
+
+ + diff --git a/apps/astro/src/pages/realizacje/[slug].astro b/apps/astro/src/pages/realizacje/[slug].astro index a968015..6ea2f89 100644 --- a/apps/astro/src/pages/realizacje/[slug].astro +++ b/apps/astro/src/pages/realizacje/[slug].astro @@ -22,7 +22,9 @@ export async function getStaticPaths() { return collection?.map(({ slug }) => ({ params: { slug: slug.replace(slugPrefix, '') } })) } -const { slug } = Astro.params +const { slug: _slug } = Astro.params + +const slug = `${slugPrefix}${_slug}` const page = await sanityFetch<{ name: string @@ -42,11 +44,11 @@ const page = await sanityFetch<{ ${Components_Query} } `, - params: { slug: `${slugPrefix}${slug}` }, + params: { slug: slug }, }) if (!page) return Astro.rewrite('/404') -const metadata = await metadataFetch('Project_Collection', `${slugPrefix}${slug}`) +const metadata = await metadataFetch('Project_Collection', slug) --- @@ -60,5 +62,5 @@ const metadata = await metadataFetch('Project_Collection', `${slugPrefix}${slug} - + diff --git a/apps/sanity/schema/Components.ts b/apps/sanity/schema/Components.ts index 73dfcae..ec5c429 100644 --- a/apps/sanity/schema/Components.ts +++ b/apps/sanity/schema/Components.ts @@ -16,6 +16,7 @@ import PeopleShowcase from "./components/PeopleShowcase"; import ImagesMarquee from "./components/ImagesMarquee"; import TextBlockCtaAndImage from "./components/TextBlockCtaAndImage"; import ContactForm from "./components/ContactForm"; +import FeaturedProjects from "./components/FeaturedProjects"; export default defineType({ name: 'components', @@ -39,6 +40,7 @@ export default defineType({ ImagesMarquee, TextBlockCtaAndImage, ContactForm, + FeaturedProjects, ], options: { insertMenu: { diff --git a/apps/sanity/schema/components/FeaturedProjects.ts b/apps/sanity/schema/components/FeaturedProjects.ts new file mode 100644 index 0000000..29279d7 --- /dev/null +++ b/apps/sanity/schema/components/FeaturedProjects.ts @@ -0,0 +1,62 @@ +import { defineField } from 'sanity'; +import { toPlainText } from '../../utils/to-plain-text'; +import { sectionPreview } from '../../utils/section-preview'; + +const name = 'FeaturedProjects'; +const title = 'Wyróżnione projekty'; +const icon = () => '✨'; + +export default defineField({ + name, + type: 'object', + title, + icon, + fields: [ + defineField({ + name: 'heading', + type: 'Heading', + title: 'Nagłówek', + validation: Rule => Rule.required(), + }), + defineField({ + name: 'cta', + type: 'cta', + title: 'Wezwanie do działania', + validation: Rule => Rule.required(), + }), + defineField({ + name: 'projects', + type: 'array', + title: 'Projekty (opcjonalne)', + description: 'Jeśli to pole zostanie puste, zostaną wyświetlone 4 ostatnie projekty (według daty zakończenia).', + of: [{ + type: 'reference', + to: [{ type: 'Project_Collection' }], + options: { + disableNew: true, + filter: ({ parent }) => { + const selectedIds = (parent as { _ref?: string }[])?.filter(item => item._ref).map(item => item._ref) || []; + if (selectedIds.length > 0) { + return { + filter: '!(_id in $selectedIds)', + params: { selectedIds } + } + } + return {} + } + } + }], + validation: Rule => Rule.max(4).error('Rekomendujemy dodanie maksymalnie 4 projektów.'), + }), + ], + preview: { + select: { + heading: 'heading', + }, + prepare: ({ heading }) => ({ + title: title, + subtitle: toPlainText(heading), + ...sectionPreview({ name, icon: icon() }), + }), + }, +}); diff --git a/apps/sanity/static/FeaturedProjects.webp b/apps/sanity/static/FeaturedProjects.webp new file mode 100644 index 0000000..c9844b2 Binary files /dev/null and b/apps/sanity/static/FeaturedProjects.webp differ