feature: some new components

This commit is contained in:
Benno Tielen 2024-11-12 15:39:11 +01:00
parent 0c7c64f7fc
commit 87a9cdd07c
131 changed files with 2734 additions and 439 deletions

View file

@ -1,11 +1,11 @@
import type { Preview } from '@storybook/react' import type { Preview } from '@storybook/react'
import { lato } from '../src/app/fonts' import { defaultFont } from '../src/app/fonts'
const preview: Preview = { const preview: Preview = {
decorators: [ decorators: [
(Story) => { (Story) => {
return ( return (
<div className={lato.className}> <div className={defaultFont.className}>
<Story /> <Story />
</div> </div>
) )

7
_template.scss Normal file
View file

@ -0,0 +1,7 @@
$base-color: #426156;
$shade1: #728F8D;
$shade2: #CBD6D5;
$shade3: #E3E9E8;
$text-color: #000000;
$contrast-color: #ffffff;
$border-radius: 13px;

View file

@ -2,6 +2,10 @@ import { withPayload } from '@payloadcms/next/withPayload'
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
output: "export",
images: {
unoptimized: true
},
// Your Next.js config here // Your Next.js config here
eslint: { eslint: {
// Warning: This allows production builds to successfully complete even if // Warning: This allows production builds to successfully complete even if

View file

@ -13,7 +13,8 @@
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload", "payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
"start": "cross-env NODE_OPTIONS=--no-deprecation next start", "start": "cross-env NODE_OPTIONS=--no-deprecation next start",
"storybook": "storybook dev -p 6006", "storybook": "storybook dev -p 6006",
"build-storybook": "storybook build" "build-storybook": "storybook build",
"chromatic": "npx chromatic --project-token=chpt_70d6a2e05af185a"
}, },
"dependencies": { "dependencies": {
"@payloadcms/db-mongodb": "3.0.0-beta.99", "@payloadcms/db-mongodb": "3.0.0-beta.99",
@ -24,7 +25,7 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"graphql": "^16.8.1", "graphql": "^16.8.1",
"mapbox-gl": "^3.5.2", "mapbox-gl": "^3.5.2",
"next": "15.0.0-canary.123", "next": "^15.0.2",
"payload": "3.0.0-beta.99", "payload": "3.0.0-beta.99",
"react": "19.0.0-rc-f65ac7bd-20240826", "react": "19.0.0-rc-f65ac7bd-20240826",
"react-dom": "19.0.0-rc-f65ac7bd-20240826", "react-dom": "19.0.0-rc-f65ac7bd-20240826",
@ -45,6 +46,7 @@
"@types/node": "^20.12.12", "@types/node": "^20.12.12",
"@types/react": "npm:types-react@19.0.0-rc.0", "@types/react": "npm:types-react@19.0.0-rc.0",
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0", "@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
"chromatic": "^11.12.0",
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "15.0.0-canary.123", "eslint-config-next": "15.0.0-canary.123",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",

View file

@ -1,31 +0,0 @@
'use client'
import { Menu } from '@/components/Menu/Menu'
import { BannerText } from '@/components/BannerText/BannerText'
import {
HomeBanner,
HomeBannerHandle,
} from '@/components/HomeBanner/HomeBanner'
import { useRef } from 'react'
import { Worship } from '@/payload-types'
type BannerWithMenuProps = {
nextMass?: Worship
}
export const BannerWithMenu = ({ nextMass }: BannerWithMenuProps) => {
const bannerRef = useRef<HomeBannerHandle>(null)
function addThreeNewStars() {
bannerRef.current?.newStar()
bannerRef.current?.newStar()
bannerRef.current?.newStar()
}
return (
<HomeBanner stars={40} ref={bannerRef}>
<Menu starClick={addThreeNewStars} nextMass={nextMass} />
<BannerText />
</HomeBanner>
)
}

View file

@ -1,11 +1,11 @@
import { Faustina, Lato } from 'next/font/google' import { Faustina, Cairo } from 'next/font/google'
export const faustina = Faustina({ export const faustina = Faustina({
subsets: ['latin'], subsets: ['latin'],
display: 'swap', display: 'swap',
}) })
export const lato = Lato({ export const defaultFont = Cairo({
subsets: ['latin'], subsets: ['latin'],
weight: ['400'], weight: ['400'],
display: 'swap', display: 'swap',

View file

@ -1,5 +1,5 @@
import type { Metadata } from 'next' import type { Metadata } from 'next'
import { lato } from './fonts' import { defaultFont } from './fonts'
import './globals.css' import './globals.css'
export const metadata: Metadata = { export const metadata: Metadata = {
@ -12,7 +12,7 @@ export default function RootLayout({
children: React.ReactNode children: React.ReactNode
}>) { }>) {
return ( return (
<html lang="en" className={lato.className}> <html lang="en" className={defaultFont.className}>
<body>{children}</body> <body>{children}</body>
</html> </html>
) )

View file

@ -1,14 +0,0 @@
import configPromise from '@payload-config'
import { getPayload } from 'payload'
export const GET = async () => {
const payload = await getPayload({
config: configPromise,
})
const data = await payload.find({
collection: 'users',
})
return Response.json(data)
}

View file

@ -1,84 +1,170 @@
import configPromise from '@payload-config' import { Menu } from '@/components/Menu/Menu'
import { BannerWithMenu } from '@/app/BannerWithMenu' import { Banner } from '@/components/Banner/Banner'
import { Worship } from '@/payload-types' import { Section } from '@/components/Section/Section'
import styles from './home.module.css' import { MainText } from '@/components/MainText/MainText'
import { MassTable } from '@/components/MassTable/MassTable' import { Title } from '@/components/Title/Title'
import { getPayloadHMR } from '@payloadcms/next/utilities' import { ImageCardSlider } from '@/compositions/ImageCardSlider/ImageCardSlider'
import { ImageWithText } from '@/compositions/ImageWithText/ImageWithText'
import { Container } from '@/components/Container/Container'
import { ContactSection } from '@/compositions/ContactSection/ContactSection'
import { Footer } from '@/compositions/Footer/Footer'
import { EventRow } from '@/components/EventRow/EventRow'
import monst from "./mons.jpg"
import bread from "./bread.jpg"
import candle from "./candle.png"
import { SideSlider } from '@/components/SideSlider/SideSlider'
import { ContentWithSlider } from '@/compositions/ContentWithSlider/ContentWithSlider'
const extractWorshipHours = (worships: Worship[]) => { // const extractWorshipHours = (worships: Worship[]) => {
let worshipByDate = new Map<string, Worship[]>() // let worshipByDate = new Map<string, Worship[]>()
//
for (let worship of worships) { // for (let worship of worships) {
const date = worship.date.substring(0, 10) // const date = worship.date.substring(0, 10)
//
if (worshipByDate.has(date)) { // if (worshipByDate.has(date)) {
worshipByDate.get(date)?.push(worship) // worshipByDate.get(date)?.push(worship)
} else { // } else {
worshipByDate.set(date, [worship]) // worshipByDate.set(date, [worship])
} // }
} // }
//
return worshipByDate // return worshipByDate
} // }
export default async function Home() { export default async function Home() {
const today = new Date() // const today = new Date()
const nextWeek = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000) // const nextWeek = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000)
const payload = await getPayloadHMR({ config: configPromise }) // const payload = await getPayloadHMR({ config: configPromise })
const worship = await payload.find({ // const worship = await payload.find({
collection: 'worship', // collection: 'worship',
where: { // where: {
and: [ // and: [
{ // {
date: { // date: {
greater_than_equal: today.toISOString().substring(0, 10), // greater_than_equal: today.toISOString().substring(0, 10),
}, // },
}, // },
{ // {
date: { // date: {
less_than: nextWeek.toISOString().substring(0, 10), // less_than: nextWeek.toISOString().substring(0, 10),
}, // },
}, // },
], // ],
}, // },
limit: 30, // limit: 30,
sort: 'date', // sort: 'date',
}) // })
//
const nextMass = await payload.find({ // const nextMass = await payload.find({
collection: 'worship', // collection: 'worship',
where: { // where: {
and: [ // and: [
{ // {
date: { // date: {
greater_than_equal: today.toISOString(), // greater_than_equal: today.toISOString(),
}, // },
}, // },
{ // {
cancelled: { // cancelled: {
equals: false, // equals: false,
}, // },
}, // },
], // ],
}, // },
limit: 1, // limit: 1,
sort: 'date', // sort: 'date',
}) // })
//
const worshipByDate = [...extractWorshipHours(worship.docs).entries()] // const worshipByDate = [...extractWorshipHours(worship.docs).entries()]
return ( return (
<> <>
<BannerWithMenu nextMass={nextMass.docs[0]} /> <Menu/>
<div className={styles.mass}> <Banner/>
<h2>Kommen Sie zu unserer Heiligen Messe vorbei!</h2>
<Container>
<Section>
<MainText text={"Wir begrüßen Sie herzlich in unserer Pfarrei Hl. Drei Könige und im bunten Neukölln mit einer Vielfalt von Kulturen und Nationalitäten. \n" +
"Wie die drei Weisen aus dem Morgenland wollen wir uns immer wieder neu auf den Weg machen."} />
</Section>
<Section>
<Title title={"Aktuelles"} />
<ImageCardSlider slides={[
{
id: "id1",
src: monst,
title: "Anbetung in Oktober",
href: "https://somelink"
},
{
id: "id2",
src: candle,
title: "Allerseelen",
href: "https://somelink"
},
{
id: "id3",
src: bread,
title: "Erntedankfest",
href: "https://somelink"
}
]} />
</Section>
</Container>
<ImageWithText />
<ContentWithSlider slider={<>
<Title title={"Akutelle Highlights"} size={"md"} fontStyle={"sans-serif"} />
</>}>
<Container position={"right"}>
<Section>
<Title title={"Veranstaltungen"} />
<EventRow
date={"2024-10-23T16:00:00"}
title={"Gemeinsam beten"}
href={"https://link"}
location={"St. Christophorus"}
/>
<EventRow
date={"2024-10-28T19:45:00"}
title={"Rosenkranz"}
href={"https://link"}
location={"St. Clara"}
/>
<EventRow
date={"2024-11-02T19:00:00"}
title={"Allerseelen"}
href={"https://link"}
location={"St. Michael"}
/>
<EventRow
date={"2024-11-11T18:00:00"}
title={"St. Martin"}
href={"https://link"}
location={"Sportplatz St. Christophorus"}
/>
<EventRow
date={"2024-11-11T18:00:00"}
title={"St. Martin"}
href={"https://link"}
location={"Sportplatz St. Christophorus"}
/>
<EventRow
date={"2024-11-11T18:00:00"}
title={"St. Martin"}
href={"https://link"}
location={"Sportplatz St. Christophorus"}
/>
</Section>
</Container>
</ContentWithSlider>
<ContactSection />
<Footer />
<div className={styles.table}>
{worshipByDate.map(([date, worships]) => (
<MassTable key={date} date={date} masses={worships} />
))}
</div>
</div>
</> </>
) )
} }

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00195 17H5.60636C4.34793 17 3.71872 17 3.58633 16.9023C3.4376 16.7925 3.40126 16.7277 3.38515 16.5436C3.37082 16.3797 3.75646 15.7486 4.52776 14.4866C5.32411 13.1835 6.00031 11.2862 6.00031 8.6C6.00031 7.11479 6.63245 5.69041 7.75766 4.6402C8.88288 3.59 10.409 3 12.0003 3C13.5916 3 15.1177 3.59 16.2429 4.6402C17.3682 5.69041 18.0003 7.11479 18.0003 8.6C18.0003 11.2862 18.6765 13.1835 19.4729 14.4866C20.2441 15.7486 20.6298 16.3797 20.6155 16.5436C20.5994 16.7277 20.563 16.7925 20.4143 16.9023C20.2819 17 19.6527 17 18.3943 17H15.0003M9.00195 17L9.00031 18C9.00031 19.6569 10.3435 21 12.0003 21C13.6572 21 15.0003 19.6569 15.0003 18V17M9.00195 17H15.0003" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 982 B

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 21C15.5 17.4 19 14.1764 19 10.2C19 6.22355 15.866 3 12 3C8.13401 3 5 6.22355 5 10.2C5 14.1764 8.5 17.4 12 21Z" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 13C13.6569 13 15 11.6569 15 10C15 8.34315 13.6569 7 12 7C10.3431 7 9 8.34315 9 10C9 11.6569 10.3431 13 12 13Z" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 641 B

View file

@ -1,103 +0,0 @@
import { getPayloadHMR } from '@payloadcms/next/utilities'
import configPromise from '@payload-config'
import { Menu } from '@/components/Menu/Menu'
import { useLocation } from '@/hooks/useLocation'
import { useLiturgyCalendarTitle } from '@/hooks/useLiturgyCalendarTitle'
import { Container } from '@/components/Container/Container'
import { Card } from '@/components/Card/Card'
import styles from './styles.module.css'
import { MassTitle } from '@/components/MassTitle/MassTitle'
import { useDate } from '@/hooks/useCompactDate'
import { useTime } from '@/hooks/useTime'
import { Pill } from '@/components/Pill/Pill'
import { useMassType } from '@/hooks/useMassType'
import Image from 'next/image'
import bell from './bell.svg'
import locationIcon from './location.svg'
import question from './question.svg'
import { LocationMap } from '@/components/Map/Map'
import { Testimony } from '@/components/Testimony/Testimony'
import { randomTestimony } from '@/utils/randomTestimony'
export default async function Page({ params }: { params: { id: string } }) {
const payload = await getPayloadHMR({ config: configPromise })
const worship = await payload.findByID({
id: params.id,
collection: 'worship',
})
const testimony = await randomTestimony('EUCHARIST')
const location = useLocation(worship.location)
const title = useLiturgyCalendarTitle(worship.date)
const date = useDate(worship.date)
const time = useTime(worship.date)
const type = useMassType(worship.type)
return (
<>
<Menu />
<Container>
<MassTitle title={title} cancelled={worship.cancelled} />
<div className={styles.info}>
<Card>
<div className={styles.centerIcon}>
<Image
src={bell}
alt={'Location'}
width={60}
className={styles.cardIcon}
/>
</div>
<div className={styles.cardContent}>
<div className={styles.marginBottom}>
{date} <br />
{time} Uhr <br />
</div>
<Pill>{type}</Pill>
</div>
</Card>
<Card>
<div className={styles.centerIcon}>
<Image
src={locationIcon}
alt={'Location'}
width={60}
className={styles.cardIcon}
/>
</div>
<div className={styles.cardContent}>
<div className={styles.address}>
{location.name} <br />
{location.address}
</div>
</div>
</Card>
{worship.description && (
<Card>
<div className={styles.centerIcon}>
<Image
src={question}
alt={'Location'}
width={60}
className={styles.cardIcon}
/>
</div>
<div className={styles.cardText}>{worship.description}</div>
</Card>
)}
</div>
</Container>
<LocationMap />
<Testimony
name={testimony.name}
testimony={testimony.testimony}
occupation={testimony.occupation || undefined}
/>
</>
)
}

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.967 12.75C12.967 11.75 13.967 11.3546 13.967 10.25C13.967 9.14543 13.0716 8.25 11.967 8.25C11.0351 8.25 10.252 8.88739 10.03 9.75M11.967 15.75H11.977M21.0039 12C21.0039 16.9706 16.9745 21 12.0039 21C9.9675 21 3.00463 21 3.00463 21C3.00463 21 4.56382 17.2561 3.93982 16.0008C3.34076 14.7956 3.00391 13.4372 3.00391 12C3.00391 7.02944 7.03334 3 12.0039 3C16.9745 3 21.0039 7.02944 21.0039 12Z" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 715 B

View file

@ -1,42 +0,0 @@
.info {
display: flex;
gap: 30px;
margin-bottom: 80px;
flex-wrap: wrap;
justify-content: center;
}
.cardContent {
padding-top: 30px;
text-align: center;
}
.cardText {
padding-top: 30px;
padding-left: 20px;
padding-right: 20px;
}
.marginBottom {
margin-bottom: 20px;
}
.address {
white-space: pre;
}
.cardIcon {
margin-bottom: 10px;
margin-left: auto;
margin-right: auto;
transition: transform 100ms;
}
.cardIcon:hover {
transform: rotateZ(-20deg);
}
.centerIcon {
padding-top: 30px;
text-align: center;
}

View file

@ -0,0 +1,21 @@
import { Meta, StoryObj } from '@storybook/react'
import { Arrow } from './Arrow'
const meta: Meta<typeof Arrow> = {
component: Arrow,
}
type Story = StoryObj<typeof Arrow>;
export default meta
export const Left: Story = {
args: {
direction: "left"
},
}
export const Right: Story = {
args: {
direction: "right"
},
}

View file

@ -0,0 +1,3 @@
<svg width="21" height="56" viewBox="0 0 21 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 1.53406L2.68974 27.0243C2.26927 27.6814 2.26927 28.5231 2.68974 29.1802L19 54.6704" stroke="#426156" stroke-width="3"/>
</svg>

After

Width:  |  Height:  |  Size: 236 B

View file

@ -0,0 +1,12 @@
import arrow from "./Arrow.svg"
import Image from 'next/image'
type ArrowProps = {
direction: "left" | "right"
}
export const Arrow = ({direction}: ArrowProps) => {
return (
<Image src={arrow} alt={""} style={{transform: `rotate(${direction === 'left' ? 0 : 180}deg)`}}/>
)
}

View file

@ -0,0 +1,13 @@
import { Meta, StoryObj } from '@storybook/react'
import { Banner } from './Banner'
const meta: Meta<typeof Banner> = {
component: Banner,
}
type Story = StoryObj<typeof Banner>;
export default meta
export const Default: Story = {
args: {},
}

View file

@ -0,0 +1,13 @@
import { Logo } from '@/components/Logo/Logo'
import styles from "./styles.module.scss"
export const Banner = () => {
return (
<div className={styles.banner}>
<div className={styles.logo}>
<Logo color={"#ffffff"} />
</div>
</div>
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

View file

@ -0,0 +1,13 @@
.banner {
position: relative;
height: 634px;
background-image: url("banner.jpg");
background-size: cover;
background-position: top center;
}
.logo {
position: absolute;
bottom: 20px;
left: 30px;
}

View file

@ -0,0 +1,23 @@
import { Meta, StoryObj } from "@storybook/react"
import { Button } from './Button'
const meta: Meta<typeof Button> = {
component: Button
}
type Story = StoryObj<typeof Button>
export default meta
export const Large: Story = {
args: {
children: 'Mehr erfahren...',
size: "lg"
}
}
export const Medium: Story = {
args: {
children: 'Weiterlesen',
size: "md"
}
}

View file

@ -0,0 +1,32 @@
import styles from "./styles.module.scss"
import classNames from 'classnames'
type ButtonProps = {
size: 'lg' | 'md'
type?: "button" | "submit" | "reset",
children: React.ReactNode,
onClick?: () => void,
}
export function Button(
{
type = "button",
size,
children,
onClick
}: ButtonProps
) {
return (
<button
type={type}
onClick={onClick}
className={classNames({
[styles.button]: true,
[styles.lg]: size === 'lg',
[styles.md]: size === 'md',
})}
>
{children}
</button>
)
}

View file

@ -0,0 +1,26 @@
@import 'template.scss';
.button {
background: $shade1;
color: $contrast-color;
border-radius: $border-radius;
text-align: center;
border: 0;
font-weight: bold;
transition: background 0.2s;
cursor: pointer;
}
.button:hover {
background: $base-color;
}
.lg {
font-size: 18px;
padding: 20px 40px;
}
.md {
font-size: 14px;
padding: 10px 35px;
}

View file

@ -0,0 +1,3 @@
export const ChurchCard = () => {
}

View file

@ -0,0 +1,39 @@
import { Meta, StoryObj } from '@storybook/react'
import { ChurchIcon } from './ChurchIcon'
const meta: Meta<typeof ChurchIcon> = {
component: ChurchIcon,
}
type Story = StoryObj<typeof ChurchIcon>;
export default meta
export const StClara: Story = {
args: {
church: "clara"
},
}
export const StChristophorus: Story = {
args: {
church: "christophorus"
},
}
export const StRichard: Story = {
args: {
church: "richard"
},
}
export const StEduard: Story = {
args: {
church: "eduard"
},
}
export const StAnna: Story = {
args: {
church: "anna"
},
}

View file

@ -0,0 +1,32 @@
import christophorus from "./christophorus_full.svg"
import clara from "./clara_full.svg"
import anna from "./anna_full.svg"
import richard from "./richard_full.svg"
import eduard from "./eduard_full.svg"
import Image from 'next/image'
type ChurchIconProps = {
church: "clara" | "christophorus" | "richard" | "eduard" | "anna"
}
export const ChurchIcon = ({church}: ChurchIconProps) => {
if (church === "clara") {
return <Image src={clara} alt={""} />
}
if (church === "anna") {
return <Image src={anna} alt={""} />
}
if (church === "richard") {
return <Image src={richard} alt={""} />
}
if (church === "eduard") {
return <Image src={eduard} alt={""} />
}
return (
<Image src={christophorus} alt={"chris"} />
)
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 239.12 255.74"><defs><style>.cls-1{fill:#426156;}</style></defs><g id="St._Anna" data-name="St. Anna"><path class="cls-1" d="M152.23,122.54V82L120.42,64.87V54.56h2.28v-1h-2.28V48.45h-1v5.11H117v1h2.43v10.3L88.07,82.49v40.3L42,134.05l-.24,91.47v.5h157.1V133.81ZM88.07,225H42.8L43,134.84l45-11Zm63.16,0H89.07V83.08l30.84-17.35,31.32,16.86Zm46.66,0H152.23V123.57l45.66,11Z"/><polygon class="cls-1" points="197.89 134.59 197.89 225.02 152.23 225.02 152.23 123.57 197.89 134.59"/><polygon class="cls-1" points="151.23 82.59 151.23 225.02 89.07 225.02 89.07 83.08 119.91 65.73 151.23 82.59"/><polygon class="cls-1" points="88.07 123.82 88.07 225.02 42.8 225.02 43.04 134.84 88.07 123.82"/></g></svg>

After

Width:  |  Height:  |  Size: 746 B

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 175.75 265.12"
version="1.1"
id="svg34"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs27">
<style
id="style25">.cls-1{fill:#426156;}</style>
</defs>
<g
id="St._Christophorus"
data-name="St. Christophorus">
<path
class="cls-1"
d="M 114.44,72.08 V 62 h 2.27 v -1 h -2.27 v -5.16 h -1 V 61 H 111 v 1 h 2.43 V 72.1 L 71,89.31 v 115 l -23.19,17.23 v 5.94 l -29.37,0.08 v 23 H 151.35 V 89.87 Z M 113.93,73 c -75.953333,-48.666667 -37.976667,-24.333333 0,0 z"
id="path29" />
</g>
<g
id="fill">
<polygon
class="cls-1"
points="113.89,72.99 114.02,72.99 150.35,90.49 150.35,249.55 19.48,249.55 19.44,228.56 48.81,228.48 48.81,222.04 71.96,204.81 71.96,89.98 "
id="polygon31"
style="fill:#426156"
transform="translate(0.04,0.01)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 972 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 175.75 265.12"><defs><style>.cls-1{fill:#426156;}</style></defs><g id="St._Eduard" data-name="St. Eduard"><path class="cls-1" d="M136.16,177.51,87,137.13v-10.8H89.3v-1H87v-5.11H86v5.11H83.59v1H86v10.8l-15.61,13v-30L44.35,34.18V24.76h2.28v-1H44.35V18.65h-1v5.11H40.92v1h2.43v9.4L22.79,103.52l0,137.14,47.14-.4H153.4V177.51ZM69.41,239.27l-45.64.38V103.74L43.85,36,69.41,120.2Zm83,0h-82V151.39L86.52,138l49.28,40.49h16.6Z"/><polygon class="cls-1" points="152.4 178.51 152.4 239.26 70.41 239.26 70.41 151.39 86.52 138.02 135.8 178.51 152.4 178.51"/><polygon class="cls-1" points="69.41 120.2 69.41 239.27 23.77 239.65 23.77 103.74 43.85 35.98 69.41 120.2"/></g></svg>

After

Width:  |  Height:  |  Size: 716 B

View file

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 175.75 265.12">
<defs>
<style>.cls-1{fill:#426156;}</style>
</defs>
<g id="St._Eduard" data-name="St. Eduard">
<path class="cls-1"
d="M117.83,161.61,98.29,172.73V127.88L75.51,31V20h2.28V19H75.51V13.92h-1V19H72.08v1h2.43V31L51.25,127.28v34.3H40.38L24,184.82l-.09.13v63.49H150.17V190.29ZM51.24,247.44H24.92V185.26l16-22.68H51.24Zm46.05,0H52.24v-120L75,33.22l22.29,94.72Zm51.88,0H98.29V173.88l19.41-11,31.47,27.91Z"/>
<polygon class="cls-1"
points="149.17 190.74 149.17 247.44 98.29 247.44 98.29 173.88 117.7 162.83 149.17 190.74"/>
<polygon class="cls-1" points="97.29 127.94 97.29 247.44 52.24 247.44 52.24 127.45 75 33.22 97.29 127.94"/>
<polygon class="cls-1" points="51.24 162.58 51.24 247.44 24.92 247.44 24.92 185.26 40.9 162.58 51.24 162.58"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 905 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 221.52 164.2"><defs><style>.cls-1{fill:#426156;}.cls-2{fill:#728f8d;}.cls-3{fill:#fff;}</style></defs><g id="St._Christophorus" data-name="St. Christophorus"><path class="cls-1" d="M74.29,20.71l-.23-.06L19.41,61.34v74.19H191.77V49.77Zm-.62,113.82H20.41V61.84L73.67,22.19Zm117.1,0H74.67V21.83l116.1,28.73Z"/><path class="cls-2" d="M74.67,21.83v112.7h116.1v-84Zm17.64,23.1H90V56H89v-11H86.6v-1H89V38.82h1v5.11h2.28Z"/><polygon class="cls-1" points="73.67 22.19 73.67 134.53 20.41 134.53 20.41 61.84 73.67 22.19"/><polygon class="cls-3" points="92.31 43.93 92.31 44.93 90.03 44.93 90.03 55.97 89.03 55.97 89.03 44.93 86.6 44.93 86.6 43.93 89.03 43.93 89.03 38.82 90.03 38.82 90.03 43.93 92.31 43.93"/></g></svg>

After

Width:  |  Height:  |  Size: 761 B

View file

@ -1,9 +1,16 @@
import styles from './styles.module.css' import styles from './styles.module.scss'
import classNames from 'classnames'
type ContainerProps = { type ContainerProps = {
children: JSX.Element | JSX.Element[] children: JSX.Element | JSX.Element[],
flex?: boolean
position?: "center" | "left" | "right"
} }
export const Container = ({ children }: ContainerProps) => { export const Container = ({ children, flex = false, position = "center" }: ContainerProps) => {
return <div className={styles.container}>{children}</div> return <div className={classNames({
[styles.container]: true,
[styles.flex]: flex,
[styles.right]: position === "right",
})}>{children}</div>
} }

View file

@ -1,10 +0,0 @@
.container {
max-width: 800px;
margin: 0 auto;
}
@media screen and (max-width: 800px) {
.container {
padding: 0 20px;
}
}

View file

@ -0,0 +1,25 @@
$width: 1100px;
.container {
max-width: $width;
margin: 0 auto;
}
.flex {
display: flex;
gap: 80px;
align-items: center;
flex-wrap: wrap;
}
.right {
max-width: inherit;
margin-left: calc((100vw - $width) / 2);
}
@media screen and (max-width: $width) {
.container {
padding: 0 20px;
margin: 0;
}
}

View file

@ -0,0 +1,39 @@
import { Meta, StoryObj } from '@storybook/react'
import { EventRow } from './EventRow'
const meta: Meta<typeof EventRow> = {
component: EventRow,
}
type Story = StoryObj<typeof EventRow>;
export default meta
export const EventInJanuary: Story = {
args: {
date: '2024-01-06T15:00:00+01:00',
title: 'Herz Jesu Feier',
href: 'https://www.herzJesuFeier.com',
location: "St. Clara",
cancelled: false,
},
}
export const EventInMarch: Story = {
args: {
date: '2024-03-24T15:00:00+01:00',
title: 'Osternacht',
href: 'https://www.link_to_event.com',
location: "St. Richard",
cancelled: false
},
}
export const CancelledEvent: Story = {
args: {
date: '2024-03-24T15:00:00+01:00',
title: 'Osternacht',
href: 'https://www.link_to_event.com',
location: "St. Richard",
cancelled: true
},
}

View file

@ -0,0 +1,65 @@
import { useMemo } from 'react'
import styles from "./styles.module.scss"
import classNames from 'classnames'
type EventRowProps = {
/** datetime 8601 format */
date: string,
title: string,
href: string,
location?: string,
cancelled: boolean
}
/**
* Given a date in ISO 8601 format,
* return a short readable version
*/
const shortMonth = (date: string) => {
const months = [
"JAN",
"FEB",
"MRZ",
"APR",
"MAI",
"JUN",
"JUL",
"AUG",
"SEP",
"OKT",
"NOV",
"DEC"
]
const month = parseInt(date.substring(5, 7));
return months[month - 1];
}
export const EventRow = ({date, title, location, cancelled}: EventRowProps) => {
const day = useMemo(() => date.substring(8, 10), [date]);
const dateObj = useMemo(() => new Date(date), [date]);
const month = useMemo(() => shortMonth(date), [date]);
return (
<div className={styles.container}>
<div className={styles.day}>
{day} <br/>
{month}
</div>
<div className={styles.line}></div>
<div className={classNames({
[styles.details]: true,
[styles.cancelled]: cancelled
})}>
{title} <br/>
{dateObj.toLocaleDateString("de-DE", { weekday: "long"})} {dateObj.toLocaleDateString("de-DE", {dateStyle: "medium"})}, {dateObj.toLocaleTimeString("de-DE", {timeStyle: "short"})} Uhr
<br/>
{location}
</div>
</div>
);
}

View file

@ -0,0 +1,48 @@
@import "template.scss";
.day {
color: $base-color;
line-height: 105%;
font-size: 25px;
font-weight: bold;
text-align: center;
margin-left: 30px;
transition: color 0.2s ease-in;
}
.line {
width: 0.7px;
background: $base-color;
height: 96px;
margin: 0 30px;
}
.details {
line-height: 147%;
}
.container {
display: flex;
align-items: center;
cursor: pointer;
margin: 20px 0;
}
.cancelled {
text-decoration: line-through;
}
.container:hover .day {
color: $shade1;
}
@media screen and (max-width: 576px) {
.day {
margin-left: 15px;
}
.line {
margin: 0 15px;
height: 70px;
}
}

View file

@ -0,0 +1,13 @@
import styles from "./styles.module.scss"
type ColProps = {
children: React.ReactNode;
}
export const Col = ({children}: ColProps) => {
return (
<div className={styles.col}>
{children}
</div>
)
}

View file

@ -0,0 +1,9 @@
.col {
width: calc(50% - 40px);
}
@media screen and (max-width: 576px) {
.col {
flex: 0 0 100%;
}
}

View file

@ -0,0 +1,18 @@
import { Meta, StoryObj } from "@storybook/react"
import { Image } from './Image'
const meta: Meta<typeof Image> = {
component: Image
}
type Story = StoryObj<typeof Image>
export default meta
export const Default: Story = {
args: {
src: "https://www.holycross.edu/sites/default/files/styles/768w/public/mrf/rs74874_100314_fall_27_0.webp?itok=WEQQUXdO",
width: 500,
height: 400,
alt: "Some description",
}
}

View file

@ -0,0 +1,20 @@
import Img, { StaticImageData } from 'next/image'
type ImageProps = {
src: string | StaticImageData,
width: number,
height: number,
alt: string,
}
export const Image = ({src, width, height, alt}: ImageProps) => {
return (
<Img
style={{borderRadius: "13px"}}
src={src}
width={width}
height={height}
alt={alt}
/>
)
}

View file

@ -0,0 +1,23 @@
import { Meta, StoryObj } from '@storybook/react'
import { ImageCard } from './ImageCard'
const meta: Meta<typeof ImageCard> = {
component: ImageCard,
decorators: [
(Story) => (
<div style={{ width: "200px", height: "200px"}}>
<Story />
</div>
)
]
}
type Story = StoryObj<typeof ImageCard>;
export default meta
export const Default: Story = {
args: {
src: "https://www.sfcatholic.org/bishopsbulletin/wp-content/uploads/sites/3/2022/04/monstrance2-insta-1024x1024.jpg",
title: "Anbetung in Oktober"
},
}

View file

@ -0,0 +1,18 @@
import styles from "./styles.module.scss"
import { StaticImageData } from 'next/image'
type ImageCardProps = {
src: string | StaticImageData,
title: string,
href: string
}
export const ImageCard = ({src, title, href}: ImageCardProps) => {
return (
<div className={styles.container} style={{backgroundImage: `url(${src})`}}>
<div className={styles.title}>
{title}
</div>
</div>
)
}

View file

@ -0,0 +1,30 @@
@import "template.scss";
.container {
aspect-ratio: 1/1;
background-color: #c2c2c2;
background-position: center;
background-size: cover;
box-shadow: 3px 7px 26px -5px rgba(0, 0, 0, 0.15);
cursor: pointer;
overflow: hidden;
border-radius: $border-radius;
position: relative;
}
.title {
background-color: rgba(255, 255, 255, 0.91);
text-align: center;
font-size: 18px;
position: absolute;
bottom: 0px;
width: 100%;
color: $base-color;
padding: 10px 0;
transition: padding 0.3s ease-out;
border-radius: $border-radius;
}
.container:hover .title {
padding: 30px 0 70px 0;
}

View file

@ -0,0 +1,26 @@
import styles from "./styles.module.scss"
type InputProps = {
name: string;
type: 'textarea' | 'text' | 'email'
placeholder?: string
}
export const Input = ({name, type, placeholder}: InputProps) => {
if (type === 'textarea') {
return (
<textarea name={name} className={styles.input} placeholder={placeholder}>
</textarea>
)
}
return (
<input
className={styles.input}
type={type}
name={name}
placeholder={placeholder}
/>
)
}

View file

@ -0,0 +1,25 @@
import { Meta, StoryObj } from '@storybook/react'
import { Input } from './Input'
const meta: Meta<typeof Input> = {
component: Input,
}
type Story = StoryObj<typeof Input>;
export default meta
export const Default: Story = {
args: {
type: "text",
name: "name",
placeholder: "Name"
},
}
export const TextArea: Story = {
args: {
type: "textarea",
name: "name",
placeholder: "Ihre Nachricht"
},
}

View file

@ -0,0 +1,19 @@
@import "template.scss";
.input {
background-color: $shade2;
padding: 10px 20px;
font-size: 20px;
border: none;
font-family: inherit;
border-radius: $border-radius;
width: 100%;
box-sizing: border-box;
}
@media screen and (max-width: 576px) {
.input {
padding: 5px 10px;
font-size: 16px;
}
}

View file

@ -0,0 +1,50 @@
import { Meta, StoryObj } from '@storybook/react'
import { Logo } from './Logo'
const meta: Meta<typeof Logo> = {
component: Logo,
}
type Story = StoryObj<typeof Logo>;
export default meta
export const Simple: Story = {
args: {
withText: false,
color: '#000000',
height: 75
},
}
export const WithText: Story = {
args: {
withText: true,
color: '#000000',
height: 75
},
}
export const Green: Story = {
args: {
withText: false,
color: '#426156',
height: 75
},
}
export const BigAndBoldlyPink: Story = {
args: {
withText: true,
color: '#E41A7F',
height: 350
},
}
export const DifferentTextColor: Story = {
args: {
withText: true,
color: '#426156',
textColor: '#728F8D',
height: 350
},
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -0,0 +1,16 @@
import { Meta, StoryObj } from '@storybook/react'
import { MainText } from './MainText'
const meta: Meta<typeof MainText> = {
component: MainText,
}
type Story = StoryObj<typeof MainText>
export default meta
export const Default: Story = {
args: {
text: 'Wir begrüßen Sie herzlich in unserer Pfarrei Hl. Drei Könige und im bunten Neukölln mit einer Vielfalt von Kulturen und Nationalitäten. \n' +
'Wie die drei Weisen aus dem Morgenland wollen wir uns immer wieder neu auf den Weg machen.',
},
}

View file

@ -0,0 +1,13 @@
import styles from "./styles.module.scss"
type MainTextProps = {
text: string;
}
export const MainText = ({text}: MainTextProps) => {
return (
<div className={styles.mainText}>
{text}
</div>
)
}

View file

@ -0,0 +1,11 @@
.mainText {
line-height: 168%;
font-size: 36px;
text-align: center;
}
@media screen and (max-width: 576px) {
.mainText {
font-size: 24px;
}
}

View file

@ -10,11 +10,11 @@ type Story = StoryObj<typeof meta>
export const Default: Story = { export const Default: Story = {
args: { args: {
date: '2024-08-04', location: 'St. Clara',
masses: [ masses: [
{ {
id: '1', id: '1',
date: '10:00', date: '2024-08-21T15:00:00.000Z',
location: 'St. Christopherus', location: 'St. Christopherus',
type: 'MASS', type: 'MASS',
cancelled: false, cancelled: false,
@ -23,7 +23,7 @@ export const Default: Story = {
}, },
{ {
id: '1', id: '1',
date: '10:00', date: '2024-08-23T18:00:00.000Z',
location: 'St. Christopherus', location: 'St. Christopherus',
type: 'MASS', type: 'MASS',
cancelled: false, cancelled: false,
@ -32,19 +32,19 @@ export const Default: Story = {
}, },
{ {
id: '1', id: '1',
date: '10:00', date: '2024-08-24T09:00:00.000Z',
location: 'St. Christopherus', location: 'St. Christopherus',
type: 'MASS', type: 'WORD',
cancelled: false, cancelled: false,
updatedAt: '', updatedAt: '',
createdAt: '', createdAt: '',
}, },
{ {
id: '1', id: '1',
date: '10:00', date: '2024-08-26T15:00:00.000Z',
location: 'St. Christopherus', location: 'St. Christopherus',
type: 'MASS', type: 'MASS',
cancelled: false, cancelled: true,
updatedAt: '', updatedAt: '',
createdAt: '', createdAt: '',
}, },

View file

@ -6,30 +6,22 @@ import { Worship } from '@/payload-types'
import { useCompactDate } from '@/hooks/useCompactDate' import { useCompactDate } from '@/hooks/useCompactDate'
type MassTableProps = { type MassTableProps = {
date: string location: string
masses: Worship[] masses: Worship[]
} }
export const MassTable = ({ date, masses }: MassTableProps) => { export const MassTable = ({ location, masses }: MassTableProps) => {
let dateObj = useMemo(() => new Date(date), [date])
let compactDate = useCompactDate(date)
return ( return (
<div className={styles.table}> <div className={styles.table}>
<h3 className={faustina.className}> <h3 className={faustina.className}>
{dateObj.toLocaleDateString('de-DE', { weekday: 'long' })}{' '} {location}
<small>{compactDate}</small>
</h3> </h3>
{masses.map((mass) => ( {masses.map((mass) => (
<MassTableRow <MassTableRow
key={mass.id} key={mass.id}
id={mass.id} id={mass.id}
locationName={
typeof mass.location == 'string'
? mass.location
: mass.location.name
}
date={mass.date} date={mass.date}
type={mass.type} type={mass.type}
cancelled={mass.cancelled} cancelled={mass.cancelled}

View file

@ -11,7 +11,6 @@ type Story = StoryObj<typeof meta>
export const Default: Story = { export const Default: Story = {
args: { args: {
id: '1', id: '1',
locationName: 'St. Clara',
date: '2024-08-23T15:00:00.000Z', date: '2024-08-23T15:00:00.000Z',
type: 'MASS', type: 'MASS',
cancelled: false, cancelled: false,
@ -21,7 +20,6 @@ export const Default: Story = {
export const FamilyMass: Story = { export const FamilyMass: Story = {
args: { args: {
id: '1', id: '1',
locationName: 'St. Christopherus',
date: '2024-08-23T15:00:00.000Z', date: '2024-08-23T15:00:00.000Z',
type: 'FAMILY', type: 'FAMILY',
cancelled: false, cancelled: false,
@ -31,7 +29,6 @@ export const FamilyMass: Story = {
export const LiturgyOfTheWord: Story = { export const LiturgyOfTheWord: Story = {
args: { args: {
id: '1', id: '1',
locationName: 'St. Richard',
date: '2024-08-23T15:00:00.000Z', date: '2024-08-23T15:00:00.000Z',
type: 'WORD', type: 'WORD',
cancelled: false, cancelled: false,
@ -41,7 +38,6 @@ export const LiturgyOfTheWord: Story = {
export const Cancelled: Story = { export const Cancelled: Story = {
args: { args: {
id: '1', id: '1',
locationName: 'St. Richard',
date: '2024-08-23T15:00:00.000Z', date: '2024-08-23T15:00:00.000Z',
type: 'WORD', type: 'WORD',
cancelled: true, cancelled: true,

View file

@ -8,10 +8,10 @@ import { useState } from 'react'
import Link from 'next/link' import Link from 'next/link'
import classNames from 'classnames' import classNames from 'classnames'
import { useTime } from '@/hooks/useTime' import { useTime } from '@/hooks/useTime'
import { useCompactDate, useShortDayName } from '@/hooks/useCompactDate'
export type MassTableRowProps = { export type MassTableRowProps = {
id: string id: string
locationName: string
date: string date: string
type: 'MASS' | 'FAMILY' | 'WORD' type: 'MASS' | 'FAMILY' | 'WORD'
cancelled: boolean cancelled: boolean
@ -19,13 +19,15 @@ export type MassTableRowProps = {
export const MassTableRow = ({ export const MassTableRow = ({
id, id,
locationName,
date, date,
type, type,
cancelled, cancelled,
}: MassTableRowProps) => { }: MassTableRowProps) => {
const [symbol, setSymbol] = useState('-') const [symbol, setSymbol] = useState('-')
const time = useTime(date) const time = useTime(date)
const compactDate = useCompactDate(date)
const day = useShortDayName(date)
return ( return (
<Link <Link
href={`/worship/${id}`} href={`/worship/${id}`}
@ -36,10 +38,10 @@ export const MassTableRow = ({
onMouseEnter={() => setSymbol('†')} onMouseEnter={() => setSymbol('†')}
onMouseLeave={() => setSymbol('-')} onMouseLeave={() => setSymbol('-')}
> >
<div className={styles.time}>{time}</div> <div className={styles.time}>{day} {compactDate}</div>
<div className={styles.symbol}>{symbol}</div> <div className={styles.symbol}>{symbol}</div>
<div>{locationName}</div> <div>{time}</div>
<div>
{type === 'FAMILY' && ( {type === 'FAMILY' && (
<Image src={family} width={18} height={18} alt={'Familien Messe'} /> <Image src={family} width={18} height={18} alt={'Familien Messe'} />
)} )}
@ -47,7 +49,6 @@ export const MassTableRow = ({
{type === 'WORD' && ( {type === 'WORD' && (
<Image src={bible} width={18} height={18} alt={'Wortgottesfeier'} /> <Image src={bible} width={18} height={18} alt={'Wortgottesfeier'} />
)} )}
</div>
</div> </div>
</Link> </Link>
) )

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> <?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="-32 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M448 358.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16c0-6.4-3.2-12.8-9.6-19.2-3.2-16-3.2-60.8 0-73.6 6.4-3.2 9.6-9.6 9.6-19.2zM144 144c0-8.84 7.16-16 16-16h48V80c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v48h48c8.84 0 16 7.16 16 16v32c0 8.84-7.16 16-16 16h-48v112c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16V192h-48c-8.84 0-16-7.16-16-16v-32zm236.8 304H96c-19.2 0-32-12.8-32-32s16-32 32-32h284.8v64z"/></svg> <svg fill="#728F8D" width="800px" height="800px" viewBox="-32 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M448 358.4V25.6c0-16-9.6-25.6-25.6-25.6H96C41.6 0 0 41.6 0 96v320c0 54.4 41.6 96 96 96h326.4c12.8 0 25.6-9.6 25.6-25.6v-16c0-6.4-3.2-12.8-9.6-19.2-3.2-16-3.2-60.8 0-73.6 6.4-3.2 9.6-9.6 9.6-19.2zM144 144c0-8.84 7.16-16 16-16h48V80c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v48h48c8.84 0 16 7.16 16 16v32c0 8.84-7.16 16-16 16h-48v112c0 8.84-7.16 16-16 16h-32c-8.84 0-16-7.16-16-16V192h-48c-8.84 0-16-7.16-16-16v-32zm236.8 304H96c-19.2 0-32-12.8-32-32s16-32 32-32h284.8v64z"/></svg>

Before

Width:  |  Height:  |  Size: 718 B

After

Width:  |  Height:  |  Size: 718 B

View file

@ -2,7 +2,7 @@
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg <svg
fill="#000000" fill="#728F8D"
width="800px" width="800px"
height="800px" height="800px"
viewBox="-1 0 19 19" viewBox="-1 0 19 19"

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -3,6 +3,7 @@
gap: 10px; gap: 10px;
height: 24px; height: 24px;
cursor: pointer; cursor: pointer;
align-items: center;
} }
.link { .link {
@ -20,9 +21,10 @@
} }
.time { .time {
width: 40px; width: 70px;
} }
.table { .table {
width: 300px; width: 200px;
text-align: center;
} }

View file

@ -1,13 +0,0 @@
import type { Meta, StoryObj } from '@storybook/react'
import { MassTimerTooltip } from './MassTimerTooltip'
const meta: Meta<typeof MassTimerTooltip> = {
component: MassTimerTooltip,
}
type Story = StoryObj<typeof MassTimerTooltip>
export default meta
export const Default: Story = {
args: {},
}

View file

@ -1,20 +1,12 @@
import { MassTimer } from '@/components/MassTimer/MassTimer' import styles from './styles.module.scss'
import styles from './styles.module.css'
import MenuIcon from './menu.svg' import MenuIcon from './menu.svg'
import Image from 'next/image' import Image from 'next/image'
import { Worship } from '@/payload-types'
import { MenuBaseLayer } from '@/components/MenuBaseLayer/MenuBaseLayer'
import classNames from 'classnames' import classNames from 'classnames'
type MenuProps = {
starClick?: () => void
nextMass?: Worship
}
export const Menu = (props: MenuProps) => { export const Menu = () => {
return ( return (
<nav className={classNames(styles.nav, {[styles.white]: typeof props.starClick !== 'undefined'})}> <nav className={classNames(styles.nav)}>
<MenuBaseLayer />
<div className={styles.navMobile}> <div className={styles.navMobile}>
<Image src={MenuIcon} width={25} height={25} alt={'Menu'} /> <Image src={MenuIcon} width={25} height={25} alt={'Menu'} />
</div> </div>
@ -42,10 +34,6 @@ export const Menu = (props: MenuProps) => {
<div> <div>
<button className={styles.button}>Neu hier?</button> <button className={styles.button}>Neu hier?</button>
</div> </div>
{props.nextMass && (
<MassTimer nextMass={props.nextMass} onStarClick={props.starClick} />
)}
</div> </div>
</nav> </nav>
) )

View file

@ -1,15 +1,19 @@
@import "template.scss";
.nav { .nav {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 20px; gap: 20px;
color: #1f1f1f; color: $base-color;
padding: 15px; padding: 15px 45px;
border-bottom: 1px solid rgba(255, 255, 255, 0.67); background: rgba(245, 245, 245, 0.65);
margin-bottom: 2.5em; position: fixed;
} left: 0;
top: 0;
.white { width: 100%;
color: #eeeeee; box-sizing: border-box;
z-index: 1;
backdrop-filter: blur(8px);
} }
.navMobile { .navMobile {

View file

@ -0,0 +1,22 @@
import { Meta, StoryObj } from '@storybook/react'
import { Section } from './Section'
const meta: Meta<typeof Section> = {
component: Section,
}
type Story = StoryObj<typeof Section>
export default meta
export const Default: Story = {
args: {
children: 'Default',
},
}
export const SoftBackground: Story = {
args: {
children: "some content",
backgroundColor: "soft"
}
}

View file

@ -0,0 +1,20 @@
import classNames from 'classnames'
import styles from "./styles.module.scss"
export type BackgroundColor = "soft" | undefined
type SectionProps = {
backgroundColor?: BackgroundColor
children: React.ReactNode;
}
export const Section = ({ children, backgroundColor }: SectionProps) => {
return (
<section className={classNames({
[styles.section]: true,
[styles.shade2]: backgroundColor === "soft"
})}>
{children}
</section>
)
}

View file

@ -0,0 +1,15 @@
@import "template.scss";
.section {
padding: 130px 0;
}
.shade2 {
background-color: $shade2;
}
@media screen and (max-width: 576px) {
.section {
padding: 70px 0;
}
}

View file

@ -0,0 +1,13 @@
import { Meta, StoryObj } from '@storybook/react'
import { SideSlider } from './SideSlider'
const meta: Meta<typeof SideSlider> = {
component: SideSlider,
}
type Story = StoryObj<typeof SideSlider>;
export default meta
export const Default: Story = {
args: {},
}

View file

@ -0,0 +1,22 @@
import styles from "./styles.module.scss"
type SideSliderProps = {
children: React.ReactNode;
}
export const SideSlider = ({ children }: SideSliderProps) => {
return (
<div className={styles.wrapper}>
<div className={styles.container}>
<div className={styles.icon}>
</div>
<div className={styles.content}>
<div className={styles.padding}>
{children}
</div>
</div>
</div>
</div>
)
}

View file

@ -0,0 +1,65 @@
@import "template.scss";
$width: 700px;
$iconSize: 150px;
.wrapper {
overflow: hidden;
display: flex;
justify-content: flex-end;
}
.container {
width: $width;
min-height: 450px;
transform: translate(calc($width - $iconSize), 0);
transition: 300ms all ease-in;
position: relative;
}
.container:hover {
transform: translate(0, 0);
}
.icon {
position: absolute;
height: $iconSize;
width: $iconSize;
border-radius: 50%;
background-color: $shade1;
top: calc(50% - $iconSize/2);
}
.content {
position: absolute;
border-top-left-radius: $border-radius;
border-bottom-left-radius: $border-radius;
background-color: $shade1;
left: $iconSize/2;
padding-left: $iconSize/2;
min-height: 450px;
width: $width;
}
.padding {
padding: 30px 0;
}
@media screen and (max-width: $width) {
.icon {
display: none;
}
.container {
transform: none;
width: 100%;
}
.content {
border-radius: 0;
width: 100%;
position: relative;
left: 0;
}
}

View file

@ -0,0 +1,40 @@
import { Meta, StoryObj } from '@storybook/react'
import { Title } from './Title'
const meta: Meta<typeof Title> = {
component: Title,
}
type Story = StoryObj<typeof Title>
export default meta
export const Default: Story = {
args: {
title: 'Aktuelles',
},
}
export const BigTitle: Story = {
args: {
title: 'Veranstaltungen',
size: 'xl',
fontStyle: 'serif'
}
}
export const Centered: Story = {
args: {
title: 'Nächste Gottesdienste',
align: 'center'
},
}
export const sansSerifMedium: Story = {
args: {
title: 'Erntedankfest',
align: 'left',
fontStyle: 'sans-serif',
size: 'md'
}
}

View file

@ -0,0 +1,24 @@
import styles from "./styles.module.scss";
import classNames from 'classnames'
import { faustina } from '@/app/fonts'
type TitleProps = {
title: string;
align?: 'left' | 'center';
size?: 'xl' | 'lg' | 'md';
fontStyle?: 'serif' | 'sans-serif'
}
export const Title = ({title, align = "left", size = "lg", fontStyle = "serif"}: TitleProps) => {
return (
<h2 className={classNames({
[styles.title]: true,
[styles.extraLarge]: size === "xl",
[styles.large]: size === "lg",
[styles.medium]: size === "md",
[styles.left]: align === "left",
[styles.center]: align === "center",
[faustina.className]: fontStyle == "serif",
})}>{title}</h2>
)
}

View file

@ -0,0 +1,43 @@
@import "template.scss";
.title {
color: $base-color;
margin-top: 20px;
}
.extraLarge {
font-size: 90px;
font-weight: 800;
}
.large {
font-size: 60px;
font-weight: 800;
}
.medium {
font-size: 40px;
font-weight: 700;
}
.left {
text-align: left;
}
.center {
text-align: center;
}
@media screen and (max-width: 576px) {
.extraLarge {
font-size: 60px;
}
.large {
font-size: 40px;
}
.medium {
font-size: 24px;
}
}

View file

@ -0,0 +1,19 @@
import { Meta, StoryObj } from '@storybook/react'
import { TwoColumnText } from './TwoColumnText'
const meta: Meta<typeof TwoColumnText> = {
component: TwoColumnText,
}
type Story = StoryObj<typeof TwoColumnText>;
export default meta
export const Default: Story = {
args: {
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat porttitor volutpat. Mauris fermentum mi auctor porttitor sagittis. Proin quis congue elit. Nunc blandit auctor risus, in vestibulum nulla convallis id. Suspendisse potenti. Vestibulum tellus justo, imperdiet id ultrices quis, fringilla eget mauris. Sed sit amet nisl sed lectus tempus dapibus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris pulvinar ex ligula, sit amet tristique nunc varius sit amet.\n" +
"\n" +
"Curabitur sollicitudin, nulla nec sodales bibendum, nisi magna consequat arcu, non mollis est ligula pharetra mauris. Integer vehicula dolor urna, pharetra ultrices lectus maximus ac. Aliquam a lacus ut tortor fringilla dignissim. Curabitur sapien neque, ullamcorper ut lobortis sed, lobortis interdum lectus. Fusce pharetra maximus quam sed porta. Sed fermentum nibh vel elit lacinia malesuada. Suspendisse potenti. Suspendisse a dictum dui. Nulla rhoncus a nisi eu lacinia. Vestibulum at porta augue. Aliquam fermentum, nulla et aliquet maximus, dui nisi bibendum justo, eget placerat massa nulla et risus. Phasellus eleifend ante facilisis hendrerit lacinia. Aliquam eget dignissim nisi, in vehicula ligula.\n" +
"\n" +
"Curabitur at urna ornare, pretium nisl vel, ornare lacus. Morbi ante odio, bibendum at nunc vitae, scelerisque eleifend nisi. Quisque finibus imperdiet nulla sed suscipit. Phasellus ex libero, elementum vitae mollis et, faucibus vel magna. Proin vitae quam quis ipsum rhoncus vehicula. Ut porta ligula rutrum orci posuere, nec consequat est semper. Suspendisse potenti. Donec cursus erat sit amet auctor iaculis. Quisque sit amet rhoncus ex. Morbi placerat tincidunt condimentum. Aenean auctor, arcu elementum dictum sagittis, nibh tellus varius nulla, non mollis dui metus at leo. Ut porta, tellus at convallis commodo, orci odio faucibus purus, et mollis sapien lacus ut arcu. Fusce eget nisi finibus, interdum leo non, pulvinar mauris. Phasellus egestas finibus libero, non porttitor eros accumsan ut. Morbi elementum lorem ac lorem malesuada, quis dictum lorem efficitur."
},
}

View file

@ -0,0 +1,13 @@
import styles from "./styles.module.scss"
type TwoColumnTextProps = {
text: string;
}
export const TwoColumnText = ({text}: TwoColumnTextProps) => {
return (
<div className={styles.columns}>
{text}
</div>
)
}

View file

@ -0,0 +1,20 @@
@import "template.scss";
.columns {
column-count: 2;
white-space: preserve;
column-gap: 80px;
column-rule: $shade2 1px solid;
}
@media screen and (max-width: 900px) {
.columns {
column-gap: 40px;
}
}
@media screen and (max-width: 576px) {
.columns {
column-count: 1;
}
}

View file

@ -1,5 +1,5 @@
import styles from './bannerText.module.css' import styles from './bannerText.module.css'
import { faustina, lato } from '@/app/fonts' import { faustina, defaultFont } from '@/app/fonts'
export const BannerText = () => { export const BannerText = () => {
return ( return (
@ -10,7 +10,7 @@ export const BannerText = () => {
HEILIGE <br /> HEILIGE <br />
DREI KÖNIGE <br /> DREI KÖNIGE <br />
</div> </div>
<div className={styles.berlin + ' ' + lato.className}> <div className={styles.berlin + ' ' + defaultFont.className}>
Berlin Nord-Neukölln Berlin Nord-Neukölln
</div> </div>
</div> </div>

View file

@ -11,6 +11,7 @@
.container { .container {
position: absolute; position: absolute;
bottom: 100px; bottom: 100px;
color: #ffffff;
} }
.name { .name {

View file

@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react' import type { Meta, StoryObj } from '@storybook/react'
import { HomeBanner } from '@/components/HomeBanner/HomeBanner' import { HomeBanner } from '@/components/archive/HomeBanner/HomeBanner'
const meta: Meta<typeof HomeBanner> = { const meta: Meta<typeof HomeBanner> = {
component: HomeBanner, component: HomeBanner,

View file

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -13,7 +13,13 @@ export const OneDay: Story = {
args: { args: {
nextMass: { nextMass: {
id: '1', id: '1',
location: '231234', location: {
id: "d",
name: "St. Richard",
address: "Wegstraße 12",
updatedAt: "2025-08-23T15:00:00.000Z",
createdAt: '2025-08-23T15:00:00.000Z',
},
date: '2025-08-23T15:00:00.000Z', date: '2025-08-23T15:00:00.000Z',
type: 'WORD', type: 'WORD',
cancelled: false, cancelled: false,
@ -28,7 +34,13 @@ export const TimeOut: Story = {
args: { args: {
nextMass: { nextMass: {
id: '1', id: '1',
location: '231234', location: {
id: "d",
name: "St. Richard",
address: "Wegstraße 12",
updatedAt: "2025-08-23T15:00:00.000Z",
createdAt: '2025-08-23T15:00:00.000Z',
},
date: '2025-08-23T15:00:00.000Z', date: '2025-08-23T15:00:00.000Z',
type: 'WORD', type: 'WORD',
cancelled: false, cancelled: false,

View file

@ -1,9 +1,9 @@
'use client' 'use client'
import { useCountdown } from '@/components/MassTimer/useCountdown' import { useCountdown } from '@/components/archive/MassTimer/useCountdown'
import styles from './masstimer.module.css' import styles from './masstimer.module.css'
import { useState } from 'react' import { useState } from 'react'
import { MassTimerTooltip } from '@/components/MassTimerTooltip/MassTimerTooltip' import { MassTimerTooltip } from '@/components/archive/MassTimerTooltip/MassTimerTooltip'
import { Worship } from '@/payload-types' import { Worship } from '@/payload-types'
type MassTimerProps = { type MassTimerProps = {

View file

@ -0,0 +1,29 @@
import type { Meta, StoryObj } from '@storybook/react'
import { MassTimerTooltip } from './MassTimerTooltip'
const meta: Meta<typeof MassTimerTooltip> = {
component: MassTimerTooltip,
}
type Story = StoryObj<typeof MassTimerTooltip>
export default meta
export const Default: Story = {
args: {
nextMass: {
id: "12",
date: '2024-08-23T15:00:00.000Z',
location: {
id: "d",
name: "St. Richard",
address: "Wegstraße 12",
updatedAt: "2025-08-23T15:00:00.000Z",
createdAt: '2025-08-23T15:00:00.000Z',
},
type: "MASS",
cancelled: false,
updatedAt: '2025-08-23T15:00:00.000Z',
createdAt: '2025-08-23T15:00:00.000Z'
}
},
}

Some files were not shown because too many files have changed in this diff Show more