Unverified Commit d720c667 authored by Wellton Quirino's avatar Wellton Quirino Committed by GitHub

Merge pull request #2 from Iapdigital/dev

Dev for main
parents 439614d7 764f9b62
This diff is collapsed.
...@@ -6,31 +6,36 @@ ...@@ -6,31 +6,36 @@
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "eslint . --fix"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.0", "@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0", "@emotion/styled": "^11.13.0",
"@hookform/resolvers": "^3.9.0",
"@mui/material": "^5.16.4", "@mui/material": "^5.16.4",
"@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-label": "^2.1.0", "@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-select": "^2.1.1", "@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.1.0",
"axios": "^1.7.2", "axios": "^1.7.2",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^3.6.0",
"embla-carousel-react": "^8.1.5", "embla-carousel-react": "^8.1.5",
"lucide-react": "^0.383.0", "lucide-react": "^0.383.0",
"next": "14.2.3", "next": "14.2.3",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"react": "^18", "react": "^18",
"react-day-picker": "^8.10.1",
"react-dom": "^18", "react-dom": "^18",
"react-hook-form": "^7.52.0", "react-hook-form": "^7.52.2",
"tailwind-merge": "^2.3.0", "tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7",
"zod": "^3.23.8"
}, },
"devDependencies": { "devDependencies": {
"@rocketseat/eslint-config": "^2.2.2", "@rocketseat/eslint-config": "^2.2.2",
......
import { StyledInputs } from '@/components/mui/styled-inputs'
import { Button } from '@/components/ui/button'
import { TextField } from '@mui/material'
import { Trash } from 'lucide-react'
export default function AreaId() {
return (
<section className="container py-10">
<div className="flex items-center gap-6">
<h1 className="text-green-700 text-3xl font-bold">Editar Área</h1>
<Button variant="third" className="uppercase">
Salvar como rascunho
</Button>
<Button variant="secondary" className="uppercase">
Salvar e publicar
</Button>
<Button
variant="ghost"
className="uppercase flex items-center gap-2 text-orange-100 hover:text-orange-100"
>
<span>Apagar área</span>
<Trash />
</Button>
</div>
<div className="w-full">
<TextField
label="Nome da área"
variant="standard"
type="text"
className="flex"
sx={StyledInputs({ color: '#26AAA7' })}
/>
<div className="flex justify-between flex-wrap gap-6">
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Desktop</h6>
<span className="mt-4">Dimensões recomendadas: </span>
<span>Formatos aceitos: .png, .jpg</span>
<Button
variant="third"
className="border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
>
Adicionar banner
</Button>
</div>
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Mobile</h6>
<span className="mt-4">Dimensões recomendadas: </span>
<span>Formatos aceitos: .png, .jpg</span>
<Button
variant="third"
className="border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
>
Adicionar banner
</Button>
</div>
</div>
</div>
</section>
)
}
import { StyledInputs } from '@/components/mui/styled-inputs'
import { Button } from '@/components/ui/button'
import { TextField } from '@mui/material'
import { Trash } from 'lucide-react'
export default function Area() {
return (
<section className="container py-10">
<div className="flex items-center gap-6">
<h1 className="text-green-700 text-3xl font-bold">Criar Área</h1>
<Button variant="third" className="uppercase">
Salvar como rascunho
</Button>
<Button variant="secondary" className="uppercase">
Salvar e publicar
</Button>
<Button
variant="ghost"
className="uppercase flex items-center gap-2 text-orange-100 hover:text-orange-100"
>
<span>Apagar área</span>
<Trash />
</Button>
</div>
<div className="w-full">
<TextField
label="Nome da área"
variant="standard"
type="text"
className="flex"
sx={StyledInputs({ color: '#26AAA7' })}
/>
<div className="flex justify-between flex-wrap gap-6">
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Desktop</h6>
<span className="mt-4">Dimensões recomendadas: </span>
<span>Formatos aceitos: .png, .jpg</span>
<Button
variant="third"
className="border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
>
Adicionar banner
</Button>
</div>
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Mobile</h6>
<span className="mt-4">Dimensões recomendadas: </span>
<span>Formatos aceitos: .png, .jpg</span>
<Button
variant="third"
className="border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
>
Adicionar banner
</Button>
</div>
</div>
</div>
</section>
)
}
This diff is collapsed.
This diff is collapsed.
...@@ -7,21 +7,27 @@ import Link from 'next/link' ...@@ -7,21 +7,27 @@ import Link from 'next/link'
const areas = [ const areas = [
{ {
id: '1',
title: 'Educação', title: 'Educação',
}, },
{ {
id: '2',
title: 'Negócios', title: 'Negócios',
}, },
{ {
id: '3',
title: 'Comunicação', title: 'Comunicação',
}, },
{ {
id: '4',
title: 'Saúde', title: 'Saúde',
}, },
{ {
id: '5',
title: 'Tecnologia', title: 'Tecnologia',
}, },
{ {
id: '6',
title: 'Teologia', title: 'Teologia',
}, },
] ]
...@@ -42,13 +48,17 @@ export default function Admin() { ...@@ -42,13 +48,17 @@ export default function Admin() {
<div className="flex h-auto mb-20"> <div className="flex h-auto mb-20">
<aside className="mt-10 w-[348px]"> <aside className="mt-10 w-[348px]">
<h2 className="text-purple-50 text-2xl">Áreas</h2> <h2 className="text-purple-50 text-2xl">Áreas</h2>
<Button className="uppercase mt-6">+ Adicionar novo</Button>
<Button className="uppercase mt-6" asChild>
<Link href="admin/area">+ Adicionar novo</Link>
</Button>
<nav className="my-6"> <nav className="my-6">
<ul className="space-y-4"> <ul className="space-y-4">
{areas.map((area) => ( {areas.map((area) => (
<li key={area.title} className="border-b border-green-400"> <li key={area.title} className="border-b border-green-400">
<Link <Link
href="#" href={`/admin/area/${area.id}`}
className="flex justify-between py-2 hover:bg-green-400/10" className="flex justify-between py-2 hover:bg-green-400/10"
> >
<span>{area.title}</span> <span>{area.title}</span>
...@@ -77,14 +87,20 @@ export default function Admin() { ...@@ -77,14 +87,20 @@ export default function Admin() {
<div className="flex-1 ml-4 pl-6 border-l border-gray-50"> <div className="flex-1 ml-4 pl-6 border-l border-gray-50">
<h2 className="text-purple-50 text-2xl">Cursos</h2> <h2 className="text-purple-50 text-2xl">Cursos</h2>
<Button className="uppercase mt-6">+ Adicionar novo</Button> <Button className="uppercase mt-6" asChild>
<Link href="admin/curso">+ Adicionar novo</Link>
</Button>
<div className="flex items-center flex-1 my-6"> <div className="flex items-center flex-1 my-6">
<Input className="pr-8" placeholder="Pesquisar" /> <Input className="pr-8" placeholder="Pesquisar" />
<Search size={24} className="-ml-6" /> <Search size={24} className="-ml-6" />
</div> </div>
<div className="flex flex-wrap justify-around gap-4"> <div className="flex flex-wrap justify-around gap-4">
{CoursesCard.map((course) => ( {CoursesCard.map((course) => (
<Link key={course.id} className="lowercase" href="#"> <Link
key={course.id}
className="lowercase"
href={`admin/curso/${course.id}`}
>
<div className={`bg-gray-100 pb-4 rounded-lg max-w-[163px]`}> <div className={`bg-gray-100 pb-4 rounded-lg max-w-[163px]`}>
<Card.Image image={course.image.src} width="240" height="320"> <Card.Image image={course.image.src} width="240" height="320">
<Card.Title title={course.title} /> <Card.Title title={course.title} />
......
...@@ -18,7 +18,7 @@ export default function Companies() { ...@@ -18,7 +18,7 @@ export default function Companies() {
<div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6"> <div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6">
{CoursesCard.map((course) => ( {CoursesCard.map((course) => (
<div className="flex justify-center" key={course.id}> <div className="flex justify-center" key={course.id}>
<Card.Root link={`${course.category}/${course.id}`}> <Card.Root link={`curso/${course.id}`}>
<Card.Image image={course.image.src} width="273" height="365"> <Card.Image image={course.image.src} width="273" height="365">
<Card.Title title={course.title} /> <Card.Title title={course.title} />
</Card.Image> </Card.Image>
......
...@@ -15,10 +15,10 @@ export default function Students() { ...@@ -15,10 +15,10 @@ export default function Students() {
<BannerCategory title="Estudante" /> <BannerCategory title="Estudante" />
<NavLinkCategory /> <NavLinkCategory />
<SearchFilter /> <SearchFilter />
<div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6"> <div className="grid rounded-none grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6">
{CoursesCard.map((course) => ( {CoursesCard.map((course) => (
<div className="flex justify-center" key={course.id}> <div className="flex justify-center" key={course.id}>
<Card.Root link={`${course.category}/${course.id}`}> <Card.Root link={`curso/${course.id}`}>
<Card.Image image={course.image.src} width="273" height="365"> <Card.Image image={course.image.src} width="273" height="365">
<Card.Title title={course.title} /> <Card.Title title={course.title} />
</Card.Image> </Card.Image>
......
...@@ -25,8 +25,18 @@ export default function Login() { ...@@ -25,8 +25,18 @@ export default function Login() {
> >
<div className="flex flex-col space-y-6"> <div className="flex flex-col space-y-6">
<div className="flex flex-col space-y-4"> <div className="flex flex-col space-y-4">
<InputMui label="E-mail" variant="outlined" type="email" /> <InputMui
<InputMui label="Senha" variant="outlined" type="password" /> label="E-mail"
variant="outlined"
type="email"
color="white"
/>
<InputMui
label="Senha"
variant="outlined"
type="password"
color="white"
/>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Checkbox id="remember" /> <Checkbox id="remember" />
......
...@@ -18,7 +18,7 @@ export default function Professionals() { ...@@ -18,7 +18,7 @@ export default function Professionals() {
<div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6"> <div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6">
{CoursesCard.map((course) => ( {CoursesCard.map((course) => (
<div className="flex justify-center" key={course.id}> <div className="flex justify-center" key={course.id}>
<Card.Root link={`${course.category}/${course.id}`}> <Card.Root link={`curso/${course.id}`}>
<Card.Image image={course.image.src} width="273" height="365"> <Card.Image image={course.image.src} width="273" height="365">
<Card.Title title={course.title} /> <Card.Title title={course.title} />
</Card.Image> </Card.Image>
......
...@@ -20,7 +20,7 @@ export function CarouselComponent() { ...@@ -20,7 +20,7 @@ export function CarouselComponent() {
key={course.id} key={course.id}
className="sm:basis-1/2 md:basis-1/3 lg:basis-1/4 xl:basis-1/5 flex justify-center" className="sm:basis-1/2 md:basis-1/3 lg:basis-1/4 xl:basis-1/5 flex justify-center"
> >
<Card.Root link={`curso/${course.id}`}> <Card.Root link={`${course.id}`}>
<Card.Image image={course.image.src} width="240" height="320"> <Card.Image image={course.image.src} width="240" height="320">
<Card.Title title={course.title} /> <Card.Title title={course.title} />
</Card.Image> </Card.Image>
......
...@@ -3,7 +3,12 @@ import Link from 'next/link' ...@@ -3,7 +3,12 @@ import Link from 'next/link'
import LogoComponent from './logo' import LogoComponent from './logo'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet' import {
Sheet,
SheetClose,
SheetContent,
SheetTrigger,
} from '@/components/ui/sheet'
import { NavLink } from './nav-link' import { NavLink } from './nav-link'
export function Header() { export function Header() {
...@@ -63,7 +68,9 @@ export function Header() { ...@@ -63,7 +68,9 @@ export function Header() {
variant="ghost" variant="ghost"
href="/estudantes" href="/estudantes"
> >
Para estudantes <SheetClose className="uppercase">
Para estudantes
</SheetClose>
</NavLink> </NavLink>
<NavLink <NavLink
...@@ -71,28 +78,37 @@ export function Header() { ...@@ -71,28 +78,37 @@ export function Header() {
variant="ghost" variant="ghost"
href="/profissionais" href="/profissionais"
> >
Para profissionais <SheetClose className="uppercase">
Para profissionais
</SheetClose>
</NavLink> </NavLink>
<NavLink <NavLink
className="hover:bg-gray-50/10" className="hover:bg-gray-50/10"
variant="ghost" variant="ghost"
href="/empresas" href="/empresas"
> >
Para empresas <SheetClose className="uppercase">
Para empresas
</SheetClose>
</NavLink> </NavLink>
<NavLink <NavLink
className="hover:bg-gray-50/10" className="hover:bg-gray-50/10"
variant="ghost" variant="ghost"
href="/sobre" href="/sobre"
> >
Conheça a SevenPro <SheetClose className="uppercase">
Conheça a SevenPro
</SheetClose>
</NavLink> </NavLink>
<NavLink <NavLink
className="hover:bg-gray-50/10" className="hover:bg-gray-50/10"
variant="ghost" variant="ghost"
href="/contato" href="/contato"
> >
Contato <SheetClose className="uppercase">Contato</SheetClose>
</NavLink> </NavLink>
</nav> </nav>
</SheetContent> </SheetContent>
......
...@@ -3,8 +3,8 @@ import { ComponentProps } from 'react' ...@@ -3,8 +3,8 @@ import { ComponentProps } from 'react'
function LogoComponent(props: ComponentProps<'svg'>) { function LogoComponent(props: ComponentProps<'svg'>) {
return ( return (
<svg <svg
width={1801} width={115}
height={500} height={32}
viewBox="0 0 1801 500" viewBox="0 0 1801 500"
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
......
...@@ -4,9 +4,10 @@ type InputMuiProps = { ...@@ -4,9 +4,10 @@ type InputMuiProps = {
label: string label: string
variant: 'standard' | 'filled' | 'outlined' variant: 'standard' | 'filled' | 'outlined'
type: string type: string
color: string
} }
export function InputMui({ label, variant, type }: InputMuiProps) { export function InputMui({ label, variant, type, color }: InputMuiProps) {
return ( return (
<TextField <TextField
label={label} label={label}
...@@ -15,24 +16,45 @@ export function InputMui({ label, variant, type }: InputMuiProps) { ...@@ -15,24 +16,45 @@ export function InputMui({ label, variant, type }: InputMuiProps) {
sx={{ sx={{
'& .MuiOutlinedInput-root': { '& .MuiOutlinedInput-root': {
'& fieldset': { '& fieldset': {
borderColor: 'white', // Inicialmente transparente borderColor: color, // Inicialmente transparente
}, },
'&:hover fieldset': { '&:hover fieldset': {
borderColor: 'white', // Mantém transparente ao passar o mouse borderColor: color, // Mantém transparente ao passar o mouse
}, },
'&.Mui-focused fieldset': { '&.Mui-focused fieldset': {
borderColor: 'white', // Mantém transparente ao focar borderColor: color, // Mantém transparente ao focar
}, },
}, },
'& label.Mui-focused': { '& label.Mui-focused': {
color: '#B7B7B7', color,
}, },
'& label': { '& label': {
color: 'white', color,
}, },
'& input': { '& input': {
color,
},
'& .MuiInputBase-input': {
color: 'white', color: 'white',
}, },
'& .MuiInput-underline:before': {
borderBottomColor: color,
},
'& .MuiInput-underline:hover:before': {
borderBottomColor: `${color} !important`,
},
'& .MuiInput-underline:after': {
borderBottomColor: color,
},
'& .MuiFilledInput-underline:before': {
borderBottomColor: color,
},
'& .MuiFilledInput-underline:hover:before': {
borderBottomColor: `${color} !important`,
},
'& .MuiFilledInput-underline:after': {
borderBottomColor: color,
},
}} }}
/> />
) )
......
import { Autocomplete, TextField } from '@mui/material'
type SelectMuiProps = {
label: string
variant?: 'standard' | 'filled' | 'outlined'
color: string
}
const options = [
{ label: 'The Godfather', id: 1 },
{ label: 'Pulp Fiction', id: 2 },
]
export function SelectMui({ label, color }: SelectMuiProps) {
return (
<Autocomplete
options={options}
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: color, // Inicialmente transparente
},
'&:hover fieldset': {
borderColor: color, // Mantém transparente ao passar o mouse
},
'&.Mui-focused fieldset': {
borderColor: color, // Mantém transparente ao focar
},
},
'& label.Mui-focused': {
color,
},
'& label': {
color,
},
'& input': {
color,
},
'& .MuiInputBase-input': {
color: 'white',
},
'& .MuiInput-underline:before': {
borderBottomColor: color,
},
'& .MuiInput-underline:hover:before': {
borderBottomColor: `${color} !important`,
},
'& .MuiInput-underline:after': {
borderBottomColor: color,
},
'& .MuiFilledInput-underline:before': {
borderBottomColor: color,
},
'& .MuiFilledInput-underline:hover:before': {
borderBottomColor: `${color} !important`,
},
'& .MuiFilledInput-underline:after': {
borderBottomColor: color,
},
}}
renderInput={(params) => (
<TextField {...params} label={label} variant="standard" />
)}
/>
)
}
type StyledInputsProps = {
color: string
}
export function StyledInputs({ color }: StyledInputsProps) {
return {
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: color, // Inicialmente transparente
},
'&:hover fieldset': {
borderColor: color, // Mantém transparente ao passar o mouse
},
'&.Mui-focused fieldset': {
borderColor: color, // Mantém transparente ao focar
},
},
'& label.Mui-focused': {
color,
},
'& label': {
color,
},
'& input': {
color,
},
'& .MuiInputBase-input': {
color: 'white',
},
'& .MuiInput-underline:before': {
borderBottomColor: color,
},
'& .MuiInput-underline:hover:before': {
borderBottomColor: `${color} !important`,
},
'& .MuiInput-underline:after': {
borderBottomColor: color,
},
'& .MuiFilledInput-underline:before': {
borderBottomColor: color,
},
'& .MuiFilledInput-underline:hover:before': {
borderBottomColor: `${color} !important`,
},
'& .MuiFilledInput-underline:after': {
borderBottomColor: color,
},
}
}
...@@ -15,11 +15,12 @@ interface PaginationProps { ...@@ -15,11 +15,12 @@ interface PaginationProps {
} }
export function PaginationComponent({ export function PaginationComponent({
pageIndex, // pageIndex,
perPage, perPage,
totalCount, totalCount,
}: PaginationProps) { }: PaginationProps) {
const pages = Math.ceil(totalCount / perPage) || 1 const pages = Math.ceil(totalCount / perPage) || 1
console.log(pages)
return ( return (
<Pagination> <Pagination>
......
'use client'
import { ChevronLeft, ChevronRight } from 'lucide-react'
import * as React from 'react'
import { DayPicker } from 'react-day-picker'
import { buttonVariants } from '@/components/ui/button'
import { cn } from '@/lib/utils'
export type CalendarProps = React.ComponentProps<typeof DayPicker>
function Calendar({
className,
classNames,
showOutsideDays = true,
...props
}: CalendarProps) {
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn('p-3', className)}
classNames={{
months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
month: 'space-y-4',
caption: 'flex justify-center pt-1 relative items-center',
caption_label: 'text-sm font-medium',
nav: 'space-x-1 flex items-center',
nav_button: cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
),
nav_button_previous: 'absolute left-1',
nav_button_next: 'absolute right-1',
table: 'w-full border-collapse space-y-1',
head_row: 'flex',
head_cell:
'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
row: 'flex w-full mt-2',
cell: 'h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
day: cn(
buttonVariants({ variant: 'ghost' }),
'h-9 w-9 p-0 font-normal aria-selected:opacity-100',
),
day_range_end: 'day-range-end',
day_selected:
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
day_today: 'bg-accent text-accent-foreground',
day_outside:
'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
day_disabled: 'text-muted-foreground opacity-50',
day_range_middle:
'aria-selected:bg-accent aria-selected:text-accent-foreground',
day_hidden: 'invisible',
...classNames,
}}
components={{
IconLeft: () => <ChevronLeft className="h-4 w-4" />,
IconRight: () => <ChevronRight className="h-4 w-4" />,
}}
{...props}
/>
)
}
Calendar.displayName = 'Calendar'
export { Calendar }
"use client" 'use client'
import * as React from "react" import * as React from 'react'
import * as CheckboxPrimitive from "@radix-ui/react-checkbox" import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
import { Check } from "lucide-react" import { Check } from 'lucide-react'
import { cn } from "@/lib/utils" import { cn } from '@/lib/utils'
const Checkbox = React.forwardRef< const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>, React.ElementRef<typeof CheckboxPrimitive.Root>,
...@@ -13,13 +13,13 @@ const Checkbox = React.forwardRef< ...@@ -13,13 +13,13 @@ const Checkbox = React.forwardRef<
<CheckboxPrimitive.Root <CheckboxPrimitive.Root
ref={ref} ref={ref}
className={cn( className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground", 'peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
className className,
)} )}
{...props} {...props}
> >
<CheckboxPrimitive.Indicator <CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")} className={cn('flex items-center justify-center text-current')}
> >
<Check className="h-4 w-4" /> <Check className="h-4 w-4" />
</CheckboxPrimitive.Indicator> </CheckboxPrimitive.Indicator>
......
'use client'
import * as React from 'react'
import * as LabelPrimitive from '@radix-ui/react-label'
import { Slot } from '@radix-ui/react-slot'
import {
Controller,
ControllerProps,
FieldPath,
FieldValues,
FormProvider,
useFormContext,
} from 'react-hook-form'
import { cn } from '@/lib/utils'
import { Label } from '@/components/ui/label'
const Form = FormProvider
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = {
name: TName
}
const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue,
)
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>({
...props
}: ControllerProps<TFieldValues, TName>) => {
return (
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
</FormFieldContext.Provider>
)
}
const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext)
const itemContext = React.useContext(FormItemContext)
const { getFieldState, formState } = useFormContext()
const fieldState = getFieldState(fieldContext.name, formState)
if (!fieldContext) {
throw new Error('useFormField should be used within <FormField>')
}
const { id } = itemContext
return {
id,
name: fieldContext.name,
formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
}
}
type FormItemContextValue = {
id: string
}
const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue,
)
const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const id = React.useId()
return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn('space-y-2', className)} {...props} />
</FormItemContext.Provider>
)
})
FormItem.displayName = 'FormItem'
const FormLabel = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
const { error, formItemId } = useFormField()
return (
<Label
ref={ref}
className={cn(error && 'text-destructive', className)}
htmlFor={formItemId}
{...props}
/>
)
})
FormLabel.displayName = 'FormLabel'
const FormControl = React.forwardRef<
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
return (
<Slot
ref={ref}
id={formItemId}
aria-describedby={
!error
? `${formDescriptionId}`
: `${formDescriptionId} ${formMessageId}`
}
aria-invalid={!!error}
{...props}
/>
)
})
FormControl.displayName = 'FormControl'
const FormDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField()
return (
<p
ref={ref}
id={formDescriptionId}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
)
})
FormDescription.displayName = 'FormDescription'
const FormMessage = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField()
const body = error ? String(error?.message) : children
if (!body) {
return null
}
return (
<p
ref={ref}
id={formMessageId}
className={cn('text-sm font-medium text-destructive', className)}
{...props}
>
{body}
</p>
)
})
FormMessage.displayName = 'FormMessage'
export {
useFormField,
Form,
FormItem,
FormLabel,
FormControl,
FormDescription,
FormMessage,
FormField,
}
'use client'
import * as React from 'react'
import * as PopoverPrimitive from '@radix-ui/react-popover'
import { cn } from '@/lib/utils'
const Popover = PopoverPrimitive.Root
const PopoverTrigger = PopoverPrimitive.Trigger
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className,
)}
{...props}
/>
</PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName
export { Popover, PopoverTrigger, PopoverContent }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment