mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-18 09:39:11 +00:00
toast notification hook
This commit is contained in:
parent
75c4680b43
commit
162eef60ab
|
@ -24,6 +24,7 @@
|
|||
"@radix-ui/react-progress": "^1.0.0",
|
||||
"@radix-ui/react-slider": "^1.0.0",
|
||||
"@radix-ui/react-tabs": "^1.0.0",
|
||||
"@radix-ui/react-toast": "^1.0.0",
|
||||
"@radix-ui/react-tooltip": "^1.0.0",
|
||||
"@sd/assets": "workspace:*",
|
||||
"@sd/client": "workspace:*",
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import * as ToastPrimitive from '@radix-ui/react-toast';
|
||||
import { useCurrentLibrary } from '@sd/client';
|
||||
import clsx from 'clsx';
|
||||
import { Suspense } from 'react';
|
||||
import { Suspense, useEffect, useState } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
import { Sidebar } from './components/layout/Sidebar';
|
||||
import { useOperatingSystem } from './hooks/useOperatingSystem';
|
||||
import { useToasts } from './hooks/useToasts';
|
||||
|
||||
export function AppLayout() {
|
||||
const { libraries } = useCurrentLibrary();
|
||||
|
@ -34,6 +36,94 @@ export function AppLayout() {
|
|||
<Outlet />
|
||||
</Suspense>
|
||||
</div>
|
||||
<Toasts />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Toasts() {
|
||||
const { toasts, addToast, removeToast } = useToasts();
|
||||
|
||||
// useEffect(() => {
|
||||
// setTimeout(() => {
|
||||
// addToast({
|
||||
// title: 'Spacedrop',
|
||||
// subtitle: 'Someone tried to send you a file. Accept it?',
|
||||
// actionButton: {
|
||||
// text: 'Accept',
|
||||
// onClick: () => {
|
||||
// console.log('Bruh');
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }, 2000);
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<div className="fixed flex right-0">
|
||||
<ToastPrimitive.Provider>
|
||||
<>
|
||||
{toasts.map((toast) => (
|
||||
<ToastPrimitive.Root
|
||||
key={toast.id}
|
||||
open={true}
|
||||
onOpenChange={() => removeToast(toast)}
|
||||
duration={toast.duration || 3000}
|
||||
className={clsx(
|
||||
'w-80 m-4 shadow-lg rounded-lg',
|
||||
'bg-gray-800/20 backdrop-blur',
|
||||
'radix-state-open:animate-toast-slide-in-bottom md:radix-state-open:animate-toast-slide-in-right',
|
||||
'radix-state-closed:animate-toast-hide',
|
||||
'radix-swipe-end:animate-toast-swipe-out',
|
||||
'translate-x-radix-toast-swipe-move-x',
|
||||
'radix-swipe-cancel:translate-x-0 radix-swipe-cancel:duration-200 radix-swipe-cancel:ease-[ease]',
|
||||
'focus:outline-none focus-visible:ring focus-visible:ring-primary focus-visible:ring-opacity-75 border-white/10 border-2 shadow-2xl'
|
||||
)}
|
||||
>
|
||||
<div className="flex">
|
||||
<div className="w-0 flex-1 flex items-center pl-5 py-4">
|
||||
<div className="w-full radix">
|
||||
<ToastPrimitive.Title className="text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||
{toast.title}
|
||||
</ToastPrimitive.Title>
|
||||
{toast.subtitle && (
|
||||
<ToastPrimitive.Description className="mt-1 text-sm text-gray-700 dark:text-gray-400">
|
||||
{toast.subtitle}
|
||||
</ToastPrimitive.Description>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<div className="flex flex-col px-3 py-2 space-y-1">
|
||||
<div className="h-0 flex-1 flex">
|
||||
{toast.actionButton && (
|
||||
<ToastPrimitive.Action
|
||||
altText="view now"
|
||||
className="w-full border border-transparent rounded-lg px-3 py-2 flex items-center justify-center text-sm font-medium text-primary dark:text-primary hover:bg-white/10 focus:z-10 focus:outline-none focus-visible:ring focus-visible:ring-primary focus-visible:ring-opacity-75"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
toast.actionButton?.onClick();
|
||||
removeToast(toast);
|
||||
}}
|
||||
>
|
||||
{toast.actionButton.text || 'Open'}
|
||||
</ToastPrimitive.Action>
|
||||
)}
|
||||
</div>
|
||||
<div className="h-0 flex-1 flex">
|
||||
<ToastPrimitive.Close className="w-full border border-transparent rounded-lg px-3 py-2 flex items-center justify-center text-sm font-medium text-gray-700 dark:text-gray-100 hover:bg-white/10 focus:z-10 focus:outline-none focus-visible:ring focus-visible:ring-primary focus-visible:ring-opacity-75">
|
||||
Dismiss
|
||||
</ToastPrimitive.Close>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ToastPrimitive.Root>
|
||||
))}
|
||||
|
||||
<ToastPrimitive.Viewport />
|
||||
</>
|
||||
</ToastPrimitive.Provider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
34
packages/interface/src/hooks/useToasts.ts
Normal file
34
packages/interface/src/hooks/useToasts.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { proxy, useSnapshot } from 'valtio';
|
||||
|
||||
interface Toast {
|
||||
id: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
duration?: number;
|
||||
actionButton?: {
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
const state = proxy({
|
||||
toasts: [] as Toast[]
|
||||
});
|
||||
|
||||
const randomId = () => Math.random().toString(36).slice(2);
|
||||
|
||||
export function useToasts() {
|
||||
return {
|
||||
toasts: useSnapshot(state).toasts,
|
||||
addToast: (toast: Omit<Toast, 'id'>) => {
|
||||
state.toasts.push({
|
||||
id: randomId(),
|
||||
...toast
|
||||
});
|
||||
},
|
||||
removeToast: (toast: Toast | string) => {
|
||||
const id = typeof toast === 'string' ? toast : toast.id;
|
||||
state.toasts = state.toasts.filter((t) => t.id !== id);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -337,6 +337,7 @@ importers:
|
|||
'@radix-ui/react-progress': ^1.0.0
|
||||
'@radix-ui/react-slider': ^1.0.0
|
||||
'@radix-ui/react-tabs': ^1.0.0
|
||||
'@radix-ui/react-toast': ^1.0.0
|
||||
'@radix-ui/react-tooltip': ^1.0.0
|
||||
'@sd/assets': workspace:*
|
||||
'@sd/client': workspace:*
|
||||
|
@ -411,6 +412,7 @@ importers:
|
|||
'@radix-ui/react-progress': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-slider': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-tabs': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-toast': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-tooltip': 1.0.0_rj7ozvcq3uehdlnj3cbwzbi5ce
|
||||
'@sd/assets': link:../assets
|
||||
'@sd/client': link:../client
|
||||
|
@ -3451,6 +3453,29 @@ packages:
|
|||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-toast/1.0.0_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-mdoF6rahgushdev0OX+9a7JKoH0xZAZBo2Ktf/s779S7EnkZeL3/MFiRIV5LpRP5CtASmfdSD3FLnEvG1RHRtQ==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.19.0
|
||||
'@radix-ui/primitive': 1.0.0
|
||||
'@radix-ui/react-collection': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-context': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-dismissable-layer': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-portal': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-presence': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-primitive': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-use-callback-ref': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-use-controllable-state': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-use-layout-effect': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-visually-hidden': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-tooltip/1.0.0_rj7ozvcq3uehdlnj3cbwzbi5ce:
|
||||
resolution: {integrity: sha512-RB06pov+O4Npy10ei1C6fsyB9QoOjz7Ubo8Sl3qdKtLgkL9iI96925DYtH0bxx6MH6YB2FuzLU6B75qn3AQQQw==}
|
||||
peerDependencies:
|
||||
|
@ -6232,7 +6257,7 @@ packages:
|
|||
'@babel/plugin-transform-react-jsx-source': 7.18.6_@babel+core@7.19.3
|
||||
magic-string: 0.26.6
|
||||
react-refresh: 0.14.0
|
||||
vite: 3.1.4_sass@1.55.0
|
||||
vite: 3.1.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
@ -6967,6 +6992,7 @@ packages:
|
|||
normalize-range: 0.1.2
|
||||
picocolors: 1.0.0
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/autoprefixer/10.4.12_postcss@8.4.17:
|
||||
resolution: {integrity: sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==}
|
||||
|
@ -7527,7 +7553,7 @@ packages:
|
|||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001416
|
||||
electron-to-chromium: 1.4.274
|
||||
electron-to-chromium: 1.4.275
|
||||
node-releases: 2.0.6
|
||||
update-browserslist-db: 1.0.10_browserslist@4.21.4
|
||||
|
||||
|
@ -9250,8 +9276,8 @@ packages:
|
|||
jake: 10.8.5
|
||||
dev: true
|
||||
|
||||
/electron-to-chromium/1.4.274:
|
||||
resolution: {integrity: sha512-Fgn7JZQzq85I81FpKUNxVLAzoghy8JZJ4NIue+YfUYBbu1AkpgzFvNwzF/ZNZH9ElkmJD0TSWu1F2gTpw/zZlg==}
|
||||
/electron-to-chromium/1.4.275:
|
||||
resolution: {integrity: sha512-aJeQQ+Hl9Jyyzv4chBqYJwmVRY46N5i2BEX5Cuyk/5gFCUZ5F3i7Hnba6snZftWla7Gglwc5pIgcd+E7cW+rPg==}
|
||||
|
||||
/elliptic/6.5.4:
|
||||
resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==}
|
||||
|
@ -18098,7 +18124,7 @@ packages:
|
|||
valtio: ^1.2.5
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
valtio: 1.7.0
|
||||
valtio: 1.7.0_react@18.2.0+vite@3.1.4
|
||||
dev: false
|
||||
|
||||
/valtio/1.7.0:
|
||||
|
@ -18262,7 +18288,7 @@ packages:
|
|||
dependencies:
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
'@svgr/core': 6.4.0
|
||||
vite: 3.1.4_sass@1.55.0
|
||||
vite: 3.1.4
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- supports-color
|
||||
|
|
Loading…
Reference in a new issue