From a6a20fb7cc663e011e9cc475a03a682674588a7a Mon Sep 17 00:00:00 2001 From: Benno Tielen Date: Tue, 17 Dec 2024 14:45:18 +0100 Subject: [PATCH] feature: Worship page --- .gitignore | 3 + src/app/gottesdienst/[id]/page.tsx | 62 ++------------ src/collections/Events.ts | 2 + src/components/Cross/Cross.stories.tsx | 21 +++++ src/components/Cross/Cross.tsx | 25 ++++++ src/components/Cross/styles.module.scss | 9 ++ .../HorizontalRule/HorizontalRule.tsx | 5 +- src/components/HorizontalRule/cross.svg | 31 ------- src/components/HorizontalRule/cross2.svg | 7 -- src/components/Testimony/Testimony.tsx | 20 ++--- src/components/Testimony/styles.module.css | 47 ---------- src/components/Testimony/styles.module.scss | 44 ++++++++++ src/fetch/worship.ts | 3 +- src/hooks/useCompactDate.ts | 1 + .../Worship/Worship.stories.tsx | 31 +++++++ src/pageComponents/Worship/Worship.tsx | 85 +++++++++++++++++++ src/pageComponents/Worship/styles.module.scss | 23 +++++ src/utils/dto/worship.ts | 2 +- 18 files changed, 261 insertions(+), 160 deletions(-) create mode 100644 src/components/Cross/Cross.stories.tsx create mode 100644 src/components/Cross/Cross.tsx create mode 100644 src/components/Cross/styles.module.scss delete mode 100644 src/components/HorizontalRule/cross.svg delete mode 100644 src/components/HorizontalRule/cross2.svg delete mode 100644 src/components/Testimony/styles.module.css create mode 100644 src/components/Testimony/styles.module.scss create mode 100644 src/pageComponents/Worship/Worship.stories.tsx create mode 100644 src/pageComponents/Worship/Worship.tsx create mode 100644 src/pageComponents/Worship/styles.module.scss diff --git a/.gitignore b/.gitignore index 91643f2..aa768c7 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,9 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts +# storybook +/storybook-static + .env /media diff --git a/src/app/gottesdienst/[id]/page.tsx b/src/app/gottesdienst/[id]/page.tsx index 49e6c19..6705058 100644 --- a/src/app/gottesdienst/[id]/page.tsx +++ b/src/app/gottesdienst/[id]/page.tsx @@ -1,13 +1,6 @@ -import { Section } from '@/components/Section/Section' -import { Container } from '@/components/Container/Container' import { notFound } from 'next/navigation' -import { Worship } from '@/payload-types' -import { Title } from '@/components/Title/Title' -import { HR } from '@/components/HorizontalRule/HorizontalRule' -import { liturgicalDayName } from '@/hooks/liturgicalDayName' -import { ChurchWithContact } from '@/compositions/ChurchWithContact/ChurchWithContact' -import { transformCategory } from '@/utils/dto/worship' -import { readableDateTime } from '@/utils/readableDate' +import { Worship as WorshipType } from '@/payload-types' +import { Worship } from '@/pageComponents/Worship/Worship' export default async function WorshipPage({ params }: { params: Promise<{id: string}>}) { @@ -17,54 +10,9 @@ export default async function WorshipPage({ params }: { params: Promise<{id: str notFound() } - const event = await res.json() as Worship; - const subtitle = event.title ? event.title : transformCategory(event.type); - const title = event.liturgicalDay ? event.liturgicalDay : liturgicalDayName(event.date); - const church = typeof event.location === "string" ? { name: "Unkown", address: "unknown"} : event.location; + const worship = await res.json() as WorshipType; + return ( - <> -
- - - </Container> - <HR/> - </Section> - - <Section backgroundColor={"off-white"}> - <Container textAlign="center"> - <> - <p> - <strong>{church.name}</strong> <br/> - {readableDateTime(event.date)} - </p> - - { event.celebrant && - <p> - <strong>Zelebrant</strong><br/> - {event.celebrant} - </p> - } - - {event.description && - <p> - <strong>Hinweis</strong><br /> - {event.description} - </p> - } - </> - </Container> - </Section> - - - <Section> - <Container> - <ChurchWithContact - church={church.name} - contact={church.address} - /> - </Container> - </Section> - </> - + <Worship worship={worship} /> ) } \ No newline at end of file diff --git a/src/collections/Events.ts b/src/collections/Events.ts index ef25e59..d50f20e 100644 --- a/src/collections/Events.ts +++ b/src/collections/Events.ts @@ -38,6 +38,8 @@ export const Events: CollectionConfig = { admin: { date: { pickerAppearance: 'dayAndTime', + timeIntervals: 15, + timeFormat: 'HH:mm' }, }, }, diff --git a/src/components/Cross/Cross.stories.tsx b/src/components/Cross/Cross.stories.tsx new file mode 100644 index 0000000..a2f71c2 --- /dev/null +++ b/src/components/Cross/Cross.stories.tsx @@ -0,0 +1,21 @@ +import { Meta, StoryObj } from '@storybook/react' +import { Cross } from './Cross' + +const meta: Meta<typeof Cross> = { + component: Cross, +} + +type Story = StoryObj<typeof Cross>; +export default meta + +export const Default: Story = { + args: { + schema: "base" + }, +} + +export const Contrast: Story = { + args: { + schema: "contrast" + }, +} \ No newline at end of file diff --git a/src/components/Cross/Cross.tsx b/src/components/Cross/Cross.tsx new file mode 100644 index 0000000..5dca149 --- /dev/null +++ b/src/components/Cross/Cross.tsx @@ -0,0 +1,25 @@ +import styles from "./styles.module.scss" +import classNames from 'classnames' + +type CrossProps = { + schema?: "base" | "contrast" +} + +export const Cross = ({schema = "base"}: CrossProps) => { + const style = classNames({ + [styles.crossContrast]: schema === "contrast", + [styles.crossBase]: schema === "base", + }) + + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 39.69 49.61" + className={style} + height={49.61} + > + <polygon + points="33.89 14.81 19.89 14.81 19.89 0.8 18.89 0.8 18.89 14.81 4.89 14.81 4.89 15.81 18.89 15.81 18.89 48.8 19.89 48.8 19.89 15.81 33.89 15.81 33.89 14.81" /> + </svg> +) +} \ No newline at end of file diff --git a/src/components/Cross/styles.module.scss b/src/components/Cross/styles.module.scss new file mode 100644 index 0000000..d133462 --- /dev/null +++ b/src/components/Cross/styles.module.scss @@ -0,0 +1,9 @@ +@import "template.scss"; + +.crossContrast { + fill: $contrast-color; +} + +.crossBase { + fill: $base-color; +} \ No newline at end of file diff --git a/src/components/HorizontalRule/HorizontalRule.tsx b/src/components/HorizontalRule/HorizontalRule.tsx index 82d1ddf..6332c74 100644 --- a/src/components/HorizontalRule/HorizontalRule.tsx +++ b/src/components/HorizontalRule/HorizontalRule.tsx @@ -1,12 +1,11 @@ import styles from "./styles.module.scss" -import Image from "next/image" -import cross from "./cross2.svg" +import { Cross } from '@/components/Cross/Cross' export const HR = () => { return ( <div className={styles.container}> <div className={styles.line}></div> - <Image src={cross} alt={"Cross"} className={styles.cross} /> + <Cross /> <div className={styles.line}></div> </div> ) diff --git a/src/components/HorizontalRule/cross.svg b/src/components/HorizontalRule/cross.svg deleted file mode 100644 index e2be0a0..0000000 --- a/src/components/HorizontalRule/cross.svg +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - width="40" - height="70" - viewBox="0 0 10.583333 18.520834" - version="1.1" - id="svg5" - xmlns="http://www.w3.org/2000/svg" - xmlns:svg="http://www.w3.org/2000/svg"> - <defs - id="defs2" /> - <g - id="layer1"> - <rect - style="fill:#426156FF;stroke-width:0.473399" - id="rect846" - width="0.80836952" - height="16.864483" - x="5.1093903" - y="0.83949941" /> - <rect - style="fill:#426156FF;stroke-width:0.454843" - id="rect848" - width="10" - height="0.7728833" - x="0.35068181" - y="4.9346447" /> - </g> -</svg> diff --git a/src/components/HorizontalRule/cross2.svg b/src/components/HorizontalRule/cross2.svg deleted file mode 100644 index 2bd078e..0000000 --- a/src/components/HorizontalRule/cross2.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 39.69 49.61"> - <defs> - <style>.cls-1{fill:#426156;}</style> - </defs> - <polygon class="cls-1" - points="33.89 14.81 19.89 14.81 19.89 0.8 18.89 0.8 18.89 14.81 4.89 14.81 4.89 15.81 18.89 15.81 18.89 48.8 19.89 48.8 19.89 15.81 33.89 15.81 33.89 14.81"/> -</svg> \ No newline at end of file diff --git a/src/components/Testimony/Testimony.tsx b/src/components/Testimony/Testimony.tsx index 3f0ec25..1fb9198 100644 --- a/src/components/Testimony/Testimony.tsx +++ b/src/components/Testimony/Testimony.tsx @@ -1,12 +1,10 @@ -import styles from './styles.module.css' +import styles from './styles.module.scss' import { Container } from '@/components/Container/Container' import classNames from 'classnames' import { faustina } from '@/app/fonts' -import Image from 'next/image' -import quote from './quotes.svg' type TestimonyProps = { - name: string + name?: string testimony: string occupation?: string } @@ -16,18 +14,14 @@ export const Testimony = ({ name, testimony, occupation }: TestimonyProps) => { <Container> <div className={styles.testimony}> <div className={styles.container}> - <Image - src={quote} - alt={'Quote'} - width={100} - className={classNames(styles.quote, styles.slidein)} - /> <p className={classNames(styles.testimonyText, faustina.className)}> {testimony} </p> - <p className={styles.name}> - {name} {occupation && <>- {occupation}</>} - </p> + {typeof name === 'string' && + <p className={styles.name}> + {name} {occupation && <>- {occupation}</>} + </p> + } </div> </div> </Container> diff --git a/src/components/Testimony/styles.module.css b/src/components/Testimony/styles.module.css deleted file mode 100644 index 976307a..0000000 --- a/src/components/Testimony/styles.module.css +++ /dev/null @@ -1,47 +0,0 @@ -.testimony { - display: flex; - padding: 80px 0 50px 0; - gap: 40px; - align-items: center; -} - -.testimonyText { - font-style: italic; - line-height: 1.7em; - font-size: 1.1em; -} - -.container { - position: relative; -} - -.person { - height: 150px; - width: 150px; - background-color: #f6dc66; - flex-shrink: 0; -} - -.name { - text-align: right; - font-weight: bold; -} - -.quote { - position: absolute; - top: -10px; - left: -10px; - opacity: 0.5; - z-index: -1; -} - -.slidein { - transform: translateX(-100%); - animation: slide-in 0.3s forwards; -} - -@keyframes slide-in { - 100% { - transform: translateX(0%); - } -} diff --git a/src/components/Testimony/styles.module.scss b/src/components/Testimony/styles.module.scss new file mode 100644 index 0000000..3b8ace5 --- /dev/null +++ b/src/components/Testimony/styles.module.scss @@ -0,0 +1,44 @@ +@import "template.scss"; + +.testimony { + display: flex; + padding: 80px 0 50px 0; + gap: 40px; + align-items: center; +} + +.testimonyText { + font-size: 33px; + color: $base-color; + text-align: center; + position: relative; +} + +.testimonyText::after { + content: '”'; + color: $contrast-color; + font-size: 120px; + position: absolute; + bottom: -20px; + line-height: 0; +} + +.testimonyText::before { + content: '“'; + color: $contrast-color; + font-size: 120px; + position: relative; + line-height: 0; + top: 40px; +} + +.container { + width: 870px; + margin: 0 auto; +} + +.name { + text-align: right; + font-weight: bold; + color: $shade1; +} \ No newline at end of file diff --git a/src/fetch/worship.ts b/src/fetch/worship.ts index 2b131aa..9d338e7 100644 --- a/src/fetch/worship.ts +++ b/src/fetch/worship.ts @@ -53,7 +53,8 @@ export const fetchWorship = async (args?: FetchWorshipArgs): Promise<PaginatedDo type: true, date: true, cancelled: true, - location: true + location: true, + title: true, }, limit: 15 }, diff --git a/src/hooks/useCompactDate.ts b/src/hooks/useCompactDate.ts index 17d2df5..60838a2 100644 --- a/src/hooks/useCompactDate.ts +++ b/src/hooks/useCompactDate.ts @@ -7,6 +7,7 @@ export const useCompactDate = (date: string) => { /** * Return date in user friendly format + * in format DD.MM.YYYY * */ export const useDate = (date: string) => { diff --git a/src/pageComponents/Worship/Worship.stories.tsx b/src/pageComponents/Worship/Worship.stories.tsx new file mode 100644 index 0000000..49c9bdf --- /dev/null +++ b/src/pageComponents/Worship/Worship.stories.tsx @@ -0,0 +1,31 @@ +import { Meta, StoryObj } from '@storybook/react' +import { Worship } from './Worship' + +const meta: Meta<typeof Worship> = { + component: Worship, +} + +type Story = StoryObj<typeof Worship>; +export default meta + +export const Default: Story = { + args: { + worship: { + id: "", + date: "2024-12-16T10:42:16+0000", + location: { + id: "", + name: "St. Clara", + address: "Schudomastr 12\n12345 Berlin", + createdAt: "", + updatedAt: "" + } , + type: 'MASS', + title: null, + cancelled: false, + celebrant: "Pfr. M. Mustermann", + updatedAt: "", + createdAt: "", + } + }, +} \ No newline at end of file diff --git a/src/pageComponents/Worship/Worship.tsx b/src/pageComponents/Worship/Worship.tsx new file mode 100644 index 0000000..e70b297 --- /dev/null +++ b/src/pageComponents/Worship/Worship.tsx @@ -0,0 +1,85 @@ +import styles from "./styles.module.scss" +import { Worship as WorshipType } from '@/payload-types' +import { useDate } from '@/hooks/useCompactDate' +import { Section } from '@/components/Section/Section' +import { Title } from '@/components/Title/Title' +import { liturgicalDayName } from '@/hooks/liturgicalDayName' +import { EventExcerpt, EventExcerptRow } from '@/components/EventExcerpt/EventExcerpt' +import { transformCategory } from '@/utils/dto/worship' +import { TextDiv } from '@/components/Text/TextDiv' +import { church } from '@/utils/church' +import { ChurchIcon } from '@/components/ChurchIcon/ChurchIcon' +import { Cross } from '@/components/Cross/Cross' +import { Testimony } from '@/components/Testimony/Testimony' + +type WorshipPageProps = { + worship: WorshipType +} + +export const Worship = ({ worship }: WorshipPageProps) => { + const date = new Date(worship.date); + const day = date.toLocaleDateString('de-DE', {weekday: 'long'} ) + const localeDate = useDate(worship.date) + const liturgicalDay = worship.liturgicalDay ? worship.liturgicalDay : liturgicalDayName(worship.date); + const what = worship.title ? worship.title : transformCategory(worship.type); + const time = date.toLocaleTimeString("de-DE", { timeStyle: "short" }); + + return ( + <> + <Section> + <div className={styles.textCenter}> + <Cross schema={"contrast"} /> + </div> + <Title + title={`${day}, ${localeDate}`} + size={'xl'} + color={'contrast'} + align={"center"} + /> + + <p className={styles.liturgicalDay}> + {liturgicalDay} + </p> + </Section> + + <Section padding={"medium"}> + <EventExcerpt> + <EventExcerptRow label={"Was:"}> + {what} + </EventExcerptRow> + <EventExcerptRow label={"Wo:"}> + { typeof worship.location == "object" && + <TextDiv text={`${worship.location.name}\n${worship.location.address}\n${time} Uhr`} /> + } + </EventExcerptRow> + { worship.celebrant && + <EventExcerptRow label={"Zelebrant:"}> + {worship.celebrant} + </EventExcerptRow> + } + + { typeof worship.description === "string" && worship.description != "" && + <EventExcerptRow label={"Hinweise:"}> + <TextDiv text={worship.description} /> + </EventExcerptRow> + } + + <div> + <div className={styles.church}> + <ChurchIcon + church={church(typeof worship.location == "object" ? worship.location.name : "clara")} + color={"#426156"} + style={"filled"} + stroke={3} + /> + </div> + </div> + </EventExcerpt> + </Section> + + <Section> + <Testimony testimony={"Du bringst nichts mit hinein, Du nimmst nichts mit hinaus
Lass eine goldene Spur zurück, Im alten Erdenhaus"} /> + </Section> + </> + ) +} \ No newline at end of file diff --git a/src/pageComponents/Worship/styles.module.scss b/src/pageComponents/Worship/styles.module.scss new file mode 100644 index 0000000..4ba992f --- /dev/null +++ b/src/pageComponents/Worship/styles.module.scss @@ -0,0 +1,23 @@ +@import "template.scss"; + +.textCenter { + text-align: center; +} + +.liturgicalDay { + text-align: center; + margin-top: -20px; +} + +.church { + height: 144px; + width: 144px; + margin: 40px auto; + border-radius: $border-radius; + border: 1px solid $base-color; +} + +.church svg { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/src/utils/dto/worship.ts b/src/utils/dto/worship.ts index af6f1f2..6782fb0 100644 --- a/src/utils/dto/worship.ts +++ b/src/utils/dto/worship.ts @@ -22,7 +22,7 @@ export const tranformWorship = (worship: Worship[]): (EventRowProps & {id: strin return worship.map(w => { return { id: w.id, - title: transformCategory(w.type), + title: typeof w.title === "string" ? w.title : transformCategory(w.type), date: w.date, href: `/gottesdienst/${w.id}`, location: typeof w.location === 'string' ? w.location : w.location.name,