Skip to content

Commit

Permalink
feat(Toast): add Toast nearly identical to ChatGPT's (danny-avila#1108)
Browse files Browse the repository at this point in the history
  • Loading branch information
danny-avila authored Oct 27, 2023
1 parent ba5ab86 commit 81a90d2
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 3 deletions.
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@radix-ui/react-slider": "^1.1.1",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.3",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.6",
"@tanstack/react-query": "^4.28.0",
"@zattoo/use-double-click": "1.2.0",
Expand Down
10 changes: 8 additions & 2 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { RecoilRoot } from 'recoil';
import * as RadixToast from '@radix-ui/react-toast';
import { RouterProvider } from 'react-router-dom';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { QueryClient, QueryClientProvider, QueryCache } from '@tanstack/react-query';
import { ScreenshotProvider, ThemeProvider, useApiErrorBoundary } from './hooks';
import Toast from './components/ui/Toast';
import { router } from './routes';

const App = () => {
Expand All @@ -22,8 +24,12 @@ const App = () => {
<QueryClientProvider client={queryClient}>
<RecoilRoot>
<ThemeProvider>
<RouterProvider router={router} />
<ReactQueryDevtools initialIsOpen={false} position="top-right" />
<RadixToast.Provider>
<RouterProvider router={router} />
<ReactQueryDevtools initialIsOpen={false} position="top-right" />
<Toast />
<RadixToast.Viewport className="pointer-events-none fixed inset-0 z-[60] mx-auto my-2 flex max-w-[560px] flex-col items-stretch justify-start md:pb-5" />
</RadixToast.Provider>
</ThemeProvider>
</RecoilRoot>
</QueryClientProvider>
Expand Down
7 changes: 7 additions & 0 deletions client/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ export enum ESide {
Left = 'left',
}

export enum NotificationSeverity {
INFO = 'info',
SUCCESS = 'success',
WARNING = 'warning',
ERROR = 'error',
}

export type TBaseSettingsProps = {
conversation: TConversation | TPreset | null;
className?: string;
Expand Down
58 changes: 58 additions & 0 deletions client/src/components/ui/Toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as RadixToast from '@radix-ui/react-toast';
import { NotificationSeverity } from '~/common/types';
import { useToast } from '~/hooks';

export default function Toast() {
const { toast, onOpenChange } = useToast();
const severityClassName = {
[NotificationSeverity.INFO]: 'border-gray-500 bg-gray-500',
[NotificationSeverity.SUCCESS]: 'border-green-500 bg-green-500',
[NotificationSeverity.WARNING]: 'border-orange-500 bg-orange-500',
[NotificationSeverity.ERROR]: 'border-red-500 bg-red-500',
};

return (
<RadixToast.Root
open={toast.open}
onOpenChange={onOpenChange}
className="toast-root"
style={{
height: '74px',
marginBottom: '0px',
}}
>
<div className="w-full p-1 text-center md:w-auto md:text-justify">
<div
className={`alert-root pointer-events-auto inline-flex flex-row gap-2 rounded-md border px-3 py-2 text-white ${
severityClassName[toast.severity]
}`}
role="alert"
>
{toast.showIcon && (
<div className="mt-1 flex-shrink-0 flex-grow-0">
<svg
stroke="currentColor"
fill="none"
strokeWidth="2"
viewBox="0 0 24 24"
strokeLinecap="round"
strokeLinejoin="round"
className="icon-sm"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2" />
<line x1="12" y1="8" x2="12" y2="12" />
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
</div>
)}
<RadixToast.Description className="flex-1 justify-center gap-2">
<div className="whitespace-pre-wrap text-left">{toast.message}</div>
</RadixToast.Description>
</div>
</div>
</RadixToast.Root>
);
}
1 change: 1 addition & 0 deletions client/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './AuthContext';
export * from './ThemeContext';
export * from './ScreenshotContext';
export * from './ApiErrorBoundaryContext';
export { default as useToast } from './useToast';
export { default as useTimeout } from './useTimeout';
export { default as useUserKey } from './useUserKey';
export { default as useDebounce } from './useDebounce';
Expand Down
43 changes: 43 additions & 0 deletions client/src/hooks/useToast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useRef, useEffect } from 'react';
import { useRecoilState } from 'recoil';
import { NotificationSeverity } from '~/common';
import store from '~/store';

export default function useToast(timeoutDuration = 100) {
const [toast, setToast] = useRecoilState(store.toastState);
const timerRef = useRef<number | null>(null);

useEffect(() => {
return () => {
if (timerRef.current !== null) {
clearTimeout(timerRef.current);
}
};
}, []);

type TShowToast = {
message: string;
severity?: NotificationSeverity;
showIcon?: boolean;
};

const showToast = ({
message,
severity = NotificationSeverity.SUCCESS,
showIcon = true,
}: TShowToast) => {
setToast({ ...toast, open: false });
if (timerRef.current !== null) {
clearTimeout(timerRef.current);
}
timerRef.current = window.setTimeout(() => {
setToast({ open: true, message, severity, showIcon });
}, timeoutDuration);
};

return {
toast,
onOpenChange: (open: boolean) => setToast({ ...toast, open }),
showToast,
};
}
2 changes: 2 additions & 0 deletions client/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import endpoints from './endpoints';
import models from './models';
import user from './user';
import text from './text';
import toast from './toast';
import submission from './submission';
import search from './search';
import preset from './preset';
Expand All @@ -17,6 +18,7 @@ export default {
...models,
...user,
...text,
...toast,
...submission,
...search,
...preset,
Expand Down
14 changes: 14 additions & 0 deletions client/src/store/toast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { atom } from 'recoil';
import { NotificationSeverity } from '~/common';

const toastState = atom({
key: 'toastState',
default: {
open: false,
message: '',
severity: NotificationSeverity.SUCCESS,
showIcon: true,
},
});

export default { toastState };
61 changes: 61 additions & 0 deletions client/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1532,3 +1532,64 @@ button.scroll-convo {
.hidden-visibility {
visibility: hidden;
}

.toast-root {
align-items:center;
display:flex;
flex-direction:column;
height:0;
transition:all .24s cubic-bezier(0,0,.2,1)
}

.toast-root[data-state=open] {
-webkit-animation:toast-open .24s cubic-bezier(.175,.885,.32,1.175) both;
animation:toast-open .24s cubic-bezier(.175,.885,.32,1.175) both
}
.toast-root[data-state=closed] {
-webkit-animation:toast-close .12s cubic-bezier(.4,0,1,1) both;
animation:toast-close .12s cubic-bezier(.4,0,1,1) both
}
.toast-root .alert-root {
box-shadow:0 0 1px rgba(67,90,111,.3),0 5px 8px -4px rgba(67,90,111,.3);
flex-shrink:0;
pointer-events:all
}

@-webkit-keyframes toast-open {
0% {
opacity:0;
-webkit-transform:translateY(-100%);
transform:translateY(-100%)
}
to {
-webkit-transform:translateY(0);
transform:translateY(0)
}
}
@keyframes toast-open {
0% {
opacity:0;
-webkit-transform:translateY(-100%);
transform:translateY(-100%)
}
to {
-webkit-transform:translateY(0);
transform:translateY(0)
}
}
@-webkit-keyframes toast-close {
0% {
opacity:1
}
to {
opacity:0
}
}
@keyframes toast-close {
0% {
opacity:1
}
to {
opacity:0
}
}
87 changes: 86 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 81a90d2

Please sign in to comment.