Migrate filter modal.
parent
99b9519ab7
commit
3cd0228906
|
@ -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>
|
||||
)
|
||||
})
|
|
@ -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>
|
||||
)
|
||||
}
|
|
@ -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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -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"
|
|
@ -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,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -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>
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
];
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "website",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
Loading…
Reference in New Issue