Skip to content

Commit b2312ec

Browse files
authored
feat: Update toast to better colours with logos (#20)
- Introduced `error` variant - Rename `green` to `success` - Added icons to `success` and `error` variants <img width="434" alt="image" src="https://github.com/user-attachments/assets/71edf1f7-c64e-4883-a7d9-8174c3807386"> <img width="422" alt="image" src="https://github.com/user-attachments/assets/0d3c2450-0a60-498d-9a15-89516a1d67a4">
1 parent 28bb798 commit b2312ec

File tree

8 files changed

+73
-44
lines changed

8 files changed

+73
-44
lines changed

project/apps/web/app/auth/SignInForm.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ export function SignInForm() {
3232
},
3333
onError(error) {
3434
toast({
35+
title: "Error",
3536
description: error.message,
36-
variant: "destructive",
37+
variant: "error",
3738
});
3839
},
3940
});

project/apps/web/app/auth/SignUpForm.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ export function SignUpForm() {
3232
onError: (error) => {
3333
toast({
3434
description: error.message,
35-
variant: "destructive",
35+
variant: "error",
36+
title: "Error",
3637
});
3738
},
3839
});

project/apps/web/app/globals.css

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ h6 {
4646
--destructive: 0 100% 50%;
4747
--destructive-foreground: 210 40% 98%;
4848

49-
--green: 120 100% 25%;
50-
--green-foreground: 0 0% 100%;
49+
--success: 120 100% 25%;
50+
--success-foreground: 0 0% 100%;
51+
52+
--error: 0 78.4% 47.3%;
53+
--error-foreground: 0 75% 98.4%;
5154

5255
--ring: 215 20.2% 65.1%;
5356

project/apps/web/app/question/[id]/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ const QuestionPageContent = ({ id }: { id: string }) => {
6161
onSettled: () => setConfirmLoading(false),
6262
onError: (error) => {
6363
toast({
64-
variant: "destructive",
64+
variant: "error",
6565
title: "Error",
66-
description: "Error updating question" + error.message,
66+
description: error.message,
6767
});
6868
},
6969
});
@@ -86,9 +86,9 @@ const QuestionPageContent = ({ id }: { id: string }) => {
8686
onSettled: () => setConfirmLoading(false),
8787
onError: (error) => {
8888
toast({
89-
variant: "destructive",
89+
variant: "error",
9090
title: "Error",
91-
description: "Error deleting question" + error.message,
91+
description: error.message,
9292
});
9393
},
9494
});

project/apps/web/app/questions/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ const QuestionRepositoryContent = () => {
5151
onSettled: () => setConfirmLoading(false),
5252
onError: (error) => {
5353
toast({
54-
variant: "destructive",
54+
variant: "error",
5555
title: "Error",
56-
description: "Error creating question: " + error.message,
56+
description: error.message,
5757
});
5858
},
5959
});
Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
"use client"
1+
"use client";
22

3-
import * as React from "react"
4-
import * as ToastPrimitives from "@radix-ui/react-toast"
5-
import { cva, type VariantProps } from "class-variance-authority"
6-
import { X } from "lucide-react"
3+
import * as React from "react";
4+
import * as ToastPrimitives from "@radix-ui/react-toast";
5+
import { cva, type VariantProps } from "class-variance-authority";
6+
import { X } from "lucide-react";
7+
import { CircleAlert, CircleCheck } from "lucide-react";
8+
import { cn } from "@/lib/utils";
79

8-
import { cn } from "@/lib/utils"
9-
10-
const ToastProvider = ToastPrimitives.Provider
10+
const ToastProvider = ToastPrimitives.Provider;
1111

1212
const ToastViewport = React.forwardRef<
1313
React.ElementRef<typeof ToastPrimitives.Viewport>,
@@ -17,29 +17,41 @@ const ToastViewport = React.forwardRef<
1717
ref={ref}
1818
className={cn(
1919
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
20-
className
20+
className,
2121
)}
2222
{...props}
2323
/>
24-
))
25-
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
24+
));
25+
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
2626

2727
const toastVariants = cva(
2828
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
2929
{
3030
variants: {
3131
variant: {
3232
default: "border bg-background text-foreground",
33-
success: "success bg-green text-green-foreground",
33+
success:
34+
"success group border-success bg-success text-success-foreground",
35+
error: "error group border-error bg-error text-error-foreground",
3436
destructive:
3537
"destructive group border-destructive bg-destructive text-destructive-foreground",
3638
},
3739
},
3840
defaultVariants: {
3941
variant: "default",
4042
},
43+
},
44+
);
45+
46+
const ToastLogo = ({ variant }: VariantProps<typeof toastVariants>) => {
47+
switch (variant) {
48+
case "success":
49+
return <CircleCheck className="w-4 h-4" />;
50+
case "error":
51+
return <CircleAlert className="w-4 h-4" />;
4152
}
42-
)
53+
return <></>;
54+
};
4355

4456
const Toast = React.forwardRef<
4557
React.ElementRef<typeof ToastPrimitives.Root>,
@@ -52,9 +64,9 @@ const Toast = React.forwardRef<
5264
className={cn(toastVariants({ variant }), className)}
5365
{...props}
5466
/>
55-
)
56-
})
57-
Toast.displayName = ToastPrimitives.Root.displayName
67+
);
68+
});
69+
Toast.displayName = ToastPrimitives.Root.displayName;
5870

5971
const ToastAction = React.forwardRef<
6072
React.ElementRef<typeof ToastPrimitives.Action>,
@@ -64,12 +76,12 @@ const ToastAction = React.forwardRef<
6476
ref={ref}
6577
className={cn(
6678
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
67-
className
79+
className,
6880
)}
6981
{...props}
7082
/>
71-
))
72-
ToastAction.displayName = ToastPrimitives.Action.displayName
83+
));
84+
ToastAction.displayName = ToastPrimitives.Action.displayName;
7385

7486
const ToastClose = React.forwardRef<
7587
React.ElementRef<typeof ToastPrimitives.Close>,
@@ -79,15 +91,15 @@ const ToastClose = React.forwardRef<
7991
ref={ref}
8092
className={cn(
8193
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
82-
className
94+
className,
8395
)}
8496
toast-close=""
8597
{...props}
8698
>
87-
<X className="h-4 w-4" />
99+
<X className="w-4 h-4" />
88100
</ToastPrimitives.Close>
89-
))
90-
ToastClose.displayName = ToastPrimitives.Close.displayName
101+
));
102+
ToastClose.displayName = ToastPrimitives.Close.displayName;
91103

92104
const ToastTitle = React.forwardRef<
93105
React.ElementRef<typeof ToastPrimitives.Title>,
@@ -98,8 +110,8 @@ const ToastTitle = React.forwardRef<
98110
className={cn("text-sm font-semibold", className)}
99111
{...props}
100112
/>
101-
))
102-
ToastTitle.displayName = ToastPrimitives.Title.displayName
113+
));
114+
ToastTitle.displayName = ToastPrimitives.Title.displayName;
103115

104116
const ToastDescription = React.forwardRef<
105117
React.ElementRef<typeof ToastPrimitives.Description>,
@@ -110,12 +122,13 @@ const ToastDescription = React.forwardRef<
110122
className={cn("text-sm opacity-90", className)}
111123
{...props}
112124
/>
113-
))
114-
ToastDescription.displayName = ToastPrimitives.Description.displayName
125+
));
126+
127+
ToastDescription.displayName = ToastPrimitives.Description.displayName;
115128

116-
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
129+
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
117130

118-
type ToastActionElement = React.ReactElement<typeof ToastAction>
131+
type ToastActionElement = React.ReactElement<typeof ToastAction>;
119132

120133
export {
121134
type ToastProps,
@@ -127,4 +140,5 @@ export {
127140
ToastDescription,
128141
ToastClose,
129142
ToastAction,
130-
}
143+
ToastLogo,
144+
};

project/apps/web/components/ui/toaster.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Toast,
66
ToastClose,
77
ToastDescription,
8+
ToastLogo,
89
ToastProvider,
910
ToastTitle,
1011
ToastViewport,
@@ -19,7 +20,12 @@ export function Toaster() {
1920
return (
2021
<Toast key={id} {...props}>
2122
<div className="grid gap-1">
22-
{title && <ToastTitle>{title}</ToastTitle>}
23+
{title && (
24+
<ToastTitle className="flex flex-row items-center gap-2">
25+
<ToastLogo variant={props.variant} />
26+
{title}
27+
</ToastTitle>
28+
)}
2329
{description && (
2430
<ToastDescription>{description}</ToastDescription>
2531
)}

project/apps/web/tailwind.config.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ module.exports = {
3131
DEFAULT: "hsl(var(--destructive))",
3232
foreground: "hsl(var(--destructive-foreground))",
3333
},
34-
green: {
35-
DEFAULT: "hsl(var(--green))",
36-
foreground: "hsl(var(--green-foreground))",
34+
success: {
35+
DEFAULT: "hsl(var(--success))",
36+
foreground: "hsl(var(--success-foreground))",
37+
},
38+
error: {
39+
DEFAULT: "hsl(var(--error))",
40+
foreground: "hsl(var(--error-foreground))",
3741
},
3842
muted: {
3943
DEFAULT: "hsl(var(--muted))",

0 commit comments

Comments
 (0)