From 0ebef3657f86d19f1b43c7181be9d4ab4251f5ef Mon Sep 17 00:00:00 2001 From: andres Date: Thu, 15 Aug 2024 14:05:51 +0200 Subject: [PATCH] refactor ui --- .idea/git_toolbox_blame.xml | 6 + bun.lockb | Bin 181474 -> 195232 bytes components.json | 17 ++ package.json | 8 +- src/components/auth-redirect/index.tsx | 2 +- src/components/button/index.tsx | 26 --- src/components/fullscreen-loader/index.tsx | 2 +- src/components/index.ts | 6 +- src/components/input/index.tsx | 15 -- src/components/mode-toggle.tsx | 40 ++++ src/components/theme-provider.tsx | 9 + src/components/todolist/index.tsx | 166 ++++++++------- src/components/ui/button.tsx | 56 +++++ src/components/ui/card.tsx | 79 +++++++ src/components/ui/checkbox.tsx | 28 +++ src/components/ui/dropdown-menu.tsx | 198 ++++++++++++++++++ src/components/ui/input/index.tsx | 35 ++++ src/components/ui/label.tsx | 24 +++ src/components/{ => ui}/loader/index.tsx | 0 src/components/ui/skeleton.tsx | 15 ++ .../{toggle-group => ui}/toggle-group.tsx | 30 +-- src/components/ui/toggle.tsx | 43 ++++ src/lib/utils.ts | 6 + src/pages/_app.tsx | 35 +++- src/pages/_document.tsx | 13 ++ src/pages/index.tsx | 49 ++--- src/pages/login.tsx | 31 +-- .../todolist-api/todolists/todolists.api.ts | 9 +- .../todolist-api/todolists/todolists.hooks.ts | 5 +- src/styles/globals.css | 106 ++++++---- tailwind.config.cjs | 8 - tailwind.config.ts | 80 +++++++ 32 files changed, 899 insertions(+), 248 deletions(-) create mode 100644 .idea/git_toolbox_blame.xml create mode 100644 components.json delete mode 100644 src/components/button/index.tsx delete mode 100644 src/components/input/index.tsx create mode 100644 src/components/mode-toggle.tsx create mode 100644 src/components/theme-provider.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/checkbox.tsx create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/components/ui/input/index.tsx create mode 100644 src/components/ui/label.tsx rename src/components/{ => ui}/loader/index.tsx (100%) create mode 100644 src/components/ui/skeleton.tsx rename src/components/{toggle-group => ui}/toggle-group.tsx (66%) create mode 100644 src/components/ui/toggle.tsx create mode 100644 src/lib/utils.ts create mode 100644 src/pages/_document.tsx delete mode 100644 tailwind.config.cjs create mode 100644 tailwind.config.ts diff --git a/.idea/git_toolbox_blame.xml b/.idea/git_toolbox_blame.xml new file mode 100644 index 0000000..7dc1249 --- /dev/null +++ b/.idea/git_toolbox_blame.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 4e90f882492175dc4aae4bc4f9fae33b32e29232..c506578370d241e0769eee9a13ce6042f0504ce2 100755 GIT binary patch delta 44477 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 Ddb6v- delta 36797 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 bRh?aWl`W;F=o|f2_h)s#Eh($?R!RQ{QjGd! diff --git a/components.json b/components.json new file mode 100644 index 0000000..af7b002 --- /dev/null +++ b/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/styles/globals.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} \ No newline at end of file diff --git a/package.json b/package.json index 82ecf05..a22da4e 100644 --- a/package.json +++ b/package.json @@ -10,17 +10,21 @@ "format": "prettier --write ." }, "dependencies": { + "@radix-ui/react-dropdown-menu": "^2.1.1", + "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-toggle-group": "^1.0.4", "@tanstack/react-query": "^4.28.0", "async-mutex": "^0.5.0", "axios": "^1.3.4", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", - "lucide-react": "^0.377.0", + "lucide-react": "^0.427.0", "next": "13.2.4", + "next-themes": "^0.3.0", "react": "18.2.0", "react-dom": "18.2.0", - "tailwind-merge": "^2.3.0", + "tailwind-merge": "^2.5.0", + "tailwindcss-animate": "^1.0.7", "zod": "^3.21.4" }, "devDependencies": { diff --git a/src/components/auth-redirect/index.tsx b/src/components/auth-redirect/index.tsx index dd5f54a..280cb02 100644 --- a/src/components/auth-redirect/index.tsx +++ b/src/components/auth-redirect/index.tsx @@ -3,7 +3,7 @@ import { useEffect } from "react" import { useRouter } from "next/router" -import { Loader } from "../loader" +import { Loader } from "../ui/loader" import { useMeQuery } from "@/services" diff --git a/src/components/button/index.tsx b/src/components/button/index.tsx deleted file mode 100644 index 6088487..0000000 --- a/src/components/button/index.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type { ComponentPropsWithoutRef, FC } from "react" - -import { cn } from "@/helpers" - -type Props = ComponentPropsWithoutRef<"button"> & { - variant?: "primary" | "outlined" | "icon" -} - -export const Button: FC = ({ - className, - variant = "primary", - ...rest -}) => { - return ( - + + + setTheme("light")}> + Light + + setTheme("dark")}> + Dark + + setTheme("system")}> + System + + + + ) +} diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx new file mode 100644 index 0000000..30d1451 --- /dev/null +++ b/src/components/theme-provider.tsx @@ -0,0 +1,9 @@ +"use client" + +import { ThemeProvider as NextThemesProvider } from "next-themes" +import type { ThemeProviderProps } from "next-themes/dist/types" +import * as React from "react" + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return {children} +} diff --git a/src/components/todolist/index.tsx b/src/components/todolist/index.tsx index 5bf07bd..b90d1cf 100644 --- a/src/components/todolist/index.tsx +++ b/src/components/todolist/index.tsx @@ -1,19 +1,31 @@ -import type { ChangeEvent, FC, FormEvent } from "react" +import { + type ChangeEvent, + type FC, + type FormEvent, + useCallback, + useMemo, +} from "react" import { memo, useState } from "react" +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card" import { Plus, Trash } from "lucide-react" - import type { Task, Todolist as TodolistType, } from "../../services/todolist-api/todolists" -import { Button } from "../button" -import { Input } from "../input" +import { Button } from "../ui/button" +import { Input } from "../ui/input" -import { - ToggleGroup, - ToggleGroupItem, -} from "@/components/toggle-group/toggle-group" +import { Checkbox } from "@/components/ui/checkbox" +import { Skeleton } from "@/components/ui/skeleton" +import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group" import { TaskStatus, useCreateTaskMutation, @@ -31,33 +43,42 @@ type Filter = "all" | "active" | "completed" export const Todolist: FC = memo(({ todolist }) => { const { data: tasks, isLoading } = useGetTasksQuery(todolist.id) - const { mutate: putTask } = useUpdateTaskMutation() + const { mutate: updateTask } = useUpdateTaskMutation() const { mutate: deleteTask } = useDeleteTaskMutation() const { mutate: deleteTodolist } = useDeleteTodolistMutation() const { mutate: createTask } = useCreateTaskMutation() const [newTaskTitle, setNewTaskTitle] = useState("") const [filter, setFilter] = useState("all") - const handleChangeStatus = (todolistId: string, task: Task) => { - const newTask: Task = { - ...task, - status: - task.status === TaskStatus.DONE ? TaskStatus.OPEN : TaskStatus.DONE, - } + const handleChangeStatus = useCallback( + (todolistId: string, task: Task) => { + updateTask({ + todolistId, + id: task.id, + status: + task.status === TaskStatus.DONE ? TaskStatus.OPEN : TaskStatus.DONE, + }) + }, + [updateTask], + ) + + const handleDeleteTask = useCallback( + (todolistId: string, taskId: string) => { + deleteTask({ todolistId, taskId }) + }, + [deleteTask], + ) - putTask({ todolistId, task: newTask }) - } - const handleDeleteTask = (todolistId: string, taskId: string) => { - deleteTask({ todolistId, taskId }) - } const handleDeleteTodolist = (todolistId: string) => { deleteTodolist({ todolistId }) } + const handleAddTask = (e: FormEvent) => { e.preventDefault() createTask({ todolistId: todolist.id, title: newTaskTitle }) setNewTaskTitle("") } + const handleNewTaskTitleChange = (e: ChangeEvent) => { setNewTaskTitle(e.target.value) } @@ -66,7 +87,6 @@ export const Todolist: FC = memo(({ todolist }) => { setFilter(value as Filter) } - if (isLoading) return
loading...
const filteredTasks = tasks?.filter((task) => { switch (filter) { case "active": @@ -78,53 +98,57 @@ export const Todolist: FC = memo(({ todolist }) => { } }) + const renderTasks = useMemo(() => { + return filteredTasks?.map((task) => { + return ( +
  • + + +
  • + ) + }) + }, [filteredTasks, todolist.id, handleChangeStatus, handleDeleteTask]) + return ( -
    -
    -

    {todolist.title}

    - -
    -
    - - -
    - {filteredTasks?.map((task) => { - return ( -
    - - + + +
    + + -
    - ) - })} -
    + +
      {isLoading ? null : renderTasks}
    + +
    + = memo(({ todolist }) => { className={"w-full"} > - All + ALL - Active + TODO - Completed + DONE -
    - + + ) }) diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..1620e13 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,56 @@ +import { Slot } from "@radix-ui/react-slot" +import { type VariantProps, cva } from "class-variance-authority" +import * as React from "react" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10 shrink-0", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + }, +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..afa13ec --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,79 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

    +)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

    +)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

    +)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..ddbdd01 --- /dev/null +++ b/src/components/ui/checkbox.tsx @@ -0,0 +1,28 @@ +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { Check } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..769ff7a --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,198 @@ +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { Check, ChevronRight, Circle } from "lucide-react" + +import { cn } from "@/lib/utils" + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/src/components/ui/input/index.tsx b/src/components/ui/input/index.tsx new file mode 100644 index 0000000..96600ef --- /dev/null +++ b/src/components/ui/input/index.tsx @@ -0,0 +1,35 @@ +import { Label } from "@/components/ui/label" +import { cn } from "@/helpers" +import * as React from "react" +import { useId } from "react" + +export interface InputProps + extends React.InputHTMLAttributes { + label?: string +} + +const Input = React.forwardRef( + ({ className, type, label, id, ...props }, ref) => { + const generatedId = useId() + const idToUse = id || generatedId + + return ( +
    + {label && } + +
    + ) + }, +) +Input.displayName = "Input" + +export { Input } diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx new file mode 100644 index 0000000..683faa7 --- /dev/null +++ b/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/src/components/loader/index.tsx b/src/components/ui/loader/index.tsx similarity index 100% rename from src/components/loader/index.tsx rename to src/components/ui/loader/index.tsx diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx new file mode 100644 index 0000000..01b8b6d --- /dev/null +++ b/src/components/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "@/lib/utils" + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
    + ) +} + +export { Skeleton } diff --git a/src/components/toggle-group/toggle-group.tsx b/src/components/ui/toggle-group.tsx similarity index 66% rename from src/components/toggle-group/toggle-group.tsx rename to src/components/ui/toggle-group.tsx index 2d1acc9..8bfe044 100644 --- a/src/components/toggle-group/toggle-group.tsx +++ b/src/components/ui/toggle-group.tsx @@ -1,34 +1,10 @@ -"use client" - -import * as React from "react" - import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group" import type { VariantProps } from "class-variance-authority" -import { cva } from "class-variance-authority" +import * as React from "react" -import { cn } from "@/helpers" +import { toggleVariants } from "@/components/ui/toggle" +import { cn } from "@/lib/utils" -const toggleVariants = cva( - "inline-flex border border-sky-700 items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-sky-700 data-[state=on]:text-white", - { - variants: { - variant: { - default: "bg-transparent", - outline: - "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground", - }, - size: { - default: "h-9 px-3", - sm: "h-8 px-2", - lg: "h-10 px-3", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - }, -) const ToggleGroupContext = React.createContext< VariantProps >({ diff --git a/src/components/ui/toggle.tsx b/src/components/ui/toggle.tsx new file mode 100644 index 0000000..9ecac28 --- /dev/null +++ b/src/components/ui/toggle.tsx @@ -0,0 +1,43 @@ +import * as React from "react" +import * as TogglePrimitive from "@radix-ui/react-toggle" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const toggleVariants = cva( + "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground", + { + variants: { + variant: { + default: "bg-transparent", + outline: + "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground", + }, + size: { + default: "h-10 px-3", + sm: "h-9 px-2.5", + lg: "h-11 px-5", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +const Toggle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, size, ...props }, ref) => ( + +)) + +Toggle.displayName = TogglePrimitive.Root.displayName + +export { Toggle, toggleVariants } diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..d084cca --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 20aa50d..d1dd042 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,9 +1,12 @@ import "../styles/globals.css" -import { QueryClientProvider, QueryClient } from "@tanstack/react-query" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import type { AppType } from "next/dist/shared/lib/utils" -import { AuthRedirect } from "@/components" +import { AuthRedirect, Button } from "@/components" +import { ModeToggle } from "@/components/mode-toggle" +import { ThemeProvider } from "@/components/theme-provider" +import { useLogoutMutation } from "@/services" const queryClient = new QueryClient() @@ -11,10 +14,36 @@ const MyApp: AppType = ({ Component, pageProps }) => { return ( - + +
    + + ) } +function Header() { + const { mutate: logout } = useLogoutMutation() + const handleLogout = () => { + logout() + } + return ( +
    +

    Tasks

    +
    + + +
    +
    + ) +} + export default MyApp diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx new file mode 100644 index 0000000..ddb4eb0 --- /dev/null +++ b/src/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Head, Html, Main, NextScript } from "next/document" + +export default function Document() { + return ( + + + +
    + + + + ) +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index d1a5542..59ae411 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,25 +1,17 @@ -import type { ChangeEvent, FormEvent } from "react" +import { type ChangeEvent, type FormEvent, useMemo } from "react" import { useState } from "react" import type { NextPage } from "next" import Head from "next/head" -import { Todolist, Button, FullscreenLoader, Input } from "@/components" -import { - useCreateTodolistMutation, - useLogoutMutation, - useTodolistsQuery, -} from "@/services" +import { Button, FullscreenLoader, Input, Todolist } from "@/components" +import { useCreateTodolistMutation, useTodolistsQuery } from "@/services" +import { Plus } from "lucide-react" const Home: NextPage = () => { const [newTodolistTitle, setNewTodolistTitle] = useState("") - const { mutate: logout } = useLogoutMutation() const { data: todolists, isLoading: isTodolistsLoading } = useTodolistsQuery() - const handleLogout = () => { - logout() - } - const { mutate: createTodolist } = useCreateTodolistMutation() const handleAddTodolist = (e: FormEvent) => { @@ -32,6 +24,12 @@ const Home: NextPage = () => { setNewTodolistTitle(e.target.value) } + const renderTodolists = useMemo(() => { + return todolists?.map((todolist) => { + return + }) + }, [todolists]) + if (isTodolistsLoading) return return ( @@ -41,26 +39,19 @@ const Home: NextPage = () => { -
    -

    Todolist

    - -
    - - + +
    -
    - {todolists?.map((todolist) => { - return - })} -
    +
    {renderTodolists}
    ) diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 5f8c330..d95c73d 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -4,6 +4,7 @@ import React, { useState } from "react" import type { NextPage } from "next" import { Button, Input } from "@/components" +import { Label } from "@/components/ui/label" import { useLoginMutation } from "@/services" const Login: NextPage = () => { @@ -34,30 +35,30 @@ const Login: NextPage = () => { } return ( -
    +
    - + - + - diff --git a/src/services/todolist-api/todolists/todolists.api.ts b/src/services/todolist-api/todolists/todolists.api.ts index 2010988..613603e 100644 --- a/src/services/todolist-api/todolists/todolists.api.ts +++ b/src/services/todolist-api/todolists/todolists.api.ts @@ -26,7 +26,7 @@ export const TodolistAPI = { }, ) - return handleError(res.data) + return res.data }, async deleteTodolist({ todolistId }: { todolistId: string }) { @@ -60,8 +60,11 @@ export const TodolistAPI = { return res.data }, - async updateTask({ todolistId, task }: { todolistId: string; task: Task }) { - const { id, ...rest } = task + async updateTask({ + id, + todolistId, + ...rest + }: Partial & Required> & { todolistId: string }) { const res = await todolistApiInstance.patch( `/todolists/${todolistId}/tasks/${id}`, rest, diff --git a/src/services/todolist-api/todolists/todolists.hooks.ts b/src/services/todolist-api/todolists/todolists.hooks.ts index 91637cc..7f70fef 100644 --- a/src/services/todolist-api/todolists/todolists.hooks.ts +++ b/src/services/todolist-api/todolists/todolists.hooks.ts @@ -17,9 +17,8 @@ export const useCreateTodolistMutation = () => { return useMutation({ mutationFn: TodolistAPI.createTodolist, - //todo: add onMutate - onSuccess: async () => { - await queryClient.invalidateQueries([QUERY_KEYS.TODOLISTS]) + onSuccess: () => { + queryClient.invalidateQueries([QUERY_KEYS.TODOLISTS]) }, }) } diff --git a/src/styles/globals.css b/src/styles/globals.css index 831c996..e8e4f13 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -1,48 +1,72 @@ @tailwind base; @tailwind components; @tailwind utilities; -.loader { - width: 48px; - height: 48px; - border: 3px dotted #000; - border-style: solid solid dotted dotted; - border-radius: 50%; - display: inline-block; - position: relative; - box-sizing: border-box; - animation: rotation 2s linear infinite; -} -.loader::after { - content: ""; - box-sizing: border-box; - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - margin: auto; - border: 3px dotted #ff3d00; - border-style: solid solid dotted; - width: 24px; - height: 24px; - border-radius: 50%; - animation: rotationBack 1s linear infinite; - transform-origin: center center; + +@layer base { + #__next{ + height: 100%; + } + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } + + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } } -@keyframes rotation { - 0% { - transform: rotate(0deg); +@layer base { + * { + @apply border-border; } - 100% { - transform: rotate(360deg); + body { + @apply bg-background text-foreground; } -} -@keyframes rotationBack { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(-360deg); - } -} +} \ No newline at end of file diff --git a/tailwind.config.cjs b/tailwind.config.cjs deleted file mode 100644 index 54331dc..0000000 --- a/tailwind.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ["./src/**/*.{js,ts,jsx,tsx}"], - theme: { - extend: {}, - }, - plugins: [], -}; diff --git a/tailwind.config.ts b/tailwind.config.ts new file mode 100644 index 0000000..84287e8 --- /dev/null +++ b/tailwind.config.ts @@ -0,0 +1,80 @@ +import type { Config } from "tailwindcss" + +const config = { + darkMode: ["class"], + content: [ + './pages/**/*.{ts,tsx}', + './components/**/*.{ts,tsx}', + './app/**/*.{ts,tsx}', + './src/**/*.{ts,tsx}', + ], + prefix: "", + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +} satisfies Config + +export default config \ No newline at end of file