diff --git a/desktop-app/.eslintrc.json b/desktop-app/.eslintrc.json index 5c9e578f..9ed3d0a5 100644 --- a/desktop-app/.eslintrc.json +++ b/desktop-app/.eslintrc.json @@ -10,7 +10,7 @@ "parserOptions": { "ecmaVersion": "latest", "sourceType": "module", - "project": "./desktop-app/tsconfig.json" + "project": "./tsconfig.json" }, "plugins": [ "react" diff --git a/desktop-app/renderer/components/ui/toast.tsx b/desktop-app/renderer/components/ui/toast.tsx index a8224775..03709862 100644 --- a/desktop-app/renderer/components/ui/toast.tsx +++ b/desktop-app/renderer/components/ui/toast.tsx @@ -1,9 +1,9 @@ -import * as React from "react" -import * as ToastPrimitives from "@radix-ui/react-toast" -import { cva, type VariantProps } from "class-variance-authority" -import { X } from "lucide-react" +import * as React from 'react' +import * as ToastPrimitives from '@radix-ui/react-toast' +import { cva, type VariantProps } from 'class-variance-authority' +import { X } from 'lucide-react' -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils' const ToastProvider = ToastPrimitives.Provider @@ -14,7 +14,7 @@ const ToastViewport = React.forwardRef< (({ className, ...props }, ref) => ( )) @@ -104,7 +104,7 @@ const ToastDescription = React.forwardRef< >(({ className, ...props }, ref) => ( )) @@ -123,5 +123,5 @@ export { ToastTitle, ToastDescription, ToastClose, - ToastAction, + ToastAction } diff --git a/desktop-app/renderer/components/ui/toaster.tsx b/desktop-app/renderer/components/ui/toaster.tsx index e2233852..8fbf8b83 100644 --- a/desktop-app/renderer/components/ui/toaster.tsx +++ b/desktop-app/renderer/components/ui/toaster.tsx @@ -1,4 +1,4 @@ -"use client" +'use client' import { Toast, @@ -6,9 +6,9 @@ import { ToastDescription, ToastProvider, ToastTitle, - ToastViewport, -} from "@/components/ui/toast" -import { useToast } from "@/components/ui/use-toast" + ToastViewport +} from '@/components/ui/toast' +import { useToast } from '@/components/ui/use-toast' export function Toaster() { const { toasts } = useToast() diff --git a/desktop-app/renderer/components/ui/use-toast.ts b/desktop-app/renderer/components/ui/use-toast.ts index 90d8959b..9fc03dd9 100644 --- a/desktop-app/renderer/components/ui/use-toast.ts +++ b/desktop-app/renderer/components/ui/use-toast.ts @@ -1,10 +1,7 @@ // Inspired by react-hot-toast library -import * as React from "react" +import * as React from 'react' -import type { - ToastActionElement, - ToastProps, -} from "@/components/ui/toast" +import type { ToastActionElement, ToastProps } from '@/components/ui/toast' const TOAST_LIMIT = 1 const TOAST_REMOVE_DELAY = 1000000 @@ -17,10 +14,10 @@ type ToasterToast = ToastProps & { } const actionTypes = { - ADD_TOAST: "ADD_TOAST", - UPDATE_TOAST: "UPDATE_TOAST", - DISMISS_TOAST: "DISMISS_TOAST", - REMOVE_TOAST: "REMOVE_TOAST", + ADD_TOAST: 'ADD_TOAST', + UPDATE_TOAST: 'UPDATE_TOAST', + DISMISS_TOAST: 'DISMISS_TOAST', + REMOVE_TOAST: 'REMOVE_TOAST' } as const let count = 0 @@ -34,20 +31,20 @@ type ActionType = typeof actionTypes type Action = | { - type: ActionType["ADD_TOAST"] + type: ActionType['ADD_TOAST'] toast: ToasterToast } | { - type: ActionType["UPDATE_TOAST"] + type: ActionType['UPDATE_TOAST'] toast: Partial } | { - type: ActionType["DISMISS_TOAST"] - toastId?: ToasterToast["id"] + type: ActionType['DISMISS_TOAST'] + toastId?: ToasterToast['id'] } | { - type: ActionType["REMOVE_TOAST"] - toastId?: ToasterToast["id"] + type: ActionType['REMOVE_TOAST'] + toastId?: ToasterToast['id'] } interface State { @@ -64,8 +61,8 @@ const addToRemoveQueue = (toastId: string) => { const timeout = setTimeout(() => { toastTimeouts.delete(toastId) dispatch({ - type: "REMOVE_TOAST", - toastId: toastId, + type: 'REMOVE_TOAST', + toastId: toastId }) }, TOAST_REMOVE_DELAY) @@ -74,21 +71,21 @@ const addToRemoveQueue = (toastId: string) => { export const reducer = (state: State, action: Action): State => { switch (action.type) { - case "ADD_TOAST": + case 'ADD_TOAST': return { ...state, - toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), + toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT) } - case "UPDATE_TOAST": + case 'UPDATE_TOAST': return { ...state, toasts: state.toasts.map((t) => t.id === action.toast.id ? { ...t, ...action.toast } : t - ), + ) } - case "DISMISS_TOAST": { + case 'DISMISS_TOAST': { const { toastId } = action // ! Side effects ! - This could be extracted into a dismissToast() action, @@ -107,22 +104,22 @@ export const reducer = (state: State, action: Action): State => { t.id === toastId || toastId === undefined ? { ...t, - open: false, + open: false } : t - ), + ) } } - case "REMOVE_TOAST": + case 'REMOVE_TOAST': if (action.toastId === undefined) { return { ...state, - toasts: [], + toasts: [] } } return { ...state, - toasts: state.toasts.filter((t) => t.id !== action.toastId), + toasts: state.toasts.filter((t) => t.id !== action.toastId) } } } @@ -138,34 +135,34 @@ function dispatch(action: Action) { }) } -type Toast = Omit +type Toast = Omit function toast({ ...props }: Toast) { const id = genId() const update = (props: ToasterToast) => dispatch({ - type: "UPDATE_TOAST", - toast: { ...props, id }, + type: 'UPDATE_TOAST', + toast: { ...props, id } }) - const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id }) dispatch({ - type: "ADD_TOAST", + type: 'ADD_TOAST', toast: { ...props, id, open: true, onOpenChange: (open) => { if (!open) dismiss() - }, - }, + } + } }) return { id: id, dismiss, - update, + update } } @@ -185,8 +182,8 @@ function useToast() { return { ...state, toast, - dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), + dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }) } } -export { useToast, toast } +export { toast, useToast } diff --git a/desktop-app/renderer/pages/bots/index.tsx b/desktop-app/renderer/pages/bots/index.tsx index 3508509f..6bf3c07d 100644 --- a/desktop-app/renderer/pages/bots/index.tsx +++ b/desktop-app/renderer/pages/bots/index.tsx @@ -1,28 +1,73 @@ -import React from 'react' import ContextHeader from '@/components/layout/contextHeader' import { Button } from '@/components/ui/button' import { ToastAction } from '@/components/ui/toast' import { useToast } from '@/components/ui/use-toast' - +import { + Card, + Metric, + Text, + Flex, + BadgeDelta, + DeltaType, + Grid +} from '@tremor/react' +const categories: { + title: string + metric: string + metricPrev: string + delta: string + deltaType: DeltaType +}[] = [ + { + title: 'Sales', + metric: '$ 12,699', + metricPrev: '$ 9,456', + delta: '34.3%', + deltaType: 'moderateIncrease' + }, + { + title: 'Profit', + metric: '$ 40,598', + metricPrev: '$ 45,564', + delta: '10.9%', + deltaType: 'moderateDecrease' + }, + { + title: 'Customers', + metric: '1,072', + metricPrev: '856', + delta: '25.3%', + deltaType: 'moderateIncrease' + } +] export default function Bots(): JSX.Element { const { toast } = useToast() return ( - + + {categories.map((item) => ( + + + {item.title} + + {item.delta} + + + + {item.metric} + from {item.metricPrev} + + + ))} + ) } diff --git a/desktop-app/renderer/tailwind.config.js b/desktop-app/renderer/tailwind.config.js index 748793b6..cb5473e4 100644 --- a/desktop-app/renderer/tailwind.config.js +++ b/desktop-app/renderer/tailwind.config.js @@ -1,37 +1,36 @@ /** @type {import('tailwindcss').Config} */ -const plugin = require("tailwindcss/plugin"); +const plugin = require('tailwindcss/plugin') const FlipPlugin = plugin(function ({ addUtilities }) { addUtilities({ - ".flip-y-180": { - transform: "rotateY(180deg)", + '.flip-y-180': { + transform: 'rotateY(180deg)' }, - ".flip-x-180": { - transform: "rotateX(180deg)", + '.flip-x-180': { + transform: 'rotateX(180deg)' }, - ".preserve-3d": { - transformStyle: "preserve-3d", + '.preserve-3d': { + transformStyle: 'preserve-3d' }, - ".perspective": { - perspective: "1000px", + '.perspective': { + perspective: '1000px' }, - ".backface-hidden": { - backfaceVisibility: "hidden", - }, - }); -}); - + '.backface-hidden': { + backfaceVisibility: 'hidden' + } + }) +}) module.exports = { content: [ './renderer/pages/**/*.{js,ts,jsx,tsx}', './renderer/components/**/*.{js,ts,jsx,tsx}', - './node_modules/@tremor/**/*.{js,ts,jsx,tsx}', // Tremor module + './node_modules/@tremor/**/*.{js,ts,jsx,tsx}' // Tremor module ], darkMode: ['class'], theme: { - transparent: "transparent", - current: "currentColor", + transparent: 'transparent', + current: 'currentColor', container: { center: true, padding: '2rem', @@ -77,84 +76,88 @@ module.exports = { // light mode tremor: { brand: { - faint: "#eff6ff", // blue-50 - muted: "#bfdbfe", // blue-200 - subtle: "#60a5fa", // blue-400 - DEFAULT: "#3b82f6", // blue-500 - emphasis: "#1d4ed8", // blue-700 - inverted: "#ffffff", // white + faint: '#eff6ff', // blue-50 + muted: '#bfdbfe', // blue-200 + subtle: '#60a5fa', // blue-400 + DEFAULT: '#3b82f6', // blue-500 + emphasis: '#1d4ed8', // blue-700 + inverted: '#ffffff' // white }, background: { - muted: "#f9fafb", // gray-50 - subtle: "#f3f4f6", // gray-100 - DEFAULT: "#ffffff", // white - emphasis: "#374151", // gray-700 + muted: '#f9fafb', // gray-50 + subtle: '#f3f4f6', // gray-100 + DEFAULT: '#ffffff', // white + emphasis: '#374151' // gray-700 }, border: { - DEFAULT: "#e5e7eb", // gray-200 + DEFAULT: '#e5e7eb' // gray-200 }, ring: { - DEFAULT: "#e5e7eb", // gray-200 + DEFAULT: '#e5e7eb' // gray-200 }, content: { - subtle: "#9ca3af", // gray-400 - DEFAULT: "#6b7280", // gray-500 - emphasis: "#374151", // gray-700 - strong: "#111827", // gray-900 - inverted: "#ffffff", // white - }, + subtle: '#9ca3af', // gray-400 + DEFAULT: '#6b7280', // gray-500 + emphasis: '#374151', // gray-700 + strong: '#111827', // gray-900 + inverted: '#ffffff' // white + } }, // dark mode - "dark-tremor": { + 'dark-tremor': { brand: { - faint: "#0B1229", // custom - muted: "#172554", // blue-950 - subtle: "#1e40af", // blue-800 - DEFAULT: "#3b82f6", // blue-500 - emphasis: "#60a5fa", // blue-400 - inverted: "#030712", // gray-950 + faint: '#0B1229', // custom + muted: '#172554', // blue-950 + subtle: '#1e40af', // blue-800 + DEFAULT: '#3b82f6', // blue-500 + emphasis: '#60a5fa', // blue-400 + inverted: '#030712' // gray-950 }, background: { - muted: "#131A2B", // custom - subtle: "#1f2937", // gray-800 - DEFAULT: "#111827", // gray-900 - emphasis: "#d1d5db", // gray-300 + muted: '#131A2B', // custom + subtle: '#1f2937', // gray-800 + DEFAULT: '#111827', // gray-900 + emphasis: '#d1d5db' // gray-300 }, border: { - DEFAULT: "#1f2937", // gray-800 + DEFAULT: '#1f2937' // gray-800 }, ring: { - DEFAULT: "#1f2937", // gray-800 + DEFAULT: '#1f2937' // gray-800 }, content: { - subtle: "#4b5563", // gray-600 - DEFAULT: "#6b7280", // gray-500 - emphasis: "#e5e7eb", // gray-200 - strong: "#f9fafb", // gray-50 - inverted: "#000000", // black - }, - }, + subtle: '#4b5563', // gray-600 + DEFAULT: '#6b7280', // gray-500 + emphasis: '#e5e7eb', // gray-200 + strong: '#f9fafb', // gray-50 + inverted: '#000000' // black + } + } }, boxShadow: { // light - "tremor-input": "0 1px 2px 0 rgb(0 0 0 / 0.05)", - "tremor-card": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)", - "tremor-dropdown": "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)", + 'tremor-input': '0 1px 2px 0 rgb(0 0 0 / 0.05)', + 'tremor-card': + '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)', + 'tremor-dropdown': + '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)', // dark - "dark-tremor-input": "0 1px 2px 0 rgb(0 0 0 / 0.05)", - "dark-tremor-card": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)", - "dark-tremor-dropdown": "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)", + 'dark-tremor-input': '0 1px 2px 0 rgb(0 0 0 / 0.05)', + 'dark-tremor-card': + '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)', + 'dark-tremor-dropdown': + '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)' }, fontSize: { - "tremor-label": ["0.75rem"], - "tremor-default": ["0.875rem", { lineHeight: "1.25rem" }], - "tremor-title": ["1.125rem", { lineHeight: "1.75rem" }], - "tremor-metric": ["1.875rem", { lineHeight: "2.25rem" }], + 'tremor-label': ['0.75rem'], + 'tremor-default': ['0.875rem', { lineHeight: '1.25rem' }], + 'tremor-title': ['1.125rem', { lineHeight: '1.75rem' }], + 'tremor-metric': ['1.875rem', { lineHeight: '2.25rem' }] }, borderRadius: { - "tremor-small": "0.375rem", - "tremor-default": "0.5rem", - "tremor-full": "0.1rem", + 'tremor-small': '0.375rem', + 'tremor-default': '0.5rem', + 'tremor-full': '0.1rem', lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', sm: 'calc(var(--radius) - 4px)' @@ -179,35 +182,34 @@ module.exports = { { pattern: /^(bg-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, - variants: ["hover", "ui-selected"], + variants: ['hover', 'ui-selected'] }, { pattern: /^(text-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, - variants: ["hover", "ui-selected"], + variants: ['hover', 'ui-selected'] }, { pattern: /^(border-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, - variants: ["hover", "ui-selected"], + variants: ['hover', 'ui-selected'] }, { pattern: - /^(ring-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, + /^(ring-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/ }, { pattern: - /^(stroke-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, + /^(stroke-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/ }, { pattern: - /^(fill-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, - }, + /^(fill-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/ + } ], - plugins: [require("@headlessui/tailwindcss"), require('tailwindcss-animate'), FlipPlugin] + plugins: [ + require('@headlessui/tailwindcss'), + require('tailwindcss-animate'), + FlipPlugin + ] } - - - - -