Compare commits

...

3 Commits

Author SHA1 Message Date
RaviAnand Mohabir da835189c5 feat: display menu item tags 3 weeks ago
RaviAnand Mohabir c5853f1f55 feat: 💄 add margin below images 3 weeks ago
RaviAnand Mohabir a5b8f491eb feat: add feature toggles to homepage
- Add take-away and delivery options
- Update responsive styling
3 weeks ago

@ -8,7 +8,7 @@ export const getMenuCategories = async (
return payload.find({ collection: "menu-category", pagination: false, ...opts });
};
export const getMenuItems = async (opts: Omit<Options<"menu-item">, "collection">) => {
export const getMenuItems = async (opts: Omit<Options<"menu-item">, "collection" | "depth">) => {
const payload = await getPayload();
return payload.find({ collection: "menu-item", ...opts });
return payload.find({ collection: "menu-item", depth: 1, ...opts });
};

@ -1,10 +1,10 @@
import { Cigarette, PawPrint } from "lucide-react";
import { Container, HStack, Stack } from "@styled-system/jsx";
import { Cigarette, DoorOpen, PawPrint, Truck } from "lucide-react";
import { Container, Stack } from "@styled-system/jsx";
import FeatureToggle from "@/components/general/feature-toggle";
import { Metadata } from "next";
import { Params } from "../shared";
import RichText from "@/components/rich-text";
import { Text } from "@/components/ui/text";
import { getAbout } from "@/api";
import { getI18n } from "@/i18n/server";
@ -17,18 +17,14 @@ export default async function About({ params: { locale } }: { params: Params })
<Stack gap={10}>
<RichText content={about.text!} />
<Stack>
{about.dogsAllowed && (
<HStack alignItems="center">
<PawPrint />
<Text>{t("about.dogsAllowed")}</Text>
</HStack>
)}
{about.fumoire && (
<HStack alignItems="center">
<Cigarette />
<Text>{t("about.fumoire")}</Text>
</HStack>
)}
<FeatureToggle
icon={PawPrint}
feature={about.dogsAllowed}
label={t("about.dogsAllowed")}
/>
<FeatureToggle icon={Cigarette} feature={about.fumoire} label={t("about.fumoire")} />
<FeatureToggle icon={Truck} feature={about.delivery} label={t("about.delivery")} />
<FeatureToggle icon={DoorOpen} feature={about.takeAway} label={t("about.takeAway")} />
</Stack>
</Stack>
</Container>

@ -59,14 +59,15 @@ export default async function Contact({
<Heading as="h3" size="xl">
{t("general.address")}
</Heading>
<HStack gap={12} alignItems="start">
<HStack gap={12} alignItems="start" flexWrap="wrap">
<Address locale={locale} />
<ContactMethods locale={locale} />
</HStack>
{contact.address.embeddedMaps && (
<styled.div
dangerouslySetInnerHTML={{ __html: contact.address.embeddedMaps }}
width={600}
maxW={600}
width="100%"
/>
)}
</Stack>

@ -1,11 +1,9 @@
import { Box, HStack, Stack } from "@styled-system/jsx";
import { HStack, Stack } from "@styled-system/jsx";
import type { Media, MenuItemTag as MenuItemTagT } from "@/payload-types";
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 MenuItemImage from "@/app/(frontend)/[locale]/menu/menu-item-image";
import MenuItemTag from "./menu-item-tag";
import RichText from "@/components/rich-text";
import { TabContentBaseProps } from "@ark-ui/react";
import { Tabs } from "@/components/ui/tabs";
@ -30,45 +28,27 @@ export default async function CategoryTabContent({
{menuItems.docs.map((mi) => (
<HStack key={mi.id} alignItems="start">
<Stack marginRight="auto">
<HStack>
<HStack alignItems="start">
<Text>{mi.name}</Text>
{mi.image && (
<HoverCard.Root>
<HoverCard.Trigger asChild>
<IconButton variant="ghost">
<ImageIcon />
</IconButton>
</HoverCard.Trigger>
<HoverCard.Positioner>
<HoverCard.Content>
<HoverCard.Arrow>
<HoverCard.ArrowTip />
</HoverCard.Arrow>
<Box w={250} h={150} position="relative">
<Image
src={(mi.image as Media).url!}
alt={(mi.image as Media).alt ?? ""}
className={css({ objectFit: "cover" })}
fill
/>
</Box>
</HoverCard.Content>
</HoverCard.Positioner>
</HoverCard.Root>
)}
<HStack flexWrap="wrap">
{mi.tags?.map((tag) => (
<MenuItemTag key={(tag as MenuItemTagT).id} tag={tag as MenuItemTagT} />
))}
</HStack>
{mi.image && <MenuItemImage image={mi.image as Media} />}
</HStack>
{mi.description && (
<RichText content={mi.description} className={css({ color: "fg.muted" })} />
)}
</Stack>
<HStack justify="end">
<Stack css={{ sm: { justifyContent: "end", flexDir: "row" } }}>
{mi.variants.map((v) => (
<Stack key={v.id} align="end">
<Text>{formatToCHF(v.price!)}</Text>
<Text color="fg.muted">{v.title}</Text>
</Stack>
))}
</HStack>
</Stack>
</HStack>
))}
</Stack>

@ -0,0 +1,34 @@
import { Box } from "@styled-system/jsx";
import { HoverCard } from "@ark-ui/react";
import { IconButton } from "@/components/ui/icon-button";
import Image from "next/image";
import { ImageIcon } from "lucide-react";
import { Media } from "@/payload-types";
import { css } from "@styled-system/css";
export default function MenuItemImage({ image }: { image: Media }) {
return (
<HoverCard.Root>
<HoverCard.Trigger asChild>
<IconButton variant="ghost">
<ImageIcon />
</IconButton>
</HoverCard.Trigger>
<HoverCard.Positioner>
<HoverCard.Content>
<HoverCard.Arrow>
<HoverCard.ArrowTip />
</HoverCard.Arrow>
<Box w={250} h={150} position="relative">
<Image
src={(image as Media).url!}
alt={(image as Media).alt ?? ""}
className={css({ objectFit: "cover" })}
fill
/>
</Box>
</HoverCard.Content>
</HoverCard.Positioner>
</HoverCard.Root>
);
}

@ -0,0 +1,41 @@
import { Box, HStack, Stack } from "@styled-system/jsx";
import { Media, MenuItemTag } from "@/payload-types";
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 MenuItemImage from "@/app/(frontend)/[locale]/menu/menu-item-image";
import RichText from "@/components/rich-text";
import { TabContentBaseProps } from "@ark-ui/react";
import { Tabs } from "@/components/ui/tabs";
import { Text } from "@/components/ui/text";
import { css } from "@styled-system/css";
import { formatToCHF } from "@/utils/formatters";
import { getMenuItems } from "@/api";
export default function MenuItemTag({ tag }: { tag: MenuItemTag }) {
return (
<HoverCard.Root>
<HoverCard.Trigger asChild>
<Box bg="accent.a8" color="white" fontSize="xs" borderRadius="md" p={1}>
{(tag as MenuItemTag).name}
</Box>
</HoverCard.Trigger>
<HoverCard.Positioner>
<HoverCard.Content p={2} pb={0.5}>
<HoverCard.Arrow>
<HoverCard.ArrowTip />
</HoverCard.Arrow>
{(tag as MenuItemTag).description !== undefined && (
<RichText
content={(tag as MenuItemTag).description}
className={css({ fontSize: "sm" })}
/>
)}
</HoverCard.Content>
</HoverCard.Positioner>
</HoverCard.Root>
);
}

@ -1,5 +1,5 @@
import { Box, Container, Stack, styled } from "@styled-system/jsx";
import { Info, Palmtree, PartyPopper } from "lucide-react";
import { Box, Container, HStack, Stack } from "@styled-system/jsx";
import { Cigarette, DoorOpen, Info, Palmtree, PartyPopper, PawPrint, Truck } from "lucide-react";
import {
getAbout,
getCurrentAnnouncements,
@ -9,6 +9,7 @@ import {
} from "@/api";
import { Alert } from "@/components/ui/alert";
import FeatureToggle from "@/components/general/feature-toggle";
import Gallery from "./gallery";
import { Heading } from "@/components/ui/heading";
import Image from "next/image";
@ -45,14 +46,10 @@ export default async function Home({ params: { locale } }: { params: Params }) {
maxH="80%"
align="center"
px={30}
gap={24}
gap={20}
color="white"
>
<Stack
maxW={550}
width="100%"
className={scrollable({ hideScrollbar: false, px: 2 })}
>
<Stack maxW={550} width="100%" className={scrollable({ hideScrollbar: false, px: 2 })}>
{announcements.docs.length > 0 && (
<Heading size="xl" color="white">
{t("general.announcements")}
@ -96,6 +93,16 @@ export default async function Home({ params: { locale } }: { params: Params }) {
<Text color="white" maxW={550} width="100%" textAlign="center" fontSize={36}>
{home.tagline}
</Text>
<HStack justify="center" flexWrap="wrap">
<FeatureToggle
icon={PawPrint}
feature={about.dogsAllowed}
label={t("about.dogsAllowed")}
/>
<FeatureToggle icon={Cigarette} feature={about.fumoire} label={t("about.fumoire")} />
<FeatureToggle icon={Truck} feature={about.delivery} label={t("about.delivery")} />
<FeatureToggle icon={DoorOpen} feature={about.takeAway} label={t("about.takeAway")} />
</HStack>
</Stack>
</Box>
<Container>

@ -1,15 +1,15 @@
import { Box, BoxProps } from "@styled-system/jsx";
import { getAbout, getContact } from "@/api";
import { Box } from "@styled-system/jsx";
import { Locale } from "@/i18n/settings";
import { Text } from "@/components/ui/text";
export default async function Address({ locale }: { locale: Locale }) {
export default async function Address({ locale, ...props }: { locale: Locale } & BoxProps) {
const about = await getAbout({ locale });
const contact = await getContact({ locale });
return (
<Box>
<Box {...props}>
<Text fontWeight="bold">{about.name}</Text>
<Text>
{contact.address.street} {contact.address.number}

@ -1,16 +1,17 @@
import { Grid } from "@styled-system/jsx";
import { Grid, GridProps } from "@styled-system/jsx";
import { Link } from "@/components/ui/link";
import { Locale } from "@/i18n/settings";
import { Text } from "@/components/ui/text";
import { getContact } from "@/api";
import { getI18n } from "@/i18n/server";
export default async function ContactMethods({ locale }: { locale: Locale }) {
export default async function ContactMethods({ locale, ...props }: { locale: Locale } & GridProps) {
const t = await getI18n();
const contact = await getContact({ locale });
return (
<Grid gridTemplateColumns="min-content 1fr" columnGap={2} rowGap={0.5}>
<Grid gridTemplateColumns="min-content 1fr" columnGap={2} rowGap={0.5} {...props}>
{contact.phone && (
<>
<Text fontWeight="bold">{t("general.phoneNumber")}</Text>

@ -0,0 +1,20 @@
import { HStack } from "@styled-system/jsx";
import React from "react";
import { Text } from "@/components/ui/text";
type FeatureToggleProps = {
feature: boolean;
icon: React.ComponentType;
label: string;
};
export default function FeatureToggle({ feature, icon: Icon, label }: FeatureToggleProps) {
return (
feature && (
<HStack alignItems="center">
<Icon />
<Text>{label}</Text>
</HStack>
)
);
}

@ -18,9 +18,15 @@ export default async function Footer({ locale }: { locale: Locale }) {
return (
<styled.footer minH={60} p={8} className={stack({ gap: 4, justify: "end" })}>
<HStack justify="space-between" alignItems="start" flexWrap="wrap">
<Address locale={locale} />
<HStack>
<Stack
css={{
flexDir: "column",
alignItems: "center",
sm: { flexDir: "row", alignItems: "start" },
}}
>
<Address locale={locale} flex={1} />
<HStack flex={1} justify="center">
{(contact.socialLinks ?? []).map((sl) => (
<IconButton key={sl.id} asChild variant="link">
<a href={sl.link}>
@ -29,8 +35,10 @@ export default async function Footer({ locale }: { locale: Locale }) {
</IconButton>
))}
</HStack>
<ContactMethods locale={locale} />
</HStack>
<HStack flex={1} justify="end">
<ContactMethods locale={locale} />
</HStack>
</Stack>
<Stack alignSelf="center" gap={1}>
<Heading size="lg">{t("general.openingTimes")}</Heading>
<OpeningTimes locale={locale} />

@ -162,7 +162,7 @@ export function serializeLexical({ nodes }: Props): JSX.Element {
const media = node.value as Media;
return (
<styled.div textAlign="center">
<styled.div textAlign="center" mb={4}>
<Image
height={250}
width={500}

@ -31,5 +31,15 @@ export const About: GlobalConfig = {
type: "checkbox",
required: true,
},
{
name: "delivery",
type: "checkbox",
required: true,
},
{
name: "takeAway",
type: "checkbox",
required: true,
},
],
};

@ -31,6 +31,8 @@ export default {
about: {
dogsAllowed: "Hunde erlaubt",
fumoire: "Fumoire verfügbar",
takeAway: "Take-away",
delivery: "Lieferung",
},
contact: {
name: "Name",

@ -349,6 +349,8 @@ export interface About {
} | null;
dogsAllowed: boolean;
fumoire: boolean;
delivery: boolean;
takeAway: boolean;
updatedAt?: string | null;
createdAt?: string | null;
}

Loading…
Cancel
Save