fix: home page
This commit is contained in:
parent
b868c0a7a4
commit
8cc72d2722
14 changed files with 291 additions and 71 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
68
src/collections/Highlight.ts
Normal file
68
src/collections/Highlight.ts
Normal 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(),
|
||||
}
|
||||
}
|
||||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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}>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
}
|
||||
|
||||
.white {
|
||||
color: #ffffff;
|
||||
color: $shade3;
|
||||
}
|
||||
|
||||
.extraLarge {
|
||||
|
|
|
|||
34
src/fetch/highlights.ts
Normal file
34
src/fetch/highlights.ts
Normal 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()
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
23
src/utils/dto/highlight.ts
Normal file
23
src/utils/dto/highlight.ts
Normal 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
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue