feature: Worship page
This commit is contained in:
parent
ef913bc500
commit
a6a20fb7cc
18 changed files with 261 additions and 160 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -39,6 +39,9 @@ yarn-error.log*
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
|
|
||||||
|
# storybook
|
||||||
|
/storybook-static
|
||||||
|
|
||||||
.env
|
.env
|
||||||
|
|
||||||
/media
|
/media
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,6 @@
|
||||||
import { Section } from '@/components/Section/Section'
|
|
||||||
import { Container } from '@/components/Container/Container'
|
|
||||||
import { notFound } from 'next/navigation'
|
import { notFound } from 'next/navigation'
|
||||||
import { Worship } from '@/payload-types'
|
import { Worship as WorshipType } from '@/payload-types'
|
||||||
import { Title } from '@/components/Title/Title'
|
import { Worship } from '@/pageComponents/Worship/Worship'
|
||||||
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'
|
|
||||||
|
|
||||||
export default async function WorshipPage({ params }: { params: Promise<{id: string}>}) {
|
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()
|
notFound()
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = await res.json() as Worship;
|
const worship = await res.json() as WorshipType;
|
||||||
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;
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Worship worship={worship} />
|
||||||
<Section>
|
|
||||||
<Container>
|
|
||||||
<Title title={title} subtitle={subtitle} />
|
|
||||||
</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>
|
|
||||||
</>
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +38,8 @@ export const Events: CollectionConfig = {
|
||||||
admin: {
|
admin: {
|
||||||
date: {
|
date: {
|
||||||
pickerAppearance: 'dayAndTime',
|
pickerAppearance: 'dayAndTime',
|
||||||
|
timeIntervals: 15,
|
||||||
|
timeFormat: 'HH:mm'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
21
src/components/Cross/Cross.stories.tsx
Normal file
21
src/components/Cross/Cross.stories.tsx
Normal file
|
|
@ -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"
|
||||||
|
},
|
||||||
|
}
|
||||||
25
src/components/Cross/Cross.tsx
Normal file
25
src/components/Cross/Cross.tsx
Normal file
|
|
@ -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>
|
||||||
|
)
|
||||||
|
}
|
||||||
9
src/components/Cross/styles.module.scss
Normal file
9
src/components/Cross/styles.module.scss
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
@import "template.scss";
|
||||||
|
|
||||||
|
.crossContrast {
|
||||||
|
fill: $contrast-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crossBase {
|
||||||
|
fill: $base-color;
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import styles from "./styles.module.scss"
|
import styles from "./styles.module.scss"
|
||||||
import Image from "next/image"
|
import { Cross } from '@/components/Cross/Cross'
|
||||||
import cross from "./cross2.svg"
|
|
||||||
|
|
||||||
export const HR = () => {
|
export const HR = () => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.line}></div>
|
<div className={styles.line}></div>
|
||||||
<Image src={cross} alt={"Cross"} className={styles.cross} />
|
<Cross />
|
||||||
<div className={styles.line}></div>
|
<div className={styles.line}></div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
Before Width: | Height: | Size: 712 B |
|
|
@ -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>
|
|
||||||
|
Before Width: | Height: | Size: 373 B |
|
|
@ -1,12 +1,10 @@
|
||||||
import styles from './styles.module.css'
|
import styles from './styles.module.scss'
|
||||||
import { Container } from '@/components/Container/Container'
|
import { Container } from '@/components/Container/Container'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { faustina } from '@/app/fonts'
|
import { faustina } from '@/app/fonts'
|
||||||
import Image from 'next/image'
|
|
||||||
import quote from './quotes.svg'
|
|
||||||
|
|
||||||
type TestimonyProps = {
|
type TestimonyProps = {
|
||||||
name: string
|
name?: string
|
||||||
testimony: string
|
testimony: string
|
||||||
occupation?: string
|
occupation?: string
|
||||||
}
|
}
|
||||||
|
|
@ -16,18 +14,14 @@ export const Testimony = ({ name, testimony, occupation }: TestimonyProps) => {
|
||||||
<Container>
|
<Container>
|
||||||
<div className={styles.testimony}>
|
<div className={styles.testimony}>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Image
|
|
||||||
src={quote}
|
|
||||||
alt={'Quote'}
|
|
||||||
width={100}
|
|
||||||
className={classNames(styles.quote, styles.slidein)}
|
|
||||||
/>
|
|
||||||
<p className={classNames(styles.testimonyText, faustina.className)}>
|
<p className={classNames(styles.testimonyText, faustina.className)}>
|
||||||
{testimony}
|
{testimony}
|
||||||
</p>
|
</p>
|
||||||
<p className={styles.name}>
|
{typeof name === 'string' &&
|
||||||
{name} {occupation && <>- {occupation}</>}
|
<p className={styles.name}>
|
||||||
</p>
|
{name} {occupation && <>- {occupation}</>}
|
||||||
|
</p>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
||||||
|
|
@ -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%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
44
src/components/Testimony/styles.module.scss
Normal file
44
src/components/Testimony/styles.module.scss
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -53,7 +53,8 @@ export const fetchWorship = async (args?: FetchWorshipArgs): Promise<PaginatedDo
|
||||||
type: true,
|
type: true,
|
||||||
date: true,
|
date: true,
|
||||||
cancelled: true,
|
cancelled: true,
|
||||||
location: true
|
location: true,
|
||||||
|
title: true,
|
||||||
},
|
},
|
||||||
limit: 15
|
limit: 15
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export const useCompactDate = (date: string) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return date in user friendly format
|
* Return date in user friendly format
|
||||||
|
* in format DD.MM.YYYY
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const useDate = (date: string) => {
|
export const useDate = (date: string) => {
|
||||||
|
|
|
||||||
31
src/pageComponents/Worship/Worship.stories.tsx
Normal file
31
src/pageComponents/Worship/Worship.stories.tsx
Normal file
|
|
@ -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: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
85
src/pageComponents/Worship/Worship.tsx
Normal file
85
src/pageComponents/Worship/Worship.tsx
Normal file
|
|
@ -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>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
23
src/pageComponents/Worship/styles.module.scss
Normal file
23
src/pageComponents/Worship/styles.module.scss
Normal file
|
|
@ -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%;
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ export const tranformWorship = (worship: Worship[]): (EventRowProps & {id: strin
|
||||||
return worship.map(w => {
|
return worship.map(w => {
|
||||||
return {
|
return {
|
||||||
id: w.id,
|
id: w.id,
|
||||||
title: transformCategory(w.type),
|
title: typeof w.title === "string" ? w.title : transformCategory(w.type),
|
||||||
date: w.date,
|
date: w.date,
|
||||||
href: `/gottesdienst/${w.id}`,
|
href: `/gottesdienst/${w.id}`,
|
||||||
location: typeof w.location === 'string' ? w.location : w.location.name,
|
location: typeof w.location === 'string' ? w.location : w.location.name,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue