feature: styling

This commit is contained in:
Benno Tielen 2024-08-22 15:01:23 +02:00
parent b3262d8700
commit 210b8641bc
24 changed files with 237 additions and 145 deletions

View file

@ -20,8 +20,6 @@
"@payloadcms/next": "beta", "@payloadcms/next": "beta",
"@payloadcms/plugin-cloud": "beta", "@payloadcms/plugin-cloud": "beta",
"@payloadcms/richtext-lexical": "beta", "@payloadcms/richtext-lexical": "beta",
"@romcal/calendar.france": "^3.0.0-dev.79",
"@romcal/calendar.germany": "file:./../romcal/dist/bundles/germany",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"graphql": "^16.8.1", "graphql": "^16.8.1",
@ -30,7 +28,6 @@
"payload": "beta", "payload": "beta",
"react": "^19.0.0-rc-6230622a1a-20240610", "react": "^19.0.0-rc-6230622a1a-20240610",
"react-dom": "^19.0.0-rc-6230622a1a-20240610", "react-dom": "^19.0.0-rc-6230622a1a-20240610",
"romcal": "^3.0.0-dev.79",
"sharp": "0.32.6" "sharp": "0.32.6"
}, },
"devDependencies": { "devDependencies": {

4
src/app/globals.css Normal file
View file

@ -0,0 +1,4 @@
html,
body {
margin: 0;
}

BIN
src/app/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -1,9 +1,9 @@
import type { Metadata } from 'next' import type { Metadata } from 'next'
import { lato } from './fonts' import { lato } from './fonts'
import './globals.css'
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Katholische Pfarrei Heilige drei Könige Berlin', title: 'Katholische Pfarrei Heilige drei Könige Berlin',
description: 'Generated by create next app',
} }
export default function RootLayout({ export default function RootLayout({

View file

@ -33,7 +33,6 @@ export default async function Page({ params }: { params: { id: string } }) {
return ( return (
<> <>
<Menu /> <Menu />
<Container> <Container>
<MassTitle title={title} cancelled={worship.cancelled} /> <MassTitle title={title} cancelled={worship.cancelled} />

View file

@ -2,11 +2,13 @@
display: flex; display: flex;
gap: 30px; gap: 30px;
margin-bottom: 80px; margin-bottom: 80px;
flex-wrap: wrap;
justify-content: center;
} }
.cardContent { .cardContent {
padding-top: 30px; padding-top: 30px;
padding-left: 50px; text-align: center;
} }
.cardText { .cardText {

View file

@ -1,6 +1,6 @@
.card { .card {
height: 260px; height: 260px;
width: 235px; width: 240px;
box-shadow: 0 0 11px 0 rgba(79, 66, 79, 0.26); box-shadow: 0 0 11px 0 rgba(79, 66, 79, 0.26);
background-color: #ffffff; background-color: #ffffff;
} }

View file

@ -16,7 +16,6 @@ export const Default: Story = {
export const Yellow: Story = { export const Yellow: Story = {
args: { args: {
background: 'yellow',
children: <>Some content</>, children: <>Some content</>,
}, },
} }

View file

@ -1,15 +1,9 @@
import styles from './styles.module.css' import styles from './styles.module.css'
import classNames from 'classnames'
type ContainerProps = { type ContainerProps = {
background?: 'yellow'
children: JSX.Element | JSX.Element[] children: JSX.Element | JSX.Element[]
} }
export const Container = ({ children, background }: ContainerProps) => { export const Container = ({ children }: ContainerProps) => {
return ( return <div className={styles.container}>{children}</div>
<div className={classNames({ [styles.yellow]: background === 'yellow' })}>
<div className={styles.container}>{children}</div>
</div>
)
} }

View file

@ -1,15 +1,10 @@
.container { .container {
width: 800px; max-width: 800px;
margin: 0 auto; margin: 0 auto;
} }
.yellow { @media screen and (max-width: 800px) {
background: rgb(255, 255, 97); .container {
background: linear-gradient( padding: 0 20px;
180deg, }
rgba(255, 255, 97, 0) 0%,
rgb(255 250 163) 20%
);
position: relative;
top: -70px;
} }

View file

@ -19,6 +19,7 @@ export type HomeBannerHandle = {
export const HomeBanner = forwardRef<HomeBannerHandle, HomeBannerProps>( export const HomeBanner = forwardRef<HomeBannerHandle, HomeBannerProps>(
function HomeBanner({ children, stars }: HomeBannerProps, ref) { function HomeBanner({ children, stars }: HomeBannerProps, ref) {
const canvasRef = useRef<HTMLCanvasElement>(null) const canvasRef = useRef<HTMLCanvasElement>(null)
const containerRef = useRef<HTMLDivElement>(null)
const drawStarAtPosition = useCallback( const drawStarAtPosition = useCallback(
(ctx: CanvasRenderingContext2D, x: number, y: number) => { (ctx: CanvasRenderingContext2D, x: number, y: number) => {
@ -57,7 +58,8 @@ export const HomeBanner = forwardRef<HomeBannerHandle, HomeBannerProps>(
useEffect(() => { useEffect(() => {
if (canvasRef.current) { if (canvasRef.current) {
canvasRef.current.width = window.innerWidth canvasRef.current.width =
containerRef.current?.clientWidth || window.innerWidth
canvasRef.current.height = 0.8 * window.innerHeight canvasRef.current.height = 0.8 * window.innerHeight
} }
const context = canvasRef.current?.getContext('2d') const context = canvasRef.current?.getContext('2d')
@ -73,7 +75,7 @@ export const HomeBanner = forwardRef<HomeBannerHandle, HomeBannerProps>(
}, [drawStar, stars]) }, [drawStar, stars])
return ( return (
<div className="splash-bg"> <div className="splash-bg" ref={containerRef}>
<canvas ref={canvasRef} className="stars"></canvas> <canvas ref={canvasRef} className="stars"></canvas>
<div className="splash">{children}</div> <div className="splash">{children}</div>
</div> </div>

View file

@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from 'react'
import mapboxgl from 'mapbox-gl' import mapboxgl from 'mapbox-gl'
import styles from './styles.module.css' import styles from './styles.module.css'
import 'mapbox-gl/dist/mapbox-gl.css' import 'mapbox-gl/dist/mapbox-gl.css'
import { Container } from '@/components/Container/Container'
// todo: as env variable // todo: as env variable
mapboxgl.accessToken = mapboxgl.accessToken =
@ -31,5 +32,9 @@ export const LocationMap = () => {
} }
}) })
return <div ref={mapContainer} className={styles.map}></div> return (
<Container>
<div ref={mapContainer} className={styles.map}></div>
</Container>
)
} }

View file

@ -15,26 +15,38 @@ export const Default: Story = {
{ {
id: '1', id: '1',
date: '10:00', date: '10:00',
locationName: 'St. Christopherus', location: 'St. Christopherus',
type: null, type: 'MASS',
cancelled: false,
updatedAt: '',
createdAt: '',
}, },
{ {
id: '1', id: '1',
date: '11:00', date: '10:00',
locationName: 'St. Richard', location: 'St. Christopherus',
type: 'FAMILY', type: 'MASS',
cancelled: false,
updatedAt: '',
createdAt: '',
}, },
{ {
id: '1', id: '1',
date: '11:00', date: '10:00',
locationName: 'St. Clara', location: 'St. Christopherus',
type: 'WORD', type: 'MASS',
cancelled: false,
updatedAt: '',
createdAt: '',
}, },
{ {
id: '1', id: '1',
date: '19:00', date: '10:00',
locationName: 'St. Clara', location: 'St. Christopherus',
type: null, type: 'MASS',
cancelled: false,
updatedAt: '',
createdAt: '',
}, },
], ],
}, },

View file

@ -11,14 +11,30 @@ export default meta
export const OneDay: Story = { export const OneDay: Story = {
args: { args: {
timeout: new Date().getTime() + 1000 * 60 * 60 * 24, nextMass: {
id: '1',
location: '231234',
date: '2025-08-23T15:00:00.000Z',
type: 'WORD',
cancelled: false,
createdAt: '2025-08-23T15:00:00.000Z',
updatedAt: '2025-08-23T15:00:00.000Z',
},
onStarClick: fn(), onStarClick: fn(),
}, },
} }
export const TimeOut: Story = { export const TimeOut: Story = {
args: { args: {
timeout: new Date().getTime(), nextMass: {
id: '1',
location: '231234',
date: '2025-08-23T15:00:00.000Z',
type: 'WORD',
cancelled: false,
createdAt: '2025-08-23T15:00:00.000Z',
updatedAt: '2025-08-23T15:00:00.000Z',
},
onStarClick: fn(), onStarClick: fn(),
}, },
} }

View file

@ -32,7 +32,10 @@ export const MassTimer = ({ nextMass, onStarClick }: MassTimerProps) => {
🌟 🌟
</button> </button>
<span onMouseEnter={() => setDisplayTooltip(true)}> <span
onMouseEnter={() => setDisplayTooltip(true)}
suppressHydrationWarning={true}
>
{days}T {hours}S {minutes}M {seconds}S {days}T {hours}S {minutes}M {seconds}S
</span> </span>
</div> </div>

View file

@ -1,5 +1,6 @@
.container { .container {
position: relative; position: relative;
width: 145px;
} }
.starButton { .starButton {

View file

@ -1,7 +1,7 @@
.title { .title {
font-size: 48px; font-size: 48px;
font-weight: 700; font-weight: 700;
margin-block-start: 0; margin-block-start: -10px;
} }
.mass { .mass {

View file

@ -18,7 +18,7 @@ export const Menu = (props: MenuProps) => {
<Image src={MenuIcon} width={25} height={25} alt={'Menu'} /> <Image src={MenuIcon} width={25} height={25} alt={'Menu'} />
</div> </div>
<div className={styles.itemsLeft}> <div className={styles.itemsLeft}>
<a className={styles.menuLink} href={''}> <a className={styles.menuLink} href={'/'}>
Home Home
</a> </a>
<a className={styles.menuLink} href={''}> <a className={styles.menuLink} href={''}>
@ -35,7 +35,7 @@ export const Menu = (props: MenuProps) => {
<div className={styles.itemsRight}> <div className={styles.itemsRight}>
<div> <div>
<a className={styles.menuLink} href={''}> <a className={styles.menuLink} href={''}>
Spenden Mithelfen
</a> </a>
</div> </div>
<div> <div>

View file

@ -2,10 +2,10 @@
display: flex; display: flex;
align-items: baseline; align-items: baseline;
gap: 20px; gap: 20px;
color: #3d3d3d; color: #1f1f1f;
padding-top: 15px; padding: 15px;
height: 50px; border-bottom: 1px solid rgba(255, 255, 255, 0.67);
border-bottom: 1px solid rgba(217, 217, 217, 0.19); margin-bottom: 2.5em;
} }
.navMobile { .navMobile {

View file

@ -15,3 +15,12 @@ export const Default: Story = {
'Die Eucharistie ist für mich wie ein spiritueller Boost. Wenn ich die Hostie empfange, fühle ich mich krass verbunden mit Jesus. Es ist wie ein Reminder, dass ich nicht allein bin, egal was abgeht. Dieser Moment gibt mir richtig Power und lässt mich mit einem starken Gefühl von Frieden und Hoffnung rausgehen.', 'Die Eucharistie ist für mich wie ein spiritueller Boost. Wenn ich die Hostie empfange, fühle ich mich krass verbunden mit Jesus. Es ist wie ein Reminder, dass ich nicht allein bin, egal was abgeht. Dieser Moment gibt mir richtig Power und lässt mich mit einem starken Gefühl von Frieden und Hoffnung rausgehen.',
}, },
} }
export const WithOccupation: Story = {
args: {
name: 'Johan Schäfer',
testimony:
'Die Eucharistie ist für mich wie ein spiritueller Boost. Wenn ich die Hostie empfange, fühle ich mich krass verbunden mit Jesus. Es ist wie ein Reminder, dass ich nicht allein bin, egal was abgeht. Dieser Moment gibt mir richtig Power und lässt mich mit einem starken Gefühl von Frieden und Hoffnung rausgehen.',
occupation: 'Schüler',
},
}

View file

@ -2,22 +2,32 @@ import styles from './styles.module.css'
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
} }
export const Testimony = ({ name, testimony }: TestimonyProps) => { export const Testimony = ({ name, testimony, occupation }: TestimonyProps) => {
return ( return (
<Container background={'yellow'}> <Container>
<div className={styles.testimony}> <div className={styles.testimony}>
<div className={styles.person}></div> <div className={styles.container}>
<div> <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>{name}</p> <p className={styles.name}>
{name} {occupation && <>- {occupation}</>}
</p>
</div> </div>
</div> </div>
</Container> </Container>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 46.195 46.195" xml:space="preserve">
<g>
<path style="fill:#FFFF61;" d="M35.765,8.264c-5.898,0-10.555,4.782-10.555,10.68s4.844,10.68,10.742,10.68
c0.059,0,0.148-0.008,0.207-0.009c-2.332,1.857-5.261,2.976-8.467,2.976c-1.475,0-2.662,1.196-2.662,2.67s0.949,2.67,2.424,2.67
c10.469-0.001,18.741-8.518,18.741-18.987c0-0.002,0-0.004,0-0.007C46.195,13.042,41.661,8.264,35.765,8.264z"/>
<path style="fill:#FFFF61;" d="M10.75,8.264c-5.898,0-10.563,4.782-10.563,10.68s4.84,10.68,10.739,10.68
c0.059,0,0.146-0.008,0.205-0.009c-2.332,1.857-5.262,2.976-8.468,2.976C1.188,32.591,0,33.787,0,35.261s0.964,2.67,2.439,2.67
c10.469-0.001,18.756-8.518,18.756-18.987c0-0.002,0-0.004,0-0.007C21.195,13.042,16.646,8.264,10.75,8.264z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1,013 B

View file

@ -7,11 +7,41 @@
.testimonyText { .testimonyText {
font-style: italic; font-style: italic;
line-height: 1.7em;
font-size: 1.1em;
}
.container {
position: relative;
} }
.person { .person {
height: 150px; height: 150px;
width: 150px; width: 150px;
background-color: white; background-color: #f6dc66;
flex-shrink: 0; 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%);
}
}

View file

@ -8,161 +8,162 @@
export interface Config { export interface Config {
auth: { auth: {
users: UserAuthOperations users: UserAuthOperations;
} };
collections: { collections: {
users: User users: User;
media: Media media: Media;
worship: Worship worship: Worship;
church: Church church: Church;
testimony: Testimony testimony: Testimony;
'payload-preferences': PayloadPreference 'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration 'payload-migrations': PayloadMigration;
} };
db: { db: {
defaultIDType: string defaultIDType: string;
} };
globals: {} globals: {};
locale: null locale: null;
user: User & { user: User & {
collection: 'users' collection: 'users';
} };
} }
export interface UserAuthOperations { export interface UserAuthOperations {
forgotPassword: { forgotPassword: {
email: string email: string;
password: string password: string;
} };
login: { login: {
email: string email: string;
password: string password: string;
} };
registerFirstUser: { registerFirstUser: {
email: string email: string;
password: string password: string;
} };
unlock: { unlock: {
email: string email: string;
password: string password: string;
} };
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users". * via the `definition` "users".
*/ */
export interface User { export interface User {
id: string id: string;
updatedAt: string updatedAt: string;
createdAt: string createdAt: string;
email: string email: string;
resetPasswordToken?: string | null resetPasswordToken?: string | null;
resetPasswordExpiration?: string | null resetPasswordExpiration?: string | null;
salt?: string | null salt?: string | null;
hash?: string | null hash?: string | null;
loginAttempts?: number | null loginAttempts?: number | null;
lockUntil?: string | null lockUntil?: string | null;
password?: string | null password?: string | null;
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media". * via the `definition` "media".
*/ */
export interface Media { export interface Media {
id: string id: string;
alt: string alt: string;
updatedAt: string updatedAt: string;
createdAt: string createdAt: string;
url?: string | null url?: string | null;
thumbnailURL?: string | null thumbnailURL?: string | null;
filename?: string | null filename?: string | null;
mimeType?: string | null mimeType?: string | null;
filesize?: number | null filesize?: number | null;
width?: number | null width?: number | null;
height?: number | null height?: number | null;
focalX?: number | null focalX?: number | null;
focalY?: number | null focalY?: number | null;
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "worship". * via the `definition` "worship".
*/ */
export interface Worship { export interface Worship {
id: string id: string;
date: string date: string;
location: string | Church location: string | Church;
type: 'MASS' | 'FAMILY' | 'WORD' type: 'MASS' | 'FAMILY' | 'WORD';
cancelled: boolean cancelled: boolean;
title?: string | null title?: string | null;
description?: string | null description?: string | null;
updatedAt: string updatedAt: string;
createdAt: string createdAt: string;
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "church". * via the `definition` "church".
*/ */
export interface Church { export interface Church {
id: string id: string;
name: string name: string;
address: string address: string;
updatedAt: string updatedAt: string;
createdAt: string createdAt: string;
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "testimony". * via the `definition` "testimony".
*/ */
export interface Testimony { export interface Testimony {
id: string id: string;
testimony: string testimony: string;
name: string name: string;
occupation?: string | null occupation?: string | null;
category: 'EUCHARIST' category: 'EUCHARIST';
updatedAt: string updatedAt: string;
createdAt: string createdAt: string;
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences". * via the `definition` "payload-preferences".
*/ */
export interface PayloadPreference { export interface PayloadPreference {
id: string id: string;
user: { user: {
relationTo: 'users' relationTo: 'users';
value: string | User value: string | User;
} };
key?: string | null key?: string | null;
value?: value?:
| { | {
[k: string]: unknown [k: string]: unknown;
} }
| unknown[] | unknown[]
| string | string
| number | number
| boolean | boolean
| null | null;
updatedAt: string updatedAt: string;
createdAt: string createdAt: string;
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations". * via the `definition` "payload-migrations".
*/ */
export interface PayloadMigration { export interface PayloadMigration {
id: string id: string;
name?: string | null name?: string | null;
batch?: number | null batch?: number | null;
updatedAt: string updatedAt: string;
createdAt: string createdAt: string;
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth". * via the `definition` "auth".
*/ */
export interface Auth { export interface Auth {
[k: string]: unknown [k: string]: unknown;
} }
declare module 'payload' { declare module 'payload' {
export interface GeneratedTypes extends Config {} export interface GeneratedTypes extends Config {}
} }