feat: implement about and contact page

fetch localized content from Payload
main
RaviAnand Mohabir 3 weeks ago
parent f39059202f
commit ac318177d4

@ -1,6 +1,7 @@
import type { Options } from "node_modules/payload/dist/globals/operations/local/findOne";
import { getPayload } from "@/utils/payload";
export const getAbout = async () => {
export const getAbout = async (opts: Omit<Options<"about">, "slug"> = {}) => {
const payload = await getPayload();
return await payload.findGlobal({ slug: "about" });
return await payload.findGlobal({ slug: "about", ...opts });
};

@ -1,6 +1,7 @@
import type { Options } from "node_modules/payload/dist/globals/operations/local/findOne";
import { getPayload } from "@/utils/payload";
export const getContact = async () => {
export const getContact = async (opts: Omit<Options<"contact">, "slug"> = {}) => {
const payload = await getPayload();
return await payload.findGlobal({ slug: "contact" });
return await payload.findGlobal({ slug: "contact", ...opts });
};

@ -1,6 +1,7 @@
import type { Options } from "node_modules/payload/dist/globals/operations/local/findOne";
import { getPayload } from "@/utils/payload";
export const getGallery = async () => {
export const getGallery = async (opts: Omit<Options<"gallery">, "slug"> = {}) => {
const payload = await getPayload();
return await payload.findGlobal({ slug: "gallery" });
return await payload.findGlobal({ slug: "gallery", ...opts });
};

@ -1,6 +1,7 @@
import type { Options } from "node_modules/payload/dist/globals/operations/local/findOne";
import { getPayload } from "@/utils/payload";
export const getHome = async () => {
export const getHome = async (opts: Omit<Options<"home">, "slug"> = {}) => {
const payload = await getPayload();
return await payload.findGlobal({ slug: "home" });
return await payload.findGlobal({ slug: "home", ...opts });
};

@ -1,9 +1,11 @@
import { Options } from "node_modules/payload/dist/collections/operations/local/find";
import type { Options } from "node_modules/payload/dist/collections/operations/local/find";
import { getPayload } from "@/utils/payload";
export const getMenuCategories = async () => {
export const getMenuCategories = async (
opts: Omit<Options<"menu-category">, "collection" | "pagination"> = {},
) => {
const payload = await getPayload();
return payload.find({ collection: "menu-category", pagination: false });
return payload.find({ collection: "menu-category", pagination: false, ...opts });
};
export const getMenuItems = async (opts: Omit<Options<"menu-item">, "collection">) => {

@ -1,6 +1,14 @@
import type { Options } from "node_modules/payload/dist/collections/operations/local/find";
import { getPayload } from "@/utils/payload";
export const getOpeningTimes = async () => {
export const getOpeningTimes = async (
opts: Omit<Options<"opening-time">, "collection" | "sort" | "pagination">,
) => {
const payload = await getPayload();
return await payload.find({ collection: "opening-time", sort: "from", pagination: false });
return await payload.find({
collection: "opening-time",
sort: "from",
pagination: false,
...opts,
});
};

@ -1,17 +1,18 @@
import { Box, styled } from "@styled-system/jsx";
import { Container } from "@styled-system/jsx";
import { Metadata } from "next";
import { Params } from "../shared";
import RichText from "@/components/rich-text";
import { getAbout } from "@/api";
import { getI18n } from "@/i18n/server";
export default async function About() {
const about = await getAbout();
export default async function About({ params: { locale } }: { params: Params }) {
const t = await getI18n();
const about = await getAbout({ locale });
return (
<Box>
<styled.h1></styled.h1>
<Container pt={6}>
<RichText content={about.text!} />
</Box>
</Container>
);
}

@ -2,16 +2,17 @@ import { Box, HStack, Stack } from "@styled-system/jsx";
import { getAbout, getContact } from "@/api";
import { Heading } from "@/components/ui/heading";
import { Params } from "../shared";
import { Text } from "@/components/ui/text";
import { getI18n } from "@/i18n/server";
import { getOpeningTimes } from "@/api/openingTimes";
import { styled } from "@styled-system/jsx";
export default async function Contact() {
export default async function Contact({ params: { locale } }: { params: Params }) {
const t = await getI18n();
const about = await getAbout();
const contact = await getContact();
const openingTimes = await getOpeningTimes();
const about = await getAbout({ locale });
const contact = await getContact({ locale });
const openingTimes = await getOpeningTimes({ locale });
return (
<Stack p={6} gap={10}>

@ -1,9 +1,10 @@
import Carousel from "@/components/ui/carousel";
import { Locale } from "@/i18n/settings";
import { Media } from "@/payload-types";
import { getGallery } from "@/api";
export default async function Gallery() {
const { images } = await getGallery();
export default async function Gallery({ locale }: { locale: Locale }) {
const { images } = await getGallery({ locale });
return <Carousel images={images.map(({ image }) => image as Media)} w="100%" />;
}

@ -4,6 +4,7 @@ import Footer from "@/components/layout/footer";
import { I18nProviderClient } from "@/i18n/client";
import { Metadata } from "next";
import Navbar from "@/components/layout/navbar";
import { Params } from "./shared";
import { getAbout } from "@/api";
import localFont from "next/font/local";
import { locales } from "@/i18n/settings";
@ -18,18 +19,18 @@ export default async function RootLayout({
params: { locale },
children,
}: {
params: { locale: string };
params: Params;
children: React.ReactNode;
}) {
return (
<html lang={locale}>
<I18nProviderClient locale={locale}>
<styled.body className={moderustic.className}>
<Navbar />
<Navbar locale={locale} />
<styled.main mt={20} pb={20}>
{children}
</styled.main>
<Footer />
<Footer locale={locale} />
</styled.body>
</I18nProviderClient>
</html>

@ -4,6 +4,7 @@ import { HoverCard } from "@/components/ui/hover-card";
import { IconButton } from "@/components/ui/icon-button";
import Image from "next/image";
import { Image as ImageIcon } from "lucide-react";
import { Locale } from "@/i18n/settings";
import { Media } from "@/payload-types";
import RichText from "@/components/rich-text";
import { TabContentBaseProps } from "@ark-ui/react";
@ -12,12 +13,11 @@ import { Text } from "@/components/ui/text";
import { css } from "@styled-system/css";
import { formatToCHF } from "@/utils/formatters";
import { getMenuItems } from "@/api";
import { locales } from "@/i18n/settings";
export default async function CategoryTabContent({
locale,
...props
}: { locale: (typeof locales)[number] } & TabContentBaseProps) {
}: { locale: Locale } & TabContentBaseProps) {
const menuItems = await getMenuItems({
locale,
where: { category: { equals: props.value } },

@ -9,7 +9,7 @@ import { getMenuCategories } from "@/api";
export default async function Menu({ params: { locale } }: { params: Params }) {
const t = await getI18n();
const menuCategories = await getMenuCategories();
const menuCategories = await getMenuCategories({ locale });
return (
<Stack p={6} align="center">

@ -4,14 +4,14 @@ import { getAbout, getHome } from "@/api";
import Gallery from "./gallery";
import Image from "next/image";
import { Media } from "@/payload-types";
import { Metadata } from "next";
import { Params } from "./shared";
import RichText from "@/components/rich-text";
import { css } from "@styled-system/css";
import { styled } from "@styled-system/jsx";
export default async function Home() {
const home = await getHome();
const about = await getAbout();
export default async function Home({ params: { locale } }: { params: Params }) {
const home = await getHome({ locale });
const about = await getAbout({ locale });
return (
<Stack gap={10} align="center">
@ -37,7 +37,7 @@ export default async function Home() {
<RichText content={home.aboutText} />
</Container>
<Box maxW={600} w="100%" h="60vh">
<Gallery />
<Gallery locale={locale} />
</Box>
</Stack>
);

@ -1,3 +1,3 @@
import { locales } from "@/i18n/settings";
import { Locale } from "@/i18n/settings";
export type Params = { locale: (typeof locales)[number] };
export type Params = { locale: Locale };

@ -2,13 +2,14 @@ import { Box, HStack, Stack, styled } from "@styled-system/jsx";
import { getAbout, getContact } from "@/api";
import { IconButton } from "@/components/ui/icon-button";
import { Locale } from "@/i18n/settings";
import { SiFacebook } from "@icons-pack/react-simple-icons";
import { Text } from "@/components/ui/text";
import { stack } from "@styled-system/patterns";
export default async function Footer() {
const about = await getAbout();
const contact = await getContact();
export default async function Footer({ locale }: { locale: Locale }) {
const about = await getAbout({ locale });
const contact = await getContact({ locale });
return (
<styled.footer h={60} p={8} className={stack({ gap: 4, justify: "end" })}>

@ -1,6 +1,7 @@
import Image from "next/image";
import LanguagePicker from "./language-picker";
import Link from "next/link";
import { Locale } from "@/i18n/settings";
import { Media } from "@/payload-types";
import MobileNav from "./mobile-nav";
import NavLink from "./nav-link";
@ -10,9 +11,9 @@ import { getAbout } from "@/api";
import { getI18n } from "@/i18n/server";
import { styled } from "@styled-system/jsx";
export default async function Navbar() {
export default async function Navbar({ locale }: { locale: Locale }) {
const t = await getI18n();
const about = await getAbout();
const about = await getAbout({ locale });
return (
<styled.nav

@ -8,9 +8,12 @@ import {
IS_UNDERLINE,
} from "./node-format";
import React, { Fragment, JSX } from "react";
import { css, cva } from "@styled-system/css";
import { DefaultNodeTypes } from "@payloadcms/richtext-lexical";
import { cva } from "@styled-system/css";
import Image from "next/image";
import { Media } from "@/payload-types";
import { styled } from "@styled-system/jsx";
export type NodeTypes = DefaultNodeTypes;
@ -18,12 +21,12 @@ const headingRecipe = cva({
base: { fontSize: "xl" },
variants: {
size: {
h1: { fontSize: "xl" },
h2: { fontSize: "2xl" },
h3: { fontSize: "3xl" },
h4: { fontSize: "4xl" },
h5: { fontSize: "5xl" },
h6: { fontSize: "6xl" },
h1: { fontSize: "4xl" },
h2: { fontSize: "3xl" },
h3: { fontSize: "2xl" },
h4: { fontSize: "xl" },
h5: { fontSize: "lg" },
h6: { fontSize: "md" },
},
},
});
@ -102,7 +105,11 @@ export function serializeLexical({ nodes }: Props): JSX.Element {
return <br key={index} />;
}
case "paragraph": {
return <p key={index}>{serializedChildren}</p>;
return (
<styled.p key={index} mb={2}>
{serializedChildren}
</styled.p>
);
}
case "heading": {
const Tag = node?.tag;
@ -151,8 +158,23 @@ export function serializeLexical({ nodes }: Props): JSX.Element {
</a>
);
}
case "upload": {
const media = node.value as Media;
return (
<styled.div textAlign="center">
<Image
height={250}
width={500}
src={media.url!}
alt={media.alt ?? ""}
className={css({ display: "inline-block" })}
/>
</styled.div>
);
}
default:
console.log(node.type);
return null;
}
})}

@ -1,3 +1,4 @@
import { ContactEmbedNotice } from "@/globals/ContactEmbedNotice";
import type { GlobalConfig } from "payload";
export const Contact: GlobalConfig = {
@ -52,20 +53,6 @@ export const Contact: GlobalConfig = {
name: "embeddedMaps",
type: "code",
},
{
name: "embeddedMapsNotice",
type: "ui",
admin: {
components: {
Field: () => (
<p>
Use a generator like <a href="https://www.maps.ie/create-google-map/">maps.ie</a>{" "}
to create a Google Maps embed.
</p>
),
},
},
},
],
},
{

@ -0,0 +1,6 @@
export const ContactEmbedNotice = () => (
<p>
Use a generator like <a href="https://www.maps.ie/create-google-map/">maps.ie</a> to create a
Google Maps embed.
</p>
);

@ -4,9 +4,21 @@ export default {
menu: "Menu",
contact: "Contact",
home: "Home",
address: "Address",
email: "Email",
openingTimes: "Opening Times",
en: "English",
de: "German",
fr: "French",
it: "Italian",
},
days: {
"0": "Monday",
"1": "Tuesday",
"2": "Wednesday",
"3": "Thursday",
"4": "Friday",
"5": "Saturday",
"6": "Sunday",
},
} as const;

@ -1,2 +1,4 @@
export const defaultLocale = "de" as const;
export const locales = [defaultLocale, "en"] as const;
export type Locale = (typeof locales)[number];

Loading…
Cancel
Save