diff --git a/package.json b/package.json index a089d7c..e078076 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "@lukemorales/query-key-factory": "^1.3.2", "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-slot": "^1.0.2", "@tanstack/react-query": "^5.17.9", "@tanstack/react-query-devtools": "^5.17.9", "class-variance-authority": "^0.7.0", @@ -18,8 +19,10 @@ "eslint-plugin-tailwindcss": "^3.13.1", "lucide-react": "^0.312.0", "next": "14.0.4", + "next-themes": "^0.2.1", "react": "^18", "react-dom": "^18", + "sonner": "^1.3.1", "tailwind-merge": "^2.2.0", "vaul": "^0.8.0", "zustand": "^4.4.7" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1914e25..3347e4e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ dependencies: '@radix-ui/react-dialog': specifier: ^1.0.5 version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.47)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': + specifier: ^1.0.2 + version: 1.0.2(@types/react@18.2.47)(react@18.2.0) '@tanstack/react-query': specifier: ^5.17.9 version: 5.17.9(react@18.2.0) @@ -32,12 +35,18 @@ dependencies: next: specifier: 14.0.4 version: 14.0.4(react-dom@18.2.0)(react@18.2.0) + next-themes: + specifier: ^0.2.1 + version: 0.2.1(next@14.0.4)(react-dom@18.2.0)(react@18.2.0) react: specifier: ^18 version: 18.2.0 react-dom: specifier: ^18 version: 18.2.0(react@18.2.0) + sonner: + specifier: ^1.3.1 + version: 1.3.1(react-dom@18.2.0)(react@18.2.0) tailwind-merge: specifier: ^2.2.0 version: 2.2.0 @@ -2332,6 +2341,18 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /next-themes@0.2.1(next@14.0.4)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==} + peerDependencies: + next: '*' + react: '*' + react-dom: '*' + dependencies: + next: 14.0.4(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /next@14.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-qbwypnM7327SadwFtxXnQdGiKpkuhaRLE2uq62/nRul9cj9KhQ5LhHmlziTNqUidZotw/Q1I9OjirBROdUJNgA==} engines: {node: '>=18.17.0'} @@ -2871,6 +2892,16 @@ packages: engines: {node: '>=8'} dev: true + /sonner@1.3.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-+rOAO56b2eI3q5BtgljERSn2umRk63KFIvgb2ohbZ5X+Eb5u+a/7/0ZgswYqgBMg8dyl7n6OXd9KasA8QF9ToA==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index ac3a187..a3617d3 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,12 +1,15 @@ import type { Metadata } from "next"; -import { Inter } from "next/font/google"; +import { Inter, Poppins, DM_Sans } from "next/font/google"; import "./globals.css"; import React from "react"; import { GlobalProvider } from "./global-provider"; import { cn } from "@/utils/cn"; -import NavigationBar from "@/components/common/NavigationBar"; +import NavigationBar from "@/components/common/navigation-bar"; +import { Toaster } from "@/components/ui/sonner"; const inter = Inter({ subsets: ["latin"] }); +const poppins = Poppins({ subsets: ["latin"], weight: ["400", "500", "600", "700"] }); +const dm_sans = DM_Sans({ subsets: ["latin"], weight: ["400", "500", "600", "700"] }); export const metadata: Metadata = { title: "Create Next App", @@ -16,11 +19,12 @@ export const metadata: Metadata = { export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - +
-
{children}
+
{children}
+
diff --git a/src/app/ticker/_components/drawer.tsx b/src/app/ticker/_components/ticker-drawer.tsx similarity index 100% rename from src/app/ticker/_components/drawer.tsx rename to src/app/ticker/_components/ticker-drawer.tsx diff --git a/src/app/ticker/_components/ticker-list.tsx b/src/app/ticker/_components/ticker-list.tsx new file mode 100644 index 0000000..58d575b --- /dev/null +++ b/src/app/ticker/_components/ticker-list.tsx @@ -0,0 +1,41 @@ +"use client"; + +import Toast from "@/components/common/toast/toast"; +import { Button } from "@/components/ui/button"; +import React from "react"; +import { toast } from "sonner"; + +const TickerList = React.memo(() => { + const onTickerDelete = React.useCallback(() => { + toast.custom((t) => ); + }, []); + + return ( +
+
+
+

GOOGLE

+ +
+
+

GOOGLE

+ +
+
+

GOOGLE

+ +
+
+

GOOGLE

+ +
+
+

GOOGLE

+ +
+
+
+ ); +}); + +export default TickerList; diff --git a/src/app/ticker/page.tsx b/src/app/ticker/page.tsx index 0e4ee90..81825b3 100644 --- a/src/app/ticker/page.tsx +++ b/src/app/ticker/page.tsx @@ -1,13 +1,14 @@ import { Plus } from "lucide-react"; import { Drawer as DrawerPrimitive, DrawerTrigger } from "@/components/ui/drawer"; -import { TickerDrawer } from "./_components/drawer"; +import { TickerDrawer } from "./_components/ticker-drawer"; +import TickerList from "./_components/ticker-list"; const TickerPage = () => { return ( - +

You Added 0 Tickers

-
+
@@ -17,6 +18,7 @@ const TickerPage = () => {
+
diff --git a/src/components/common/NavigationBar.tsx b/src/components/common/navigation-bar.tsx similarity index 100% rename from src/components/common/NavigationBar.tsx rename to src/components/common/navigation-bar.tsx diff --git a/src/components/common/toast/toast.tsx b/src/components/common/toast/toast.tsx new file mode 100644 index 0000000..6698b99 --- /dev/null +++ b/src/components/common/toast/toast.tsx @@ -0,0 +1,39 @@ +import { Button } from "@/components/ui/button"; +import { cn } from "@/utils/cn"; +import React from "react"; +import { toast } from "sonner"; + +export interface ToastProps extends React.HTMLAttributes { + t?: string | number; + title: string; + isRevertable?: boolean; +} + +const Toast = React.memo(({ t, title, isRevertable, ...props }: ToastProps) => { + const onUndo = React.useCallback(() => { + toast.dismiss(t); + }, [t]); + + return ( +
+

{title}

+ {isRevertable && } +
+ ); +}); + +const UndoButton = React.memo(({ onClick }: { onClick: () => void }) => { + return ( + + ); +}); + +export default Toast; diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..30f1ad2 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,46 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import { cn } from "@/utils/cn"; + +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", + }, + }, + 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/sonner.tsx b/src/components/ui/sonner.tsx new file mode 100644 index 0000000..452f4d9 --- /dev/null +++ b/src/components/ui/sonner.tsx @@ -0,0 +1,31 @@ +"use client" + +import { useTheme } from "next-themes" +import { Toaster as Sonner } from "sonner" + +type ToasterProps = React.ComponentProps + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = "system" } = useTheme() + + return ( + + ) +} + +export { Toaster }