feat: refactor NewDates, clean up legacy code

This reverts commit 0c7836fa59.
This commit is contained in:
Simon Emanuelsson
2025-05-03 19:33:04 +02:00
parent c6a0b4ee30
commit db289b80b1
96 changed files with 1603 additions and 1500 deletions

View File

@@ -1,3 +1,7 @@
.dialog {
max-width: 690px;
}
.links {
display: grid;
gap: var(--Space-x05);

View File

@@ -8,7 +8,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import styles from "./customerSupport.module.css"
@@ -30,7 +30,7 @@ export default function CustomerSupportModal() {
return (
<Modal>
<Dialog>
<Dialog className={styles.dialog}>
{({ close }) => (
<Modal.Content>
<Modal.Content.Header handleClose={close} title={title}>

View File

@@ -15,4 +15,5 @@
.text {
color: var(--Text-Interactive-Default);
text-align: left;
}

View File

@@ -3,7 +3,7 @@ import { useIntl } from "react-intl"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import Alert from "@/components/TempDesignSystem/Alert"
import { AlertTypeEnum } from "@/types/enums/alert"

View File

@@ -7,7 +7,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import { dt } from "@/lib/dt"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import useLang from "@/hooks/useLang"
import CancelStayPriceContainer from "../CancelStayPriceContainer"

View File

@@ -7,7 +7,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import { trpc } from "@/lib/trpc/client"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import { toast } from "@/components/TempDesignSystem/Toasts"
import useLang from "@/hooks/useLang"

View File

@@ -1,3 +1,7 @@
.dialog {
max-width: 690px;
}
.modalText {
display: flex;
flex-direction: column;

View File

@@ -2,11 +2,13 @@
import { Dialog, DialogTrigger } from "react-aria-components"
import { useIntl } from "react-intl"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import Alerts from "./Alerts"
import Steps from "./Steps"
import styles from "./cancelStay.module.css"
export default function CancelStay() {
const intl = useIntl()
return (
@@ -15,7 +17,7 @@ export default function CancelStay() {
{intl.formatMessage({ defaultMessage: "Cancel stay" })}
</Modal.Button>
<Modal>
<Dialog>
<Dialog className={styles.dialog}>
{({ close }) => (
<Alerts closeModal={close}>
<Steps closeModal={close} />

View File

@@ -1,7 +1,7 @@
"use client"
import { useIntl } from "react-intl"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import Alert from "@/components/TempDesignSystem/Alert"
import { AlertTypeEnum } from "@/types/enums/alert"

View File

@@ -1,7 +1,7 @@
"use client"
import { useIntl } from "react-intl"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import Alert from "@/components/TempDesignSystem/Alert"
import { AlertTypeEnum } from "@/types/enums/alert"

View File

@@ -1,7 +1,7 @@
"use client"
import { useIntl } from "react-intl"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import Alert from "@/components/TempDesignSystem/Alert"
import { AlertTypeEnum } from "@/types/enums/alert"

View File

@@ -5,7 +5,7 @@ import { dt } from "@/lib/dt"
import { trpc } from "@/lib/trpc/client"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import PriceContainer from "@/components/HotelReservation/MyStay/ReferenceCard/PriceContainer"
import Divider from "@/components/TempDesignSystem/Divider"
import { toast } from "@/components/TempDesignSystem/Toasts"

View File

@@ -1,14 +0,0 @@
.button {
background-color: var(--Main-Grey-White);
border-color: var(--Scandic-Beige-40);
border-style: solid;
border-width: 1px;
border-radius: var(--Corner-radius-Medium);
display: flex;
align-items: center;
justify-content: space-between;
min-width: 0; /* allow shrinkage */
height: 60px;
padding: var(--Spacing-x1) var(--Spacing-x2);
transition: border-color 200ms ease;
}

View File

@@ -1,24 +0,0 @@
"use client"
import { Button as ButtonRAC } from "react-aria-components"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import styles from "./calendarButton.module.css"
interface CalendarButtonProps {
text: string
onClick: () => void
}
export default function CalendarButton({ text, onClick }: CalendarButtonProps) {
return (
<ButtonRAC onPress={onClick} className={styles.button}>
<Typography variant="Body/Paragraph/mdRegular">
<span>{text}</span>
</Typography>
<MaterialIcon icon="calendar_today" />
</ButtonRAC>
)
}

View File

@@ -1,39 +1,33 @@
"use client"
import { useState } from "react"
import { createPortal } from "react-dom"
import { useFormContext } from "react-hook-form"
import {
Button as ButtonRAC,
Dialog,
DialogTrigger,
} from "react-aria-components"
import { useFormContext, useWatch } from "react-hook-form"
import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { dt } from "@/lib/dt"
import { useMyStayStore } from "@/stores/my-stay"
import DatePickerSingleDesktop from "@/components/DatePicker/Single/Desktop"
import DatePickerSingleMobile from "@/components/DatePicker/Single/Mobile"
import Modal from "@/components/Modal"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import useLang from "@/hooks/useLang"
import CalendarButton from "./CalendarButton"
import styles from "./newDates.module.css"
import type { DateRange } from "react-day-picker"
export default function NewDates() {
const { checkInDate, checkOutDate } = useMyStayStore((state) => ({
checkInDate: state.mainRoom.checkInDate,
checkOutDate: state.mainRoom.checkOutDate,
}))
const [showCheckInDatePicker, setShowCheckInDatePicker] = useState(false)
const [showCheckOutDatePicker, setShowCheckOutDatePicker] = useState(false)
const [selectedDates, setSelectedDates] = useState<DateRange>(() => ({
from: dt(checkInDate).startOf("day").toDate(),
to: dt(checkOutDate).startOf("day").toDate(),
}))
interface NewDatesProps {
checkInDate: Date
checkOutDate: Date
}
export default function NewDates({ checkInDate, checkOutDate }: NewDatesProps) {
const intl = useIntl()
const lang = useLang()
const { setValue } = useFormContext()
// Calculate default number of days between check-in and check-out
@@ -41,147 +35,111 @@ export default function NewDates() {
.startOf("day")
.diff(dt(checkInDate).startOf("day"), "days")
function showCheckInPicker() {
// Update selected dates before showing picker
setSelectedDates((prev) => ({
from: prev.from ?? dt(checkInDate).startOf("day").toDate(),
to: prev.to ?? dt(checkOutDate).startOf("day").toDate(),
}))
setShowCheckInDatePicker(true)
setShowCheckOutDatePicker(false)
const fromDate = useWatch({ name: "checkInDate" })
const toDate = useWatch({ name: "checkOutDate" })
function handleSelectDate(date: Date, name: "checkInDate" | "checkOutDate") {
setValue(name, dt(date).format("YYYY-MM-DD"))
}
function showCheckOutPicker() {
// Update selected dates before showing picker
setSelectedDates((prev) => ({
from: prev.from ?? dt(checkInDate).startOf("day").toDate(),
to: prev.to ?? dt(checkOutDate).startOf("day").toDate(),
}))
setShowCheckOutDatePicker(true)
setShowCheckInDatePicker(false)
}
function handleCheckInDateSelect(date: Date) {
const newCheckIn = dt(date).startOf("day")
const currentCheckOut = dt(selectedDates.to).startOf("day")
// Calculate new check-out date based on defaultDaysBetween, only if new check-in is after current check-out
const newCheckOut = newCheckIn.isSameOrAfter(currentCheckOut)
? newCheckIn.add(defaultDaysBetween, "days")
: currentCheckOut
// Update selected dates state first
const newDates = {
from: newCheckIn.toDate(),
to: newCheckOut.toDate(),
function handleSelectCheckInDate(checkIn: Date) {
handleSelectDate(checkIn, "checkInDate")
if (dt(checkIn).isSameOrAfter(toDate)) {
handleSelectDate(
dt(checkIn).add(defaultDaysBetween, "days").toDate(),
"checkOutDate"
)
}
setSelectedDates(newDates)
// Then update form values
setValue("checkInDate", newCheckIn.format("YYYY-MM-DD"))
setValue("checkOutDate", newCheckOut.format("YYYY-MM-DD"))
}
function handleCheckOutDateSelect(date: Date) {
const newCheckOut = dt(date).startOf("day")
const currentCheckIn = dt(selectedDates.from).startOf("day")
// Only adjust check-in if new check-out is before current check-in
const newCheckIn = newCheckOut.isBefore(currentCheckIn)
? newCheckOut.subtract(defaultDaysBetween, "days")
: currentCheckIn
// Update selected dates state
const newDates = {
from: newCheckIn.toDate(),
to: newCheckOut.toDate(),
function handleSelectCheckOutDate(checkOut: Date) {
handleSelectDate(checkOut, "checkOutDate")
if (dt(checkOut).isSameOrBefore(fromDate)) {
handleSelectDate(
dt(checkOut).subtract(defaultDaysBetween, "days").toDate(),
"checkInDate"
)
}
setSelectedDates(newDates)
// Then update form values
setValue("checkInDate", newCheckIn.format("YYYY-MM-DD"))
setValue("checkOutDate", newCheckOut.format("YYYY-MM-DD"))
}
const fromDate = selectedDates.from ?? dt(checkInDate).toDate()
const toDate = selectedDates.to ?? dt(checkOutDate).toDate()
const checkInLabel = intl.formatMessage({ defaultMessage: "Check-in" })
const checkOutLabel = intl.formatMessage({ defaultMessage: "Check-out" })
const checkInText = dt(fromDate).locale(lang).format("dddd, DD MMM, YYYY")
const checkOutText = dt(toDate).locale(lang).format("dddd, DD MMM, YYYY")
return (
<>
<div className={styles.container}>
<div className={styles.checkInDate}>
<Caption color="uiTextHighContrast" type="bold">
{intl.formatMessage({
defaultMessage: "Check-in",
})}
</Caption>
<Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.textDefault}>{checkInLabel}</span>
</Typography>
<CalendarButton
text={dt(selectedDates.from ?? new Date())
.locale(lang)
.format("dddd, DD MMM, YYYY")}
onClick={showCheckInPicker}
/>
<DialogTrigger>
<ButtonRAC className={styles.trigger}>
<Typography variant="Body/Paragraph/mdRegular">
<span>{checkInText}</span>
</Typography>
<MaterialIcon icon="calendar_today" />
</ButtonRAC>
<Modal>
<Dialog>
{({ close }) => (
<>
<DatePickerSingleDesktop
close={close}
handleOnSelect={handleSelectCheckInDate}
selectedDate={fromDate}
startMonth={fromDate}
/>
<DatePickerSingleMobile
close={close}
handleOnSelect={handleSelectCheckInDate}
hideHeader
selectedDate={fromDate}
/>
</>
)}
</Dialog>
</Modal>
</DialogTrigger>
</div>
<div className={styles.checkOutDate}>
<Caption color="uiTextHighContrast" type="bold">
{intl.formatMessage({
defaultMessage: "Check-out",
})}
</Caption>
<CalendarButton
text={dt(selectedDates.to ?? new Date())
.locale(lang)
.format("dddd, DD MMM, YYYY")}
onClick={showCheckOutPicker}
/>
<div className={styles.checkOutDate}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.textDefault}>{checkOutLabel}</span>
</Typography>
<DialogTrigger>
<ButtonRAC className={styles.trigger}>
<Typography variant="Body/Paragraph/mdRegular">
<span>{checkOutText}</span>
</Typography>
<MaterialIcon icon="calendar_today" />
</ButtonRAC>
<Modal>
<Dialog>
{({ close }) => (
<>
<DatePickerSingleDesktop
close={close}
handleOnSelect={handleSelectCheckOutDate}
selectedDate={toDate}
startMonth={toDate}
/>
<DatePickerSingleMobile
close={close}
handleOnSelect={handleSelectCheckOutDate}
hideHeader
selectedDate={toDate}
/>
</>
)}
</Dialog>
</Modal>
</DialogTrigger>
</div>
</div>
{showCheckInDatePicker &&
createPortal(
<Modal
isOpen={showCheckInDatePicker}
onToggle={() => setShowCheckInDatePicker(!showCheckInDatePicker)}
>
<DatePickerSingleDesktop
close={() => setShowCheckInDatePicker(false)}
handleOnSelect={handleCheckInDateSelect}
selectedDate={fromDate}
startMonth={fromDate}
/>
<DatePickerSingleMobile
close={() => setShowCheckInDatePicker(false)}
handleOnSelect={handleCheckInDateSelect}
selectedDate={fromDate}
hideHeader
/>
</Modal>,
document.body
)}
{showCheckOutDatePicker &&
createPortal(
<Modal
isOpen={showCheckOutDatePicker}
onToggle={() => setShowCheckOutDatePicker(!showCheckOutDatePicker)}
>
<DatePickerSingleDesktop
close={() => setShowCheckOutDatePicker(false)}
handleOnSelect={handleCheckOutDateSelect}
selectedDate={toDate}
startMonth={toDate}
/>
<DatePickerSingleMobile
close={() => setShowCheckOutDatePicker(false)}
handleOnSelect={handleCheckOutDateSelect}
selectedDate={toDate}
hideHeader
/>
</Modal>,
document.body
)}
</>
)
}

View File

@@ -13,3 +13,23 @@
flex-direction: column;
gap: var(--Spacing-x1);
}
.trigger {
align-items: center;
background-color: var(--Main-Grey-White);
border-color: var(--Scandic-Beige-40);
border-radius: var(--Corner-radius-Medium);
border-style: solid;
border-width: 1px;
display: flex;
height: 60px;
justify-content: space-between;
min-width: 0;
/* allow shrinkage */
padding: var(--Spacing-x1) var(--Spacing-x2);
transition: border-color 200ms ease;
}
.textDefault {
color: var(--Text-Default);
}

View File

@@ -6,7 +6,7 @@ import { useIntl } from "react-intl"
import { dt } from "@/lib/dt"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import { toast } from "@/components/TempDesignSystem/Toasts"
import NoAvailability from "./Alerts/NoAvailability"
@@ -62,7 +62,7 @@ export default function Form({
/>
<Modal.Content.Body>
{noAvailability && <NoAvailability />}
<NewDates />
<NewDates checkInDate={checkInDate} checkOutDate={checkOutDate} />
</Modal.Content.Body>
<Modal.Content.Footer>
<Modal.Content.Footer.Secondary onClick={closeModal}>

View File

@@ -4,7 +4,7 @@ import { useIntl } from "react-intl"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import { dateHasPassed } from "../utils"
import Alerts from "./Alerts"

View File

@@ -2,8 +2,8 @@
import { DialogTrigger } from "react-aria-components"
import { useIntl } from "react-intl"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import CustomerSupportModal from "@/components/HotelReservation/MyStay/ReferenceCard/Actions/CustomerSupportModal"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
export default function CustomerSupport() {
const intl = useIntl()

View File

@@ -34,15 +34,21 @@
}
.guaranteeCostText {
align-items: flex-end;
display: flex;
flex-direction: column;
}
.baseTextHighContrast {
color: var(--Base-Text-High-contrast);
white-space: nowrap;
}
.textDefault {
color: var(--Text-Default);
}
@media screen and (min-width: 768px) {
.guaranteeCostText {
align-items: flex-end;
}
}

View File

@@ -6,11 +6,13 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import { dateHasPassed } from "../utils"
import Form from "./Form"
import styles from "./guarantee.module.css"
export default function GuaranteeLateArrival() {
const intl = useIntl()
@@ -41,7 +43,7 @@ export default function GuaranteeLateArrival() {
<DialogTrigger>
<Modal.Button icon="check">{text}</Modal.Button>
<Modal>
<Dialog>
<Dialog className={styles.dialog}>
{({ close }) => (
<Modal.Content>
<Modal.Content.Header handleClose={close} title={text}>

View File

@@ -3,7 +3,6 @@
background-color: var(--Surface-Primary-OnSurface-Default);
border-radius: var(--Corner-radius-md);
display: flex;
flex-direction: column;
gap: var(--Space-x2);
justify-content: center;
padding: var(--Space-x15) var(--Space-x3);
@@ -27,3 +26,9 @@
display: flex;
flex-direction: column;
}
@media screen and (min-width: 768px) {
.container {
flex-direction: column;
}
}

View File

@@ -11,7 +11,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
import Modal from "@/components/HotelReservation/MyStay/Modal"
import Actions from "./Actions"
import Info from "./Info"

View File

@@ -24,7 +24,8 @@
.dialog {
display: grid;
gap: var(--Space-x3);
flex: 1;
gap: var(--Space-x2);
}
.header {
@@ -47,6 +48,16 @@
.content {
display: grid;
gap: var(--Space-x3);
grid-template-columns: 1fr 1fr;
gap: var(--Space-x2);
}
@media screen and (min-width: 768px) {
.dialog {
gap: var(--Space-x3);
}
.content {
gap: var(--Space-x3);
grid-template-columns: 1fr 1fr;
}
}

View File

@@ -4,6 +4,7 @@
border-radius: var(--Corner-radius-rounded);
color: var(--Text-Interactive-Default);
display: flex;
height: 48px;
justify-content: center;
text-decoration: none;
}

View File

@@ -1,14 +0,0 @@
.button {
align-items: center;
background: none;
border: none;
cursor: pointer;
display: flex;
gap: var(--Space-x1);
padding: var(--Space-x1) 0;
width: 100%;
}
.text {
color: var(--Text-Interactive-Default);
}

View File

@@ -1,30 +0,0 @@
"use client"
import { Button as ButtonRAC } from "react-aria-components"
import {
MaterialIcon,
type MaterialIconProps,
} from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import styles from "./button.module.css"
interface ButtonProps extends React.PropsWithChildren {
icon: MaterialIconProps["icon"]
isDisabled?: boolean
}
export default function Button({
children,
icon,
isDisabled = false,
}: ButtonProps) {
return (
<ButtonRAC className={styles.button} isDisabled={isDisabled}>
<MaterialIcon color="Icon/Interactive/Default" icon={icon} />
<Typography variant="Body/Paragraph/mdBold">
<span className={styles.text}>{children}</span>
</Typography>
</ButtonRAC>
)
}

View File

@@ -1,15 +0,0 @@
.content {
display: flex;
flex-direction: column;
gap: var(--Spacing-x3);
max-height: 70vh;
overflow-y: auto;
width: 100%;
}
@media screen and (min-width: 768px) {
.content {
width: 640px;
max-width: 100%;
}
}

View File

@@ -1,5 +0,0 @@
import styles from "./body.module.css"
export default function Body({ children }: React.PropsWithChildren) {
return <div className={styles.content}>{children}</div>
}

View File

@@ -1,7 +0,0 @@
.footer {
border-top: 1px solid var(--Base-Border-Subtle);
display: flex;
justify-content: space-between;
padding-top: var(--Spacing-x3);
width: 100%;
}

View File

@@ -1,64 +0,0 @@
import Button from "@/components/TempDesignSystem/Button"
import styles from "./footer.module.css"
import type { ButtonHTMLAttributes, PropsWithChildren } from "react"
import type { ButtonProps as ReactAriaButtonProps } from "react-aria-components"
import type { ButtonProps as _ButtonProps } from "@/components/TempDesignSystem/Button/button"
export default function Footer({ children }: PropsWithChildren) {
return <footer className={styles.footer}>{children}</footer>
}
interface ButtonProps extends PropsWithChildren {
intent?: _ButtonProps["intent"]
onClick?: ReactAriaButtonProps["onPress"]
type?: ButtonHTMLAttributes<HTMLButtonElement>["type"]
}
interface PrimaryButtonProps extends ButtonProps {
disabled?: boolean
form?: string
}
Footer.Primary = function PrimaryButton({
children,
disabled = false,
form,
intent = "primary",
onClick,
type = "button",
}: PrimaryButtonProps) {
return (
<Button
disabled={disabled}
form={form}
intent={intent}
onClick={onClick}
theme="base"
type={type}
>
{children}
</Button>
)
}
Footer.Secondary = function SecondaryButton({
children,
intent = "text",
onClick,
type = "button",
}: ButtonProps) {
return (
<Button
color="burgundy"
intent={intent}
onClick={onClick}
theme="base"
type={type}
>
{children}
</Button>
)
}

View File

@@ -1,15 +0,0 @@
.header {
display: grid;
gap: var(--Space-x05) var(--Space-x2);
grid-template-columns: 1fr auto;
}
.close {
align-items: center;
background: none;
border: none;
cursor: pointer;
display: flex;
justify-content: center;
padding: 0;
}

View File

@@ -1,24 +0,0 @@
import { Button as ButtonRAC } from "react-aria-components"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import styles from "./header.module.css"
interface HeaderProps extends React.PropsWithChildren {
handleClose: () => void
title: string
}
export default function Header({ children, handleClose, title }: HeaderProps) {
return (
<header className={styles.header}>
<Subtitle>{title}</Subtitle>
<ButtonRAC className={styles.close} onPress={handleClose}>
<MaterialIcon icon="close" color="Icon/Interactive/Placeholder" />
</ButtonRAC>
{children}
</header>
)
}

View File

@@ -1,15 +0,0 @@
import Body from "./Body"
import Footer from "./Footer"
import Header from "./Header"
import styles from "./modalContent.module.css"
import type { PropsWithChildren } from "react"
export default function ModalContent({ children }: PropsWithChildren) {
return <div className={styles.container}>{children}</div>
}
ModalContent.Body = Body
ModalContent.Footer = Footer
ModalContent.Header = Header

View File

@@ -1,4 +0,0 @@
.container {
display: grid;
gap: var(--Space-x3);
}

View File

@@ -1,17 +0,0 @@
import { Modal as ModalRAC, ModalOverlay } from "react-aria-components"
import Button from "./Button"
import ModalContent from "./ModalContent"
import styles from "./modal.module.css"
export default function Modal({ children }: React.PropsWithChildren) {
return (
<ModalOverlay className={styles.overlay} isDismissable>
<ModalRAC className={styles.modal}>{children}</ModalRAC>
</ModalOverlay>
)
}
Modal.Button = Button
Modal.Content = ModalContent

View File

@@ -1,70 +0,0 @@
.overlay {
background: rgba(0, 0, 0, 0.4);
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
width: 100dvw;
z-index: var(--default-modal-overlay-z-index);
&[data-entering] {
animation: overlay-fade 200ms;
}
&[data-exiting] {
animation: overlay-fade 150ms reverse ease-in;
}
}
@keyframes overlay-fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.modal {
background: var(--UI-Input-Controls-Surface-Normal);
border-top-left-radius: var(--Corner-radius-Large);
border-top-right-radius: var(--Corner-radius-Large);
max-height: 95dvh;
overflow-y: auto;
padding: var(--Space-x3);
position: absolute;
z-index: var(--default-modal-z-index);
&[data-entering] {
animation: modal-anim 200ms;
}
&[data-exiting] {
animation: modal-anim 150ms reverse ease-in;
}
}
@keyframes modal-anim {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
@media screen and (min-width: 768px) {
.overlay {
align-items: center;
display: flex;
justify-content: center;
}
.modal {
border-radius: var(--Corner-radius-Large);
width: min(690px, 100dvw);
}
}

View File

@@ -33,8 +33,8 @@ export default function PriceContainer({
{totalChildren > 0 ? `, ${childrenText}` : ""}
</Caption>
</div>
<div className={styles.price}>
<Subtitle color="burgundy" type="one">
<div className={styles.wrapper}>
<Subtitle className={styles.price} color="burgundy" type="one">
{price}
</Subtitle>
</div>

View File

@@ -15,8 +15,12 @@
flex-direction: column;
}
.price {
.wrapper {
padding-left: var(--Spacing-x2);
display: flex;
align-items: center;
}
.price {
white-space: nowrap;
}