feat: add Switch component for premium content toggle in CreateContentsPage
This commit is contained in:
parent
8f8fb6b97c
commit
d4d9861727
@ -26,7 +26,7 @@ type TComboboxOption = {
|
||||
id: string
|
||||
}
|
||||
|
||||
type TInputProperties<T extends FieldValues> = ComponentProps<
|
||||
type TComboboxProperties<T extends FieldValues> = ComponentProps<
|
||||
typeof HeadlessCombobox
|
||||
> & {
|
||||
id: string
|
||||
@ -40,7 +40,7 @@ type TInputProperties<T extends FieldValues> = ComponentProps<
|
||||
}
|
||||
|
||||
export const Combobox = <TFormValues extends Record<string, unknown>>(
|
||||
properties: TInputProperties<TFormValues>,
|
||||
properties: TComboboxProperties<TFormValues>,
|
||||
) => {
|
||||
const {
|
||||
id,
|
||||
|
||||
80
app/components/ui/switch.tsx
Normal file
80
app/components/ui/switch.tsx
Normal file
@ -0,0 +1,80 @@
|
||||
import { Field, Label, Switch as HeadlessSwitch } from '@headlessui/react'
|
||||
import { type ReactNode } from 'react'
|
||||
import {
|
||||
Controller,
|
||||
get,
|
||||
type FieldError,
|
||||
type FieldValues,
|
||||
type Path,
|
||||
type RegisterOptions,
|
||||
} from 'react-hook-form'
|
||||
import { useRemixFormContext } from 'remix-hook-form'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
type TSwitchProperties<T extends FieldValues> = {
|
||||
id: string
|
||||
label?: ReactNode
|
||||
name: Path<T>
|
||||
rules?: RegisterOptions
|
||||
containerClassName?: string
|
||||
labelClassName?: string
|
||||
className?: string
|
||||
inputClassName?: string
|
||||
}
|
||||
|
||||
export const Switch = <TFormValues extends Record<string, unknown>>(
|
||||
properties: TSwitchProperties<TFormValues>,
|
||||
) => {
|
||||
const {
|
||||
id,
|
||||
label,
|
||||
name,
|
||||
rules,
|
||||
containerClassName,
|
||||
labelClassName,
|
||||
className,
|
||||
inputClassName,
|
||||
} = properties
|
||||
|
||||
const {
|
||||
control,
|
||||
formState: { errors },
|
||||
} = useRemixFormContext()
|
||||
|
||||
const error: FieldError = get(errors, name)
|
||||
|
||||
return (
|
||||
<Field
|
||||
className={twMerge('relative', containerClassName)}
|
||||
id={id}
|
||||
>
|
||||
<Label className={twMerge('mb-1 block text-gray-700', labelClassName)}>
|
||||
{label} {error && <span className="text-red-500">{error.message}</span>}
|
||||
</Label>
|
||||
<Controller
|
||||
name={name}
|
||||
control={control}
|
||||
rules={rules}
|
||||
render={({ field }) => (
|
||||
<div className={twMerge('flex items-center', inputClassName)}>
|
||||
<HeadlessSwitch
|
||||
checked={field.value}
|
||||
onChange={(checked) => {
|
||||
field.onChange(checked)
|
||||
}}
|
||||
className={twMerge(
|
||||
'group relative flex h-7 w-14 cursor-pointer rounded-full bg-black/10 p-1 shadow transition-colors duration-200 ease-in-out focus:outline-none data-[checked]:bg-black/10 data-[focus]:outline-1 data-[focus]:outline-white',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none inline-block size-5 translate-x-0 rounded-full bg-white ring-0 shadow-lg transition duration-200 ease-in-out group-data-[checked]:translate-x-7"
|
||||
/>
|
||||
</HeadlessSwitch>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</Field>
|
||||
)
|
||||
}
|
||||
@ -9,6 +9,7 @@ import { TextEditor } from '~/components/text-editor'
|
||||
import { Button } from '~/components/ui/button'
|
||||
import { Combobox } from '~/components/ui/combobox'
|
||||
import { Input } from '~/components/ui/input'
|
||||
import { Switch } from '~/components/ui/switch'
|
||||
import { TitleDashboard } from '~/components/ui/title-dashboard'
|
||||
import type { loader } from '~/routes/_admin.lg-admin'
|
||||
|
||||
@ -67,6 +68,15 @@ export const CreateContentsPage = () => {
|
||||
mode: 'onSubmit',
|
||||
fetcher,
|
||||
resolver: zodResolver(contentSchema),
|
||||
defaultValues: {
|
||||
categories: [],
|
||||
tags: [],
|
||||
title: '',
|
||||
content: '',
|
||||
featured_image: '',
|
||||
is_premium: false,
|
||||
live_at: '',
|
||||
},
|
||||
})
|
||||
|
||||
const { handleSubmit, control, watch } = formMethods
|
||||
@ -167,6 +177,13 @@ export const CreateContentsPage = () => {
|
||||
className="border-0 bg-white shadow focus:ring-1 focus:ring-[#2E2F7C] focus:outline-none"
|
||||
labelClassName="text-sm font-medium text-[#363636]"
|
||||
/>
|
||||
<Switch
|
||||
id="is_premium"
|
||||
name="is_premium"
|
||||
label="Premium"
|
||||
labelClassName="text-sm font-medium text-[#363636]"
|
||||
inputClassName="h-[42px]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TextEditor
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user