Skip to content

Commit

Permalink
add FeaturedProjects section
Browse files Browse the repository at this point in the history
  • Loading branch information
milewskibogumil committed Nov 11, 2024
1 parent 3c97711 commit dd578bf
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 6 deletions.
8 changes: 6 additions & 2 deletions apps/astro/src/components/Components.astro
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -42,6 +43,7 @@ const components = {
ImagesMarquee,
TextBlockCtaAndImage,
ContactForm,
FeaturedProjects,
}
type ComponentsMap = {
Expand All @@ -55,9 +57,10 @@ export type ComponentsProps = Array<ComponentsMap[keyof typeof components]>
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[] {
Expand All @@ -79,6 +82,7 @@ export const Components_Query = /* groq */ `
${ImagesMarquee_Query}
${TextBlockCtaAndImage_Query}
${ContactForm_Query}
${FeaturedProjects_Query}
},
`
---
Expand All @@ -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 <DynamicComponent {...item} index={hasPreviousSections ? i + 1 : i} />
return <DynamicComponent {...item} index={hasPreviousSections ? i + 1 : i} {...attrProps} />
})
}
116 changes: 116 additions & 0 deletions apps/astro/src/components/global/FeaturedProjects.astro
Original file line number Diff line number Diff line change
@@ -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)
---

<section class="FeaturedProjects">
<header>
<PortableText value={heading} heading={index === 0 ? 'h1' : 'h2'} class="h2 heading" />
<Button {...cta} />
</header>
<div class="projects">
{
projects.map(({ img, name, slug }) => (
<article>
<a href={slug} class="project-link">
<div class="img">
<Image {...img} sizes="(max-width: 28rem) 100vw, (max-width: 38rem) 19rem, 25vw" priority={index === 0} />
</div>
<h3 class="h3">{name}</h3>
</a>
</article>
))
}
</div>
</section>

<style lang="scss">
.FeaturedProjects {
padding: clamp(3rem, calc(4vw / 0.48), 5rem) 0;
header {
margin-bottom: clamp(1.25rem, calc(2vw / 0.48), 2rem);
.heading {
margin-bottom: clamp(0.5rem, calc(1vw / 0.48), 1rem);
}
}
.projects {
display: grid;
gap: 0.75rem;
grid-template-columns: 1fr 1fr 1fr 1fr;
.project-link {
display: block;
&:hover,
&:focus-visible {
img {
transform: scale(1.03);
}
}
.img {
aspect-ratio: 48/61;
overflow: hidden;
img {
height: 100%;
transition: transform 800ms var(--easing);
}
}
h2 {
margin-top: 0.25rem;
}
}
}
@media (max-width: 63rem) {
margin: 0 auto;
max-width: 38rem;
.projects {
grid-template-columns: 1fr 1fr;
}
}
@media (max-width: 28rem) {
.projects {
grid-template-columns: 1fr;
}
}
}
</style>
10 changes: 6 additions & 4 deletions apps/astro/src/pages/realizacje/[slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
---

<Layout {...metadata}>
Expand All @@ -60,5 +62,5 @@ const metadata = await metadataFetch('Project_Collection', `${slugPrefix}${slug}
<Summary {...page.summary} />
<Overview {...page.overview} />
<Gallery {...page.gallery} />
<Components data={page.components} hasPreviousSections={true} />
<Components data={page.components} hasPreviousSections={true} excludeSlug={slug} />
</Layout>
2 changes: 2 additions & 0 deletions apps/sanity/schema/Components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -39,6 +40,7 @@ export default defineType({
ImagesMarquee,
TextBlockCtaAndImage,
ContactForm,
FeaturedProjects,
],
options: {
insertMenu: {
Expand Down
62 changes: 62 additions & 0 deletions apps/sanity/schema/components/FeaturedProjects.ts
Original file line number Diff line number Diff line change
@@ -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() }),
}),
},
});
Binary file added apps/sanity/static/FeaturedProjects.webp
Binary file not shown.

0 comments on commit dd578bf

Please sign in to comment.