From a69553e0895e23b10aa9acd54460208d122e6b01 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Sun, 8 Sep 2024 18:10:54 +0200 Subject: [PATCH 1/3] Added toast from shadcn --- components/ui/toast/Toast.vue | 28 ++++ components/ui/toast/ToastAction.vue | 19 +++ components/ui/toast/ToastClose.vue | 22 +++ components/ui/toast/ToastDescription.vue | 19 +++ components/ui/toast/ToastProvider.vue | 11 ++ components/ui/toast/ToastTitle.vue | 19 +++ components/ui/toast/ToastViewport.vue | 17 +++ components/ui/toast/Toaster.vue | 30 +++++ components/ui/toast/index.ts | 38 ++++++ components/ui/toast/use-toast.ts | 165 +++++++++++++++++++++++ 10 files changed, 368 insertions(+) create mode 100644 components/ui/toast/Toast.vue create mode 100644 components/ui/toast/ToastAction.vue create mode 100644 components/ui/toast/ToastClose.vue create mode 100644 components/ui/toast/ToastDescription.vue create mode 100644 components/ui/toast/ToastProvider.vue create mode 100644 components/ui/toast/ToastTitle.vue create mode 100644 components/ui/toast/ToastViewport.vue create mode 100644 components/ui/toast/Toaster.vue create mode 100644 components/ui/toast/index.ts create mode 100644 components/ui/toast/use-toast.ts diff --git a/components/ui/toast/Toast.vue b/components/ui/toast/Toast.vue new file mode 100644 index 0000000..6917464 --- /dev/null +++ b/components/ui/toast/Toast.vue @@ -0,0 +1,28 @@ + + + diff --git a/components/ui/toast/ToastAction.vue b/components/ui/toast/ToastAction.vue new file mode 100644 index 0000000..23167ae --- /dev/null +++ b/components/ui/toast/ToastAction.vue @@ -0,0 +1,19 @@ + + + diff --git a/components/ui/toast/ToastClose.vue b/components/ui/toast/ToastClose.vue new file mode 100644 index 0000000..3799e75 --- /dev/null +++ b/components/ui/toast/ToastClose.vue @@ -0,0 +1,22 @@ + + + diff --git a/components/ui/toast/ToastDescription.vue b/components/ui/toast/ToastDescription.vue new file mode 100644 index 0000000..a364d66 --- /dev/null +++ b/components/ui/toast/ToastDescription.vue @@ -0,0 +1,19 @@ + + + diff --git a/components/ui/toast/ToastProvider.vue b/components/ui/toast/ToastProvider.vue new file mode 100644 index 0000000..367de1a --- /dev/null +++ b/components/ui/toast/ToastProvider.vue @@ -0,0 +1,11 @@ + + + diff --git a/components/ui/toast/ToastTitle.vue b/components/ui/toast/ToastTitle.vue new file mode 100644 index 0000000..653c6e7 --- /dev/null +++ b/components/ui/toast/ToastTitle.vue @@ -0,0 +1,19 @@ + + + diff --git a/components/ui/toast/ToastViewport.vue b/components/ui/toast/ToastViewport.vue new file mode 100644 index 0000000..7354994 --- /dev/null +++ b/components/ui/toast/ToastViewport.vue @@ -0,0 +1,17 @@ + + + diff --git a/components/ui/toast/Toaster.vue b/components/ui/toast/Toaster.vue new file mode 100644 index 0000000..5b186e6 --- /dev/null +++ b/components/ui/toast/Toaster.vue @@ -0,0 +1,30 @@ + + + diff --git a/components/ui/toast/index.ts b/components/ui/toast/index.ts new file mode 100644 index 0000000..09d5dd0 --- /dev/null +++ b/components/ui/toast/index.ts @@ -0,0 +1,38 @@ +import type { ToastRootProps } from "radix-vue" +import type { HTMLAttributes } from "vue" + +import { type VariantProps, cva } from "class-variance-authority" + +export { default as Toaster } from "./Toaster.vue" +export { default as Toast } from "./Toast.vue" +export { default as ToastViewport } from "./ToastViewport.vue" +export { default as ToastAction } from "./ToastAction.vue" +export { default as ToastClose } from "./ToastClose.vue" +export { default as ToastTitle } from "./ToastTitle.vue" +export { default as ToastDescription } from "./ToastDescription.vue" +export { default as ToastProvider } from "./ToastProvider.vue" +export { toast, useToast } from "./use-toast" + +export const toastVariants = cva( + "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-[--radix-toast-swipe-end-x] data-[swipe=move]:translate-x-[--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", + { + variants: { + variant: { + default: "border bg-background text-foreground", + destructive: + "destructive group border-destructive bg-destructive text-destructive-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +) + +type ToastVariants = VariantProps + +export interface ToastProps extends ToastRootProps { + class?: HTMLAttributes["class"] + variant?: ToastVariants["variant"] + onOpenChange?: ((value: boolean) => void) | undefined +} diff --git a/components/ui/toast/use-toast.ts b/components/ui/toast/use-toast.ts new file mode 100644 index 0000000..3ead807 --- /dev/null +++ b/components/ui/toast/use-toast.ts @@ -0,0 +1,165 @@ +import { computed, ref } from "vue" +import type { Component, VNode } from "vue" +import type { ToastProps } from "." + +const TOAST_LIMIT = 1 +const TOAST_REMOVE_DELAY = 1000000 + +export type StringOrVNode = + | string + | VNode + | (() => VNode) + +type ToasterToast = ToastProps & { + id: string + title?: string + description?: StringOrVNode + action?: Component +} + +const actionTypes = { + ADD_TOAST: "ADD_TOAST", + UPDATE_TOAST: "UPDATE_TOAST", + DISMISS_TOAST: "DISMISS_TOAST", + REMOVE_TOAST: "REMOVE_TOAST", +} as const + +let count = 0 + +function genId() { + count = (count + 1) % Number.MAX_VALUE + return count.toString() +} + +type ActionType = typeof actionTypes + +type Action = + | { + type: ActionType["ADD_TOAST"] + toast: ToasterToast + } + | { + type: ActionType["UPDATE_TOAST"] + toast: Partial + } + | { + type: ActionType["DISMISS_TOAST"] + toastId?: ToasterToast["id"] + } + | { + type: ActionType["REMOVE_TOAST"] + toastId?: ToasterToast["id"] + } + +interface State { + toasts: ToasterToast[] +} + +const toastTimeouts = new Map>() + +function addToRemoveQueue(toastId: string) { + if (toastTimeouts.has(toastId)) + return + + const timeout = setTimeout(() => { + toastTimeouts.delete(toastId) + dispatch({ + type: actionTypes.REMOVE_TOAST, + toastId, + }) + }, TOAST_REMOVE_DELAY) + + toastTimeouts.set(toastId, timeout) +} + +const state = ref({ + toasts: [], +}) + +function dispatch(action: Action) { + switch (action.type) { + case actionTypes.ADD_TOAST: + state.value.toasts = [action.toast, ...state.value.toasts].slice(0, TOAST_LIMIT) + break + + case actionTypes.UPDATE_TOAST: + state.value.toasts = state.value.toasts.map(t => + t.id === action.toast.id ? { ...t, ...action.toast } : t, + ) + break + + case actionTypes.DISMISS_TOAST: { + const { toastId } = action + + if (toastId) { + addToRemoveQueue(toastId) + } + else { + state.value.toasts.forEach((toast) => { + addToRemoveQueue(toast.id) + }) + } + + state.value.toasts = state.value.toasts.map(t => + t.id === toastId || toastId === undefined + ? { + ...t, + open: false, + } + : t, + ) + break + } + + case actionTypes.REMOVE_TOAST: + if (action.toastId === undefined) + state.value.toasts = [] + else + state.value.toasts = state.value.toasts.filter(t => t.id !== action.toastId) + + break + } +} + +function useToast() { + return { + toasts: computed(() => state.value.toasts), + toast, + dismiss: (toastId?: string) => dispatch({ type: actionTypes.DISMISS_TOAST, toastId }), + } +} + +type Toast = Omit + +function toast(props: Toast) { + const id = genId() + + const update = (props: ToasterToast) => + dispatch({ + type: actionTypes.UPDATE_TOAST, + toast: { ...props, id }, + }) + + const dismiss = () => dispatch({ type: actionTypes.DISMISS_TOAST, toastId: id }) + + dispatch({ + type: actionTypes.ADD_TOAST, + toast: { + ...props, + id, + open: true, + onOpenChange: (open: boolean) => { + if (!open) + dismiss() + }, + }, + }) + + return { + id, + dismiss, + update, + } +} + +export { toast, useToast } From 2f79de84832c6e306dcab33a35f91a08bf112232 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Sun, 8 Sep 2024 19:26:38 +0200 Subject: [PATCH 2/3] Added toast on deleted entities --- app.vue | 4 ++++ assets/main.css | 8 ++++++++ components/calendar/dialog/Delete.vue | 17 +++++++++++++++-- components/calendar/form/DeleteEvent.vue | 14 +++++++++++++- components/ui/toast/ToastTitle.vue | 2 +- components/ui/toast/index.ts | 6 +++--- components/ui/toast/use-toast.ts | 2 +- i18n.config.ts | 16 ++++++++++++++-- tailwind.config.js | 5 +++++ 9 files changed, 64 insertions(+), 10 deletions(-) diff --git a/app.vue b/app.vue index 6557af5..a8e9e84 100644 --- a/app.vue +++ b/app.vue @@ -43,6 +43,10 @@ const useIdFunction = () => useId() + + + + diff --git a/assets/main.css b/assets/main.css index d457ff6..2cbcd24 100644 --- a/assets/main.css +++ b/assets/main.css @@ -31,6 +31,10 @@ --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; + --success: 156 72% 67%; + --success-muted: 156 72% 90%; + --success-foreground: 222.2 84% 4.9%; + --ring: 222.2 84% 4.9%; --radius: 0.5rem; @@ -64,6 +68,10 @@ --destructive: 0 62.8% 30.6%; --destructive-foreground: 210 40% 98%; + --success: 142 72% 29%; + --success-muted: 142 72% 10%; + --success-foreground: 210 40% 98%; + --ring: 212.7 26.8% 83.9%; } } diff --git a/components/calendar/dialog/Delete.vue b/components/calendar/dialog/Delete.vue index b964236..3d6f4d3 100644 --- a/components/calendar/dialog/Delete.vue +++ b/components/calendar/dialog/Delete.vue @@ -1,7 +1,11 @@ diff --git a/components/ui/toast/index.ts b/components/ui/toast/index.ts index 09d5dd0..1579986 100644 --- a/components/ui/toast/index.ts +++ b/components/ui/toast/index.ts @@ -14,13 +14,13 @@ export { default as ToastProvider } from "./ToastProvider.vue" export { toast, useToast } from "./use-toast" export const toastVariants = cva( - "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-[--radix-toast-swipe-end-x] data-[swipe=move]:translate-x-[--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", + "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[--radix-toast-swipe-end-x] data-[swipe=move]:translate-x-[--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", { variants: { variant: { default: "border bg-background text-foreground", - destructive: - "destructive group border-destructive bg-destructive text-destructive-foreground", + destructive: "destructive group border-destructive bg-destructive text-destructive-foreground", + success: "success group border-success bg-success-muted text-success-foreground" }, }, defaultVariants: { diff --git a/components/ui/toast/use-toast.ts b/components/ui/toast/use-toast.ts index 3ead807..66bb174 100644 --- a/components/ui/toast/use-toast.ts +++ b/components/ui/toast/use-toast.ts @@ -2,7 +2,7 @@ import { computed, ref } from "vue" import type { Component, VNode } from "vue" import type { ToastProps } from "." -const TOAST_LIMIT = 1 +const TOAST_LIMIT = 3 const TOAST_REMOVE_DELAY = 1000000 export type StringOrVNode = diff --git a/i18n.config.ts b/i18n.config.ts index a28dd38..5db15c1 100644 --- a/i18n.config.ts +++ b/i18n.config.ts @@ -107,7 +107,10 @@ export default defineI18nConfig(() => ({ deleteDialog: { title: "Delete this event", subtitle: "Data associated with this event will be lost and you won't be able to retrieve it !", - } + }, + deletedToast: { + title: "The event \"{event}\" has been successfuly deleted.", + }, }, createDialog: { title: "New calendar", @@ -127,6 +130,9 @@ export default defineI18nConfig(() => ({ title: "Are you sure you want to delete this calendar ?", subtitle: "Its events won't be accessible anymore and you won't be able to retrieve the deleted data !", }, + deletedToast: { + title: "Calendar \"{calendar}\" has been successfuly deleted.", + }, millennia: { nameSingular: "Millennia", nextSingular: "Next millennia", @@ -273,7 +279,10 @@ export default defineI18nConfig(() => ({ deleteDialog: { title: "Supprimer l'évènement", subtitle: "Les données associés à cet évènement seront supprimées et vous ne pourrez plus les récupérer !", - } + }, + deletedToast: { + title: "L'évènement \"{event}\" a été supprimé avec succès.", + }, }, createDialog: { title: "Nouveau calendrier", @@ -293,6 +302,9 @@ export default defineI18nConfig(() => ({ title: "Êtes-vous sûr de supprimer ce calendrier ?", subtitle: "Les évènements ne seront plus accessibles et vous ne pourrez plus récupérer les données !", }, + deletedToast: { + title: "Le calendrier \"{calendar}\" a été supprimé avec succès.", + }, millennia: { nameSingular: "Millénaire", nextSingular: "Millénaire suivant", diff --git a/tailwind.config.js b/tailwind.config.js index 230188b..c7ee994 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -41,6 +41,11 @@ module.exports = { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))", }, + success: { + DEFAULT: "hsl(var(--success))", + muted: "hsl(var(--success-muted))", + foreground: "hsl(var(--success-foreground))", + }, muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))", From 0f5bc219f2dd55e9fe05b255ec7eea513d697efa Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Sun, 8 Sep 2024 19:37:50 +0200 Subject: [PATCH 3/3] Changed slightly user menu --- components/global/user/CTA.vue | 16 +++++++++++----- i18n.config.ts | 2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/components/global/user/CTA.vue b/components/global/user/CTA.vue index f5c82c1..911b3a2 100644 --- a/components/global/user/CTA.vue +++ b/components/global/user/CTA.vue @@ -1,7 +1,7 @@