fix: home page

This commit is contained in:
Benno Tielen 2024-11-26 13:00:30 +01:00
parent b868c0a7a4
commit 8cc72d2722
14 changed files with 291 additions and 71 deletions

View file

@ -18,7 +18,15 @@ const preview: Preview = {
date: /Date$/i,
},
},
},
backgrounds: {
values: [
{ name: "light", value: "#ffffff" },
{ name: "shade2", value: "#CBD6D5" },
{ name: 'dark', value: "#728F8D" }
],
default: "light"
}
}
}
export default preview

View file

@ -17,6 +17,9 @@ import { transformEvents } from '@/utils/dto/events'
import { fetchBlog } from '@/fetch/blog'
import { ImageCardSlider } from '@/compositions/ImageCardSlider/ImageCardSlider'
import { blogToSlides } from '@/utils/dto/blog'
import { fetchHighlights } from '@/fetch/highlights'
import { EventRow } from '@/components/EventRow/EventRow'
import { highlightLink } from '@/utils/dto/highlight'
const sortWorship = (worship: Worship[]) => {
const map = new Map<string, Worship[]>();
@ -62,6 +65,7 @@ export default async function Home() {
)
const blog = await fetchBlog();
const highlights = await fetchHighlights()
return (
@ -93,7 +97,17 @@ export default async function Home() {
'Unsere Pfarrei Hl. Drei Könige wurde am 01.01.2020 gegründet. Am 12.01.2020 feierte Erzbischof Dr. Heiner Koch mit den Gemeinden die Gründung in einer feierlichen Hl. Messe in der katholischen Marienschule. Anwesende Gäste waren Bürgermeister Martin Hikel, Christian Nottmeier, der Superintendent des evangelischen Kirchenkreises Neukölln und vielen Akteuren aus Kiez und Ökumene. Die Vielfalt der Glaubenswege in unserer Pfarrei sehen wir als Schatz. Wie die drei Weisen aus dem Morgenland wollen wir uns immer wieder neu auf den Weg machen.'} image={forest} />}
<ContentWithSlider slider={<>
<Title title={"Akutelle Highlights"} size={"md"} fontStyle={"sans-serif"} />
<Title title={"Akutelle Highlights"} size={"md"} fontStyle={"sans-serif"} color={"white"} />
{highlights?.docs.map(highlight => (
<EventRow
color={"white"}
key={highlight.id}
date={highlight.date}
title={highlight.text}
href={highlightLink(highlight)}
cancelled={false}
/>
))}
</>}>
<Container position={"right"}>
<Section>

View file

@ -0,0 +1,68 @@
import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Highlight: CollectionConfig = {
slug: 'highlight',
labels: {
singular: {
de: "Highlight"
},
plural: {
de: "Highlights"
}
},
fields: [
{
name: 'from',
type: 'date',
required: true,
label: {
de: "Anzeigen von"
}
},
{
name: 'until',
type: 'date',
required: true,
label: {
de: "Anzeigen bis"
}
},
{
name: 'date',
type: 'date',
required: true,
label: {
de: 'Datum'
}
},
{
name: 'link',
type: 'relationship',
relationTo: ['event', 'blog', 'worship'],
admin: {
allowCreate: false,
allowEdit: false
},
required: false
},
{
name: 'text',
type: 'textarea',
required: true,
maxLength: 144,
label: {
de: "Nachricht"
}
}
],
admin: {
useAsTitle: 'text'
},
access: {
read: () => true,
create: isAdminOrEmployee(),
update: isAdminOrEmployee(),
delete: isAdminOrEmployee(),
}
}

View file

@ -1,39 +0,0 @@
import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Tweets: CollectionConfig = {
slug: 'tweet',
labels: {
singular: {
de: "Kurznachricht"
},
plural: {
de: "Kurznachrichten"
}
},
fields: [
{
name: 'parish',
type: 'relationship',
relationTo: 'parish',
hasMany: true,
label: {
de: "Gemeinde"
}
},
{
name: 'text',
type: 'textarea',
required: true,
label: {
de: "Nachricht"
}
}
],
access: {
read: () => true,
create: isAdminOrEmployee(),
update: isAdminOrEmployee(),
delete: isAdminOrEmployee(),
}
}

View file

@ -36,4 +36,20 @@ export const CancelledEvent: Story = {
location: "St. Richard",
cancelled: true
},
}
export const DarkBackground: Story = {
args: {
date: '2024-01-06T15:00:00+01:00',
title: 'Herz Jesu Feier',
href: 'https://www.herzJesuFeier.com',
location: "St. Clara",
cancelled: false,
color: "white"
},
parameters: {
backgrounds: {
default: 'dark'
}
}
}

View file

@ -7,9 +7,10 @@ export type EventRowProps = {
/** datetime 8601 format */
date: string,
title: string,
href: string,
href?: string,
location?: string,
cancelled: boolean
color?: "base" | "white"
}
/**
@ -38,20 +39,27 @@ const shortMonth = (date: string) => {
export const EventRow = ({date, title, location, cancelled, href}: EventRowProps) => {
export const EventRow = ({date, title, location, cancelled, href, color = "base"}: EventRowProps) => {
const day = useMemo(() => date.substring(8, 10), [date]);
const dateObj = useMemo(() => new Date(date), [date]);
const month = useMemo(() => shortMonth(date), [date]);
return (
<Link href={href} className={styles.link}>
<Link href={href || "https://"} className={styles.link}>
<div className={styles.container}>
<div className={styles.day}>
<div className={classNames({
[styles.day]: true,
[styles.dayBase]: color === "base",
[styles.dayWhite]: color === "white"
})}>
{day} <br />
{month}
</div>
<div className={styles.line}></div>
<div className={classNames({
[styles.line]: true,
[styles.lineWhite]: color === "white",
})}></div>
<div className={classNames({
[styles.details]: true,

View file

@ -1,7 +1,6 @@
@import "template.scss";
.day {
color: $base-color;
line-height: 105%;
font-size: 25px;
font-weight: bold;
@ -10,13 +9,26 @@
transition: color 0.2s ease-in;
}
.dayBase {
color: $base-color;
}
.dayWhite{
color: $shade3;
}
.line {
width: 0.7px;
background: $base-color;
background: $shade1;
height: 96px;
margin: 0 30px;
}
.lineWhite {
background: $shade3;
opacity: 0.5;
}
.details {
line-height: 147%;
}
@ -38,10 +50,14 @@
text-decoration: line-through;
}
.container:hover .day {
.container:hover .dayBase {
color: $contrast-color;
}
.container:hover .dayWhite {
color: $shade2;
}
@media screen and (max-width: 576px) {
.day {
margin-left: 15px;

View file

@ -1,15 +1,68 @@
"use client"
import styles from "./styles.module.scss"
import { useCallback, useEffect, useMemo, useState } from 'react'
import classNames from 'classnames'
type SideSliderProps = {
children: React.ReactNode;
}
export const SideSlider = ({ children }: SideSliderProps) => {
const [isVisible, setIsVisible] = useState(false)
const [startX, setStartX] = useState<number|undefined>(undefined)
const [endX, setEndX] = useState<number|undefined>(undefined)
const [isMobile, setIsMobile] = useState(false)
useEffect(() => {
if(window.innerWidth < 700) {
setIsMobile(true)
}
window.addEventListener("resize", () => {
if(window.innerWidth < 700) {
setIsMobile(true)
} else {
setIsMobile(false)
}
})
}, [setIsMobile])
// translateX the container when startX or endX changed
const style = useMemo(() => {
if (typeof endX === "number" && typeof startX === "number")
return {
transform: `translateX(${endX-startX}px)`
}
return undefined
}, [endX, startX])
const className = classNames({
[styles.container]: true,
[styles.isVisible]: isVisible,
});
return (
<div className={styles.wrapper}>
<div className={styles.container}>
<div className={styles.icon}>
<div
className={className}
onMouseEnter={!isMobile ? () => setIsVisible(true): undefined}
onMouseLeave={!isMobile ? () => setIsVisible(false): undefined}
style={style}
>
<div
className={styles.icon}
onTouchStart={e => {
if(typeof startX === "undefined" && typeof endX === "undefined") {
setStartX(e.touches[0].clientX)
setEndX(e.touches[0].clientX)
}
}}
onTouchMove={e => {
setEndX(e.changedTouches[0].clientX)
}}
>
</div>
<div className={styles.content}>
<div className={styles.padding}>

View file

@ -12,13 +12,13 @@ $iconSize: 150px;
.container {
width: $width;
min-height: 450px;
transform: translate(calc($width - $iconSize), 0);
transition: 300ms all ease-in;
transition: 200ms transform ease-out;
position: relative;
right: -550px;
}
.container:hover {
transform: translate(0, 0);
.isVisible {
transform: translateX(-550px);
}
.icon {
@ -39,6 +39,7 @@ $iconSize: 150px;
padding-left: $iconSize/2;
min-height: 450px;
width: $width;
color: #ffffff;
}
.padding {
@ -51,7 +52,7 @@ $iconSize: 150px;
}
.container {
transform: none;
right: 0;
width: 100%;
}
@ -60,6 +61,6 @@ $iconSize: 150px;
width: 100%;
position: relative;
left: 0;
padding: 0 20px;
}
}

View file

@ -20,7 +20,7 @@
}
.white {
color: #ffffff;
color: $shade3;
}
.extraLarge {

34
src/fetch/highlights.ts Normal file
View file

@ -0,0 +1,34 @@
import { stringify } from 'qs-esm'
import { PaginatedDocs } from 'payload'
import { Highlight } from '@/payload-types'
export const fetchHighlights = async (): Promise<PaginatedDocs<Highlight> | undefined> => {
const date = new Date();
date.setHours(0, 0, 0, 0);
const query: any = {
and: [
{
from: {
less_than_equal: date.toISOString(),
},
until: {
greater_than_equal: date.toISOString(),
}
}
],
}
const stringifiedQuery = stringify(
{
sort: "date",
where: query,
limit: 3
},
{ addQueryPrefix: true },
)
const response = await fetch(`http://localhost:3000/api/highlight${stringifiedQuery}`)
if (!response.ok) return undefined
return response.json()
}

View file

@ -16,7 +16,7 @@ export interface Config {
worship: Worship;
vermeldungen: Vermeldungen;
blog: Blog;
tweet: Tweet;
highlight: Highlight;
event: Event;
group: Group;
employees: Employee;
@ -36,7 +36,7 @@ export interface Config {
worship: WorshipSelect<false> | WorshipSelect<true>;
vermeldungen: VermeldungenSelect<false> | VermeldungenSelect<true>;
blog: BlogSelect<false> | BlogSelect<true>;
tweet: TweetSelect<false> | TweetSelect<true>;
highlight: HighlightSelect<false> | HighlightSelect<true>;
event: EventSelect<false> | EventSelect<true>;
group: GroupSelect<false> | GroupSelect<true>;
employees: EmployeesSelect<false> | EmployeesSelect<true>;
@ -293,11 +293,26 @@ export interface Document {
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "tweet".
* via the `definition` "highlight".
*/
export interface Tweet {
export interface Highlight {
id: string;
parish?: (string | Parish)[] | null;
from: string;
until: string;
date: string;
link?:
| ({
relationTo: 'event';
value: string | Event;
} | null)
| ({
relationTo: 'blog';
value: string | Blog;
} | null)
| ({
relationTo: 'worship';
value: string | Worship;
} | null);
text: string;
updatedAt: string;
createdAt: string;
@ -452,8 +467,8 @@ export interface PayloadLockedDocument {
value: string | Blog;
} | null)
| ({
relationTo: 'tweet';
value: string | Tweet;
relationTo: 'highlight';
value: string | Highlight;
} | null)
| ({
relationTo: 'event';
@ -644,10 +659,13 @@ export interface BlogSelect<T extends boolean = true> {
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "tweet_select".
* via the `definition` "highlight_select".
*/
export interface TweetSelect<T extends boolean = true> {
parish?: T;
export interface HighlightSelect<T extends boolean = true> {
from?: T;
until?: T;
date?: T;
link?: T;
text?: T;
updatedAt?: T;
createdAt?: T;

View file

@ -30,7 +30,7 @@ import { Groups } from '@/collections/Groups'
import { Events } from '@/collections/Events'
import { Announcements } from '@/collections/Announcements'
import { Blog } from '@/collections/Blog'
import { Tweets } from '@/collections/Tweets'
import { Highlight } from '@/collections/Highlight'
import { Pages } from '@/collections/Pages'
import { Documents } from '@/collections/Documents'
import { Underdog } from 'next/dist/compiled/@next/font/dist/google'
@ -48,7 +48,7 @@ export default buildConfig({
Worship,
Announcements,
Blog,
Tweets,
Highlight,
Events,
Groups,
Employees,

View file

@ -0,0 +1,23 @@
import { Highlight } from '@/payload-types'
export const highlightLink = (highlight: Highlight) => {
if(!highlight.link) {
return undefined
}
if (typeof highlight.link.value !== 'object') {
return undefined
}
switch (highlight.link.relationTo) {
case 'worship':
return `/gottesdienst/${highlight.link.value.id}`;
case 'event':
return `/event/${highlight.link.value.id}`;
case 'blog':
return `/blog/${highlight.link.value.id}`;
default:
return undefined
}
}