Migrate filter modal.

pull/3/head
Joshua Potter 2023-12-04 16:04:30 -07:00
parent 99b9519ab7
commit 3cd0228906
13 changed files with 833 additions and 4 deletions

View File

@ -0,0 +1,66 @@
import * as React from "react"
export const FieldContext = React.createContext<{
required?: boolean
disabled?: boolean
error?: string | boolean
}>({})
function Wrapper(props: React.ComponentPropsWithoutRef<"div">) {
const fieldContext = React.useContext(FieldContext)
const { children, ...other } = props
return (
<>
<div {...other}>{children}</div>
{typeof fieldContext?.error === "string" && (
<p className="pt-2 text-sm text-amber-800">{fieldContext?.error}</p>
)}
</>
)
}
type WrapperProps<T extends React.ElementType> =
React.ComponentPropsWithoutRef<T> & {
slotProps?: {
root?: React.ComponentPropsWithoutRef<"div">
}
}
export const Field = React.forwardRef<
HTMLDivElement,
WrapperProps<"div"> & {
required?: boolean
disabled?: boolean
error?: string | boolean
}
>(function Field(props, ref) {
const { children, slotProps, required, disabled, error, ...other } = props
return (
<FieldContext.Provider value={{ required, disabled, error }}>
<div ref={ref} {...other}>
<Wrapper {...slotProps?.root}>{children}</Wrapper>
</div>
</FieldContext.Provider>
)
})
export const FieldSet = React.forwardRef<
HTMLFieldSetElement,
WrapperProps<"fieldset"> & {
required?: boolean
disabled?: boolean
error?: string | boolean
}
>(function FieldSet(props, ref) {
const { children, slotProps, required, disabled, error, ...other } = props
return (
<FieldContext.Provider value={{ required, disabled, error }}>
<fieldset ref={ref} {...other}>
<Wrapper {...slotProps?.root}>{children}</Wrapper>
</fieldset>
</FieldContext.Provider>
)
})

View File

@ -0,0 +1,138 @@
import * as React from "react"
import { Controller, useForm } from "react-hook-form"
import { Button } from "./Button"
import { Field } from "./FieldSet"
import { Input } from "./Input"
import { Label } from "./Label"
import { Modal } from "./Modal"
import { Slider } from "./Slider"
import {
FIDE_RATING_MIN,
FIDE_RATING_MAX,
SearchParams,
} from "../types/SearchParams"
const computeStepLabels = (
min: number,
max: number,
// The number of labels (+ 1) that should be produced.
steps: number,
// To which value numbers should be rounded to.
round: number
) => {
let labels = []
const delta = Math.floor((max - min) / steps)
for (let i = min; i <= max; i += delta) {
if (i % round <= round / 2) {
labels.push(i - (i % round))
} else {
labels.push(i + round - (i % round))
}
}
labels[labels.length - 1] = max
return labels
}
interface FilterModalProps {
open: boolean
defaultValues: SearchParams
onClose: () => void
onSubmit: (p: SearchParams) => void
}
export function FilterModal({
open,
defaultValues,
onClose,
onSubmit,
}: FilterModalProps) {
const idPrefix = React.useId()
const { watch, reset, control, register, setValue, handleSubmit } =
useForm<SearchParams>({ defaultValues })
// Default values are processed immediately despite the modal not being open
// at the start. Furthermore, values are preserved after closing and
// re-opening the modal, but we want closing the modal to signify canceling.
// A simple workaround is to reset everytime we open the modal.
React.useEffect(() => reset(defaultValues), [open])
// Registration
const controlFIDERating = register("fideRating")
return (
<Modal
open={open}
onClose={onClose}
closeAfterTransition
frame={{
as: "form",
title: "Filters",
footer: (
<Button className="float-right py-2" type="submit">
Search coaches
</Button>
),
onSubmit: handleSubmit(onSubmit),
}}
>
<div className="flex flex-col gap-12">
<Field>
<Label htmlFor={`${idPrefix}-fideRating`}>FIDE Rating:</Label>
<p className="py-2 text-sm">
Find coaches that have a rating within the specified range. Keep in
mind, a higher rating does not necessarily mean a better coach{" "}
<i>for you</i>. If you are unsure of this or do not have any
preference, leave as is.
</p>
<div id={`${idPrefix}-fideRating`} className="mt-2 w-full px-4">
<Controller
control={control}
name={controlFIDERating.name}
render={({ field: { onChange, onBlur, value, ref } }) => (
<Slider
ref={ref}
value={value}
onBlur={onBlur}
onChange={(event, newValue: any) => {
event && onChange(event)
setValue("fideRating.0", newValue[0])
setValue("fideRating.1", newValue[1])
}}
step={10}
min={FIDE_RATING_MIN}
max={FIDE_RATING_MAX}
marks={computeStepLabels(
FIDE_RATING_MIN,
FIDE_RATING_MAX,
7,
50
).map((s) => ({ value: s, label: `${s}` }))}
/>
)}
/>
<div className="mt-16 flex flex-wrap items-center justify-center gap-x-20 gap-y-4">
<div>
<label className="text-neutral-850 text-sm font-medium">
Min:
</label>
<Input value={watch("fideRating.0")} disabled />
</div>
<div>
<label className="text-neutral-850 text-sm font-medium">
Max:
</label>
<Input value={watch("fideRating.1")} disabled />
</div>
</div>
</div>
</Field>
</div>
</Modal>
)
}

View File

@ -0,0 +1,41 @@
import * as React from "react"
import clsx from "clsx"
import {
Input as BaseInput,
InputProps,
InputOwnerState,
} from "@mui/base/Input"
import { FieldContext } from "./FieldSet"
import { resolveSlotProps } from "../utils/props"
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
function Input(props: InputProps, ref: React.ForwardedRef<HTMLInputElement>) {
const fieldContext = React.useContext(FieldContext)
const { disabled = fieldContext?.disabled, ...other } = props
const inputSlotProps = (ownerState: InputOwnerState) => {
const resolved = resolveSlotProps(props.slotProps?.input, ownerState)
return {
...resolved,
className: clsx(
"text-sm font-normal leading-5 px-3 py-2 rounded-lg shadow-md border border-solid shadow-slate-100 focus:shadow-lg bg-white text-slate-900",
fieldContext?.error
? "border-amber-800 focus-visible:outline focus-visible:outline-1 focus-visible:outline-amber-800"
: "border-slate-300",
{ "opacity-60": ownerState.disabled },
resolved?.className
),
}
}
return (
<BaseInput
ref={ref}
{...other}
slotProps={{ input: inputSlotProps }}
disabled={disabled}
/>
)
}
)

View File

@ -0,0 +1,36 @@
import * as React from "react"
import clsx from "clsx"
import { FieldContext } from "./FieldSet"
type LabelProps = {
children: React.ReactNode
sublabel?: boolean
} & React.ComponentPropsWithoutRef<"label">
export const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
function Label(props, ref) {
const fieldContext = React.useContext(FieldContext)
const { children, sublabel, className, ...other } = props
return (
<label
ref={ref}
{...other}
className={clsx(
"block font-semibold",
{
'text-neutral-850 before:content-["*"]':
fieldContext?.required && !sublabel,
"text-neutral-600/80": !fieldContext?.required,
"text-sm": sublabel,
"opacity-60": fieldContext?.disabled,
},
className
)}
>
{children}
</label>
)
}
)

View File

@ -0,0 +1,93 @@
import * as React from "react"
import clsx from "clsx"
import {
Modal as BaseModal,
ModalBackdropSlotProps,
ModalProps,
} from "@mui/base/Modal"
import XIcon from "../icons/X"
import { FadeIn } from "./FadeIn"
const Backdrop = React.forwardRef<HTMLDivElement, ModalBackdropSlotProps>(
function Backdrop(props, ref) {
const { open, ownerState, onClick, ...other } = props
return (
<div
className={clsx(
{ "MuiBackdrop-open": open },
"fixed inset-0 z-[-1] bg-neutral-800/60"
)}
onClick={onClick}
>
<div ref={ref} {...other} />
</div>
)
}
)
type FrameProps<T extends React.ElementType> =
React.ComponentPropsWithoutRef<T> & {
as?: T
title: string
footer: React.ReactNode
onClose?: ModalProps["onClose"]
}
function Frame<T extends React.ElementType>(props: FrameProps<T>) {
const { as, title, footer, onClose, children, ...other } = props
let Component = as ?? "div"
return (
<Component
className="flex h-full w-full flex-col justify-center rounded-lg bg-white"
{...other}
>
<div className="relative flex-none border-b-2 p-4 text-center">
<XIcon
className="absolute left-4 top-1/2 h-6 w-6 -translate-y-1/2 cursor-pointer"
onClick={onClose}
/>
<span className="h1 font-display font-bold">{title}</span>
</div>
<div className="flex-1 overflow-scroll px-8 py-12">{children}</div>
<div className="flex-none border-t-2 p-4">{footer}</div>
</Component>
)
}
export function Modal<T extends React.ElementType = "div">(
props: ModalProps & { frame?: FrameProps<T> }
) {
const { className, children, frame, onClose, ...other } = props
return (
<BaseModal
className={clsx(
"fixed z-[100] flex items-center justify-center text-base text-black",
className
)}
slots={{ backdrop: Backdrop }}
onClose={onClose}
{...other}
>
<div className="fixed inset-0 mt-8 md:inset-x-[18%] md:inset-y-16 md:mt-0">
<FadeIn
className="relative h-full w-full"
transition={{ duration: 0.2 }}
>
{frame ? (
<Frame {...frame} onClose={onClose}>
{children}
</Frame>
) : (
children
)}
</FadeIn>
</div>
</BaseModal>
)
}
Modal.displayName = "Modal"

View File

@ -0,0 +1,101 @@
import * as React from "react"
import clsx from "clsx"
import {
Slider as BaseSlider,
SliderProps as BaseSliderProps,
SliderOwnerState,
} from "@mui/base/Slider"
import { resolveSlotProps } from "../utils/props"
export type SliderProps = BaseSliderProps
export const Slider = React.forwardRef<HTMLInputElement, SliderProps>(
function Slider(
props: SliderProps,
ref: React.ForwardedRef<HTMLInputElement>
) {
const rootSlotProps = (ownerState: SliderOwnerState) => {
const resolved = resolveSlotProps(props.slotProps?.root, ownerState)
return {
...resolved,
className: clsx("hover:opacity-100", resolved?.className),
}
}
const railSlotProps = (ownerState: SliderOwnerState) => {
const resolved = resolveSlotProps(props.slotProps?.rail, ownerState)
return {
...resolved,
className: clsx(
"block absolute w-full h-1 rounded-sm bg-slate-300",
resolved?.className
),
}
}
const trackSlotProps = (ownerState: SliderOwnerState) => {
const resolved = resolveSlotProps(props.slotProps?.track, ownerState)
return {
...resolved,
className: clsx(
"block absolute w-full h-1 rounded-sm bg-current",
resolved?.className
),
}
}
const thumbSlotProps = (ownerState: SliderOwnerState) => {
const resolved = resolveSlotProps(props.slotProps?.thumb, ownerState)
return {
...resolved,
className: clsx(
"absolute w-6 h-6 -ml-2 -mt-2.5 box-border rounded-full bg-current hover:shadow hover:shadow-slate-300",
resolved?.className
),
}
}
const markSlotProps = (ownerState: SliderOwnerState) => {
const resolved = resolveSlotProps(props.slotProps?.mark, ownerState)
return {
...resolved,
className: clsx(
"absolute w-1 h-1 opacity-70 bg-current rounded-sm -translate-x-2/4 top-1/2",
resolved?.className
),
}
}
const markLabelSlotProps = (ownerState: SliderOwnerState) => {
const resolved = resolveSlotProps(props.slotProps?.markLabel, ownerState)
return {
...resolved,
className: clsx(
"absolute text-sm top-5 -translate-x-1/2",
resolved?.className
),
}
}
return (
<BaseSlider
ref={ref}
{...props}
className={clsx(
"relative inline-block h-1.5 w-full cursor-pointer touch-none",
props.className
)}
slotProps={{
...props.slotProps,
root: rootSlotProps,
rail: railSlotProps,
track: trackSlotProps,
thumb: thumbSlotProps,
mark: markSlotProps,
markLabel: markLabelSlotProps,
}}
/>
)
}
)

View File

@ -3,14 +3,15 @@ import axios from "axios"
import { useQuery } from "@tanstack/react-query"
import type { Coach } from "../types/Coach"
import { type SearchParams, defaultSearchParams } from "../types/SearchParams"
import { Container } from "../components/Container"
import { FadeIn, FadeInStagger } from "../components/FadeIn"
import { FallbackMessage } from "../components/FallbackMessage"
import { FilterModal } from "../components/FilterModal"
import { FilterScroll } from "../components/FilterScroll"
import { Loading } from "../components/Loading"
import { SearchResult } from "../components/SearchResult"
import { defaultSearchParams } from "../types/SearchParams"
function SearchResults() {
const { isLoading, isError, data } = useQuery({
@ -54,13 +55,23 @@ function SearchResults() {
export function Search() {
const [searchParams, setSearchParams] = React.useState(defaultSearchParams)
const [modalOpen, setModalOpen] = React.useState(false)
return (
<Container className="pt-8">
<FilterScroll
params={searchParams}
onSelect={setSearchParams}
onModal={() => {}}
onModal={() => setModalOpen(true)}
/>
<FilterModal
open={modalOpen}
defaultValues={searchParams}
onClose={() => setModalOpen(false)}
onSubmit={(q) => {
setSearchParams(q)
setModalOpen(false)
}}
/>
<SearchResults />
</Container>

View File

@ -2,8 +2,8 @@ export type SearchParams = {
fideRating: [number, number]
}
const FIDE_RATING_MIN = 1500
const FIDE_RATING_MAX = 3200
export const FIDE_RATING_MIN = 1500
export const FIDE_RATING_MAX = 3200
export const defaultSearchParams: SearchParams = {
fideRating: [FIDE_RATING_MIN, FIDE_RATING_MAX],

View File

@ -0,0 +1,11 @@
// Used when overriding slot props. `SlotComponentProps` (the generic type being
// overridden) is one of the following:
//
// 1. `Partial<React.ComponentPropsWithRef<TSlotComponent>> & TOverrides`
// 2. `(ownerState: TOwnerState) =>
// Partial<React.ComponentPropsWithRef<TSlotComponent>> & TOverrides`
//
// Refer to `mui/base/utils/types.d.ts`. The following checks which of the two
// we're working with and returns the `Partial` type.
export const resolveSlotProps = (fn: any, args: any) =>
typeof fn === "function" ? fn(args) : fn

View File

@ -4,6 +4,15 @@
let
sources = {
"@babel/runtime-7.23.5" = {
name = "_at_babel_slash_runtime";
packageName = "@babel/runtime";
version = "7.23.5";
src = fetchurl {
url = "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz";
sha512 = "NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==";
};
};
"@emotion/is-prop-valid-0.8.8" = {
name = "_at_emotion_slash_is-prop-valid";
packageName = "@emotion/is-prop-valid";
@ -22,6 +31,78 @@ let
sha512 = "Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==";
};
};
"@floating-ui/core-1.5.1" = {
name = "_at_floating-ui_slash_core";
packageName = "@floating-ui/core";
version = "1.5.1";
src = fetchurl {
url = "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.1.tgz";
sha512 = "QgcKYwzcc8vvZ4n/5uklchy8KVdjJwcOeI+HnnTNclJjs2nYsy23DOCf+sSV1kBwD9yDAoVKCkv/gEPzgQU3Pw==";
};
};
"@floating-ui/dom-1.5.3" = {
name = "_at_floating-ui_slash_dom";
packageName = "@floating-ui/dom";
version = "1.5.3";
src = fetchurl {
url = "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz";
sha512 = "ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==";
};
};
"@floating-ui/react-dom-2.0.4" = {
name = "_at_floating-ui_slash_react-dom";
packageName = "@floating-ui/react-dom";
version = "2.0.4";
src = fetchurl {
url = "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz";
sha512 = "CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==";
};
};
"@floating-ui/utils-0.1.6" = {
name = "_at_floating-ui_slash_utils";
packageName = "@floating-ui/utils";
version = "0.1.6";
src = fetchurl {
url = "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz";
sha512 = "OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==";
};
};
"@mui/base-5.0.0-beta.25" = {
name = "_at_mui_slash_base";
packageName = "@mui/base";
version = "5.0.0-beta.25";
src = fetchurl {
url = "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.25.tgz";
sha512 = "Iiv+IcappRRv6IBlknIVmLkXxfp51NEX1+l9f+dIbBuPU4PaRULegr1lCeHKsC45KU5ruxM5xMg4R/de03aJQg==";
};
};
"@mui/types-7.2.10" = {
name = "_at_mui_slash_types";
packageName = "@mui/types";
version = "7.2.10";
src = fetchurl {
url = "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz";
sha512 = "wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==";
};
};
"@mui/utils-5.14.19" = {
name = "_at_mui_slash_utils";
packageName = "@mui/utils";
version = "5.14.19";
src = fetchurl {
url = "https://registry.npmjs.org/@mui/utils/-/utils-5.14.19.tgz";
sha512 = "qAHvTXzk7basbyqPvhgWqN6JbmI2wLB/mf97GkSlz5c76MiKYV6Ffjvw9BjKZQ1YRb8rDX9kgdjRezOcoB91oQ==";
};
};
"@popperjs/core-2.11.8" = {
name = "_at_popperjs_slash_core";
packageName = "@popperjs/core";
version = "2.11.8";
src = fetchurl {
url = "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz";
sha512 = "P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==";
};
};
"@remix-run/router-1.13.1" = {
name = "_at_remix-run_slash_router";
packageName = "@remix-run/router";
@ -31,6 +112,69 @@ let
sha512 = "so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q==";
};
};
"@tanstack/query-core-5.12.1" = {
name = "_at_tanstack_slash_query-core";
packageName = "@tanstack/query-core";
version = "5.12.1";
src = fetchurl {
url = "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.12.1.tgz";
sha512 = "WbZztNmKq0t6QjdNmHzezbi/uifYo9j6e2GLJkodsYaYUlzMbAp91RDyeHkIZrm7EfO4wa6Sm5sxJZm5SPlh6w==";
};
};
"@tanstack/react-query-5.12.2" = {
name = "_at_tanstack_slash_react-query";
packageName = "@tanstack/react-query";
version = "5.12.2";
src = fetchurl {
url = "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.12.2.tgz";
sha512 = "BeWZu8zVFH20oRc+S/K9ADPgWjEzP/XQCGBNz5IbApUwPQAdwkQYbXODVL5AyAlWiSxhx+P2xlARPBApj2Yrog==";
};
};
"@types/prop-types-15.7.11" = {
name = "_at_types_slash_prop-types";
packageName = "@types/prop-types";
version = "15.7.11";
src = fetchurl {
url = "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz";
sha512 = "ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==";
};
};
"@types/react-18.2.40" = {
name = "_at_types_slash_react";
packageName = "@types/react";
version = "18.2.40";
src = fetchurl {
url = "https://registry.npmjs.org/@types/react/-/react-18.2.40.tgz";
sha512 = "H+BUhb9C1zBtogDLAk+KCNRKiHDrqSwQT/0z0PVTwMFBxqg3011ByLomADtgkgMkfwj4AMOiXBReyLTUBg681g==";
};
};
"@types/scheduler-0.16.8" = {
name = "_at_types_slash_scheduler";
packageName = "@types/scheduler";
version = "0.16.8";
src = fetchurl {
url = "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz";
sha512 = "WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==";
};
};
"asynckit-0.4.0" = {
name = "asynckit";
packageName = "asynckit";
version = "0.4.0";
src = fetchurl {
url = "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz";
sha512 = "Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==";
};
};
"axios-1.6.2" = {
name = "axios";
packageName = "axios";
version = "1.6.2";
src = fetchurl {
url = "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz";
sha512 = "7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==";
};
};
"clsx-2.0.0" = {
name = "clsx";
packageName = "clsx";
@ -40,6 +184,51 @@ let
sha512 = "rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==";
};
};
"combined-stream-1.0.8" = {
name = "combined-stream";
packageName = "combined-stream";
version = "1.0.8";
src = fetchurl {
url = "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz";
sha512 = "FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==";
};
};
"csstype-3.1.2" = {
name = "csstype";
packageName = "csstype";
version = "3.1.2";
src = fetchurl {
url = "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz";
sha512 = "I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==";
};
};
"delayed-stream-1.0.0" = {
name = "delayed-stream";
packageName = "delayed-stream";
version = "1.0.0";
src = fetchurl {
url = "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz";
sha512 = "ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==";
};
};
"follow-redirects-1.15.3" = {
name = "follow-redirects";
packageName = "follow-redirects";
version = "1.15.3";
src = fetchurl {
url = "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz";
sha512 = "1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==";
};
};
"form-data-4.0.0" = {
name = "form-data";
packageName = "form-data";
version = "4.0.0";
src = fetchurl {
url = "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz";
sha512 = "ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==";
};
};
"framer-motion-10.16.12" = {
name = "framer-motion";
packageName = "framer-motion";
@ -67,6 +256,51 @@ let
sha512 = "lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==";
};
};
"mime-db-1.52.0" = {
name = "mime-db";
packageName = "mime-db";
version = "1.52.0";
src = fetchurl {
url = "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz";
sha512 = "sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==";
};
};
"mime-types-2.1.35" = {
name = "mime-types";
packageName = "mime-types";
version = "2.1.35";
src = fetchurl {
url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz";
sha512 = "ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==";
};
};
"object-assign-4.1.1" = {
name = "object-assign";
packageName = "object-assign";
version = "4.1.1";
src = fetchurl {
url = "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz";
sha512 = "rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==";
};
};
"prop-types-15.8.1" = {
name = "prop-types";
packageName = "prop-types";
version = "15.8.1";
src = fetchurl {
url = "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz";
sha512 = "oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==";
};
};
"proxy-from-env-1.1.0" = {
name = "proxy-from-env";
packageName = "proxy-from-env";
version = "1.1.0";
src = fetchurl {
url = "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz";
sha512 = "D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==";
};
};
"react-18.2.0" = {
name = "react";
packageName = "react";
@ -85,6 +319,33 @@ let
sha512 = "6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==";
};
};
"react-hook-form-7.48.2" = {
name = "react-hook-form";
packageName = "react-hook-form";
version = "7.48.2";
src = fetchurl {
url = "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.48.2.tgz";
sha512 = "H0T2InFQb1hX7qKtDIZmvpU1Xfn/bdahWBN1fH19gSe4bBEqTfmlr7H3XWTaVtiK4/tpPaI1F3355GPMZYge+A==";
};
};
"react-is-16.13.1" = {
name = "react-is";
packageName = "react-is";
version = "16.13.1";
src = fetchurl {
url = "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz";
sha512 = "24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==";
};
};
"react-is-18.2.0" = {
name = "react-is";
packageName = "react-is";
version = "18.2.0";
src = fetchurl {
url = "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz";
sha512 = "xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==";
};
};
"react-router-6.20.1" = {
name = "react-router";
packageName = "react-router";
@ -103,6 +364,15 @@ let
sha512 = "npzfPWcxfQN35psS7rJgi/EW0Gx6EsNjfdJSAk73U/HqMEJZ2k/8puxfwHFgDQhBGmS3+sjnGbMdMSV45axPQw==";
};
};
"regenerator-runtime-0.14.0" = {
name = "regenerator-runtime";
packageName = "regenerator-runtime";
version = "0.14.0";
src = fetchurl {
url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz";
sha512 = "srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==";
};
};
"scheduler-0.23.0" = {
name = "scheduler";
packageName = "scheduler";
@ -128,17 +398,50 @@ let
version = "0.1.0";
src = ./.;
dependencies = [
sources."@babel/runtime-7.23.5"
sources."@emotion/is-prop-valid-0.8.8"
sources."@emotion/memoize-0.7.4"
sources."@floating-ui/core-1.5.1"
sources."@floating-ui/dom-1.5.3"
sources."@floating-ui/react-dom-2.0.4"
sources."@floating-ui/utils-0.1.6"
sources."@mui/base-5.0.0-beta.25"
sources."@mui/types-7.2.10"
sources."@mui/utils-5.14.19"
sources."@popperjs/core-2.11.8"
sources."@remix-run/router-1.13.1"
sources."@tanstack/query-core-5.12.1"
sources."@tanstack/react-query-5.12.2"
sources."@types/prop-types-15.7.11"
sources."@types/react-18.2.40"
sources."@types/scheduler-0.16.8"
sources."asynckit-0.4.0"
sources."axios-1.6.2"
sources."clsx-2.0.0"
sources."combined-stream-1.0.8"
sources."csstype-3.1.2"
sources."delayed-stream-1.0.0"
sources."follow-redirects-1.15.3"
sources."form-data-4.0.0"
sources."framer-motion-10.16.12"
sources."js-tokens-4.0.0"
sources."loose-envify-1.4.0"
sources."mime-db-1.52.0"
sources."mime-types-2.1.35"
sources."object-assign-4.1.1"
(sources."prop-types-15.8.1" // {
dependencies = [
sources."react-is-16.13.1"
];
})
sources."proxy-from-env-1.1.0"
sources."react-18.2.0"
sources."react-dom-18.2.0"
sources."react-hook-form-7.48.2"
sources."react-is-18.2.0"
sources."react-router-6.20.1"
sources."react-router-dom-6.20.1"
sources."regenerator-runtime-0.14.0"
sources."scheduler-0.23.0"
sources."tslib-2.6.2"
];

View File

@ -15,6 +15,7 @@
"framer-motion": "^10.16.12",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.48.2",
"react-router-dom": "^6.20.1"
},
"devDependencies": {
@ -465,6 +466,21 @@
"react": "^18.2.0"
}
},
"node_modules/react-hook-form": {
"version": "7.48.2",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.48.2.tgz",
"integrity": "sha512-H0T2InFQb1hX7qKtDIZmvpU1Xfn/bdahWBN1fH19gSe4bBEqTfmlr7H3XWTaVtiK4/tpPaI1F3355GPMZYge+A==",
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/react-hook-form"
},
"peerDependencies": {
"react": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
@ -818,6 +834,12 @@
"scheduler": "^0.23.0"
}
},
"react-hook-form": {
"version": "7.48.2",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.48.2.tgz",
"integrity": "sha512-H0T2InFQb1hX7qKtDIZmvpU1Xfn/bdahWBN1fH19gSe4bBEqTfmlr7H3XWTaVtiK4/tpPaI1F3355GPMZYge+A==",
"requires": {}
},
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",

View File

@ -9,6 +9,7 @@
"framer-motion": "^10.16.12",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.48.2",
"react-router-dom": "^6.20.1"
},
"devDependencies": {

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "website",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}