diff --git a/CHANGELOG.md b/CHANGELOG.md index e3039c5..c29f8aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,49 @@ +## 1.1.6-0 (2025-03-08) + +- chore(#53): fixed issue #53 code block is not functioning ([1ae28db](https://github.com/Your-Ehsan/Treo/commit/1ae28db)), closes [#53](https://github.com/Your-Ehsan/Treo/issues/53) +- Create CODE_OF_CONDUCT.md ([e2e1fbe](https://github.com/Your-Ehsan/Treo/commit/e2e1fbe)) +- Create FUNDING.yml ([7a9ade4](https://github.com/Your-Ehsan/Treo/commit/7a9ade4)) +- Create LICENSE ([624c867](https://github.com/Your-Ehsan/Treo/commit/624c867)) +- feat(#94): added delete functionality ([b1ce516](https://github.com/Your-Ehsan/Treo/commit/b1ce516)), closes [#94](https://github.com/Your-Ehsan/Treo/issues/94) +- feat(#95): pin to top feature implemented in clipboard ([33c8d10](https://github.com/Your-Ehsan/Treo/commit/33c8d10)), closes [#95](https://github.com/Your-Ehsan/Treo/issues/95) +- feat(#96): implmented the clear clipboard action in clipboard widget ([55f3650](https://github.com/Your-Ehsan/Treo/commit/55f3650)), closes [#96](https://github.com/Your-Ehsan/Treo/issues/96) +- fix(#51): disable commit message rule fixed ([5746bb0](https://github.com/Your-Ehsan/Treo/commit/5746bb0)), closes [#51](https://github.com/Your-Ehsan/Treo/issues/51) +- fix(#52): add favorite option in notes ([5b564c0](https://github.com/Your-Ehsan/Treo/commit/5b564c0)), closes [#52](https://github.com/Your-Ehsan/Treo/issues/52) +- fix(#64): make description optional while creating note ([ae11cc6](https://github.com/Your-Ehsan/Treo/commit/ae11cc6)), closes [#64](https://github.com/Your-Ehsan/Treo/issues/64) +- Update FUNDING.yml ([e8bf0c4](https://github.com/Your-Ehsan/Treo/commit/e8bf0c4)) +- refactor: refactor the clipboard-operations file ([45c68a1](https://github.com/Your-Ehsan/Treo/commit/45c68a1)) +- chore: implemented some coderrabbit suggestions ([091987b](https://github.com/Your-Ehsan/Treo/commit/091987b)) +- chore(build): build errors resolved & pre-commit hook updated ([75c7b59](https://github.com/Your-Ehsan/Treo/commit/75c7b59)) +- chore(deps-dev): bump @tailwindcss/postcss from 4.0.7 to 4.0.8 ([b39f396](https://github.com/Your-Ehsan/Treo/commit/b39f396)) +- chore(deps-dev): bump @tailwindcss/postcss from 4.0.8 to 4.0.9 ([a48ec08](https://github.com/Your-Ehsan/Treo/commit/a48ec08)) +- chore(deps-dev): bump @tanstack/router-devtools from 1.106.0 to 1.109.2 ([3ce69dc](https://github.com/Your-Ehsan/Treo/commit/3ce69dc)) +- chore(deps-dev): bump @tanstack/router-plugin from 1.105.5 to 1.109.2 ([8fa5cb2](https://github.com/Your-Ehsan/Treo/commit/8fa5cb2)) +- chore(deps-dev): bump @types/node from 22.13.4 to 22.13.5 ([c178fd9](https://github.com/Your-Ehsan/Treo/commit/c178fd9)) +- chore(deps-dev): bump @types/node from 22.13.5 to 22.13.8 ([8a1099e](https://github.com/Your-Ehsan/Treo/commit/8a1099e)) +- chore(deps-dev): bump drizzle-kit from 0.30.4 to 0.30.5 ([5166753](https://github.com/Your-Ehsan/Treo/commit/5166753)) +- chore(deps-dev): bump electron from 34.2.0 to 34.3.0 ([5d16c4d](https://github.com/Your-Ehsan/Treo/commit/5d16c4d)) +- chore(deps-dev): bump eslint from 9.20.1 to 9.21.0 ([5b81c22](https://github.com/Your-Ehsan/Treo/commit/5b81c22)) +- chore(deps-dev): bump eslint-plugin-react-hooks from 5.1.0 to 5.2.0 ([25af9e9](https://github.com/Your-Ehsan/Treo/commit/25af9e9)) +- chore(deps-dev): bump prettier from 3.5.1 to 3.5.2 ([358260a](https://github.com/Your-Ehsan/Treo/commit/358260a)) +- chore(deps-dev): bump tailwindcss from 4.0.7 to 4.0.8 ([74470f8](https://github.com/Your-Ehsan/Treo/commit/74470f8)) +- chore(deps-dev): bump tailwindcss from 4.0.8 to 4.0.9 ([af7674a](https://github.com/Your-Ehsan/Treo/commit/af7674a)) +- chore(deps-dev): bump vite from 6.1.1 to 6.2.0 ([f6c31b4](https://github.com/Your-Ehsan/Treo/commit/f6c31b4)) +- chore(deps): bump @hookform/resolvers from 4.1.0 to 4.1.1 ([e230987](https://github.com/Your-Ehsan/Treo/commit/e230987)) +- chore(deps): bump @hookform/resolvers from 4.1.1 to 4.1.2 ([7c37564](https://github.com/Your-Ehsan/Treo/commit/7c37564)) +- chore(deps): bump @tanstack/react-query from 5.66.7 to 5.66.8 ([8e20eca](https://github.com/Your-Ehsan/Treo/commit/8e20eca)) +- chore(deps): bump @tanstack/react-query from 5.66.8 to 5.66.9 ([2f8125a](https://github.com/Your-Ehsan/Treo/commit/2f8125a)) +- chore(deps): bump @tanstack/react-query from 5.66.9 to 5.66.11 ([d1dcb10](https://github.com/Your-Ehsan/Treo/commit/d1dcb10)) +- chore(deps): bump @tanstack/react-router from 1.106.0 to 1.109.2 ([3a2be1a](https://github.com/Your-Ehsan/Treo/commit/3a2be1a)) +- chore(deps): bump @tanstack/react-router from 1.109.2 to 1.111.3 ([7555757](https://github.com/Your-Ehsan/Treo/commit/7555757)) +- chore(deps): bump @tanstack/react-router from 1.111.3 to 1.112.0 ([c490453](https://github.com/Your-Ehsan/Treo/commit/c490453)) +- chore(deps): bump actions/labeler from 4 to 5 ([a0b0c89](https://github.com/Your-Ehsan/Treo/commit/a0b0c89)) +- chore(deps): bump drizzle-orm from 0.39.3 to 0.40.0 ([08dfcda](https://github.com/Your-Ehsan/Treo/commit/08dfcda)) +- chore(deps): bump lucide-react from 0.475.0 to 0.477.0 ([6582018](https://github.com/Your-Ehsan/Treo/commit/6582018)) +- chore(deps): bump react-medium-image-zoom from 5.2.13 to 5.2.14 ([30528f1](https://github.com/Your-Ehsan/Treo/commit/30528f1)) +- chore(deps): bump tailwind-merge from 3.0.1 to 3.0.2 ([908bc8c](https://github.com/Your-Ehsan/Treo/commit/908bc8c)) +- chore(refactor): removed some useless code ([ce8ecdb](https://github.com/Your-Ehsan/Treo/commit/ce8ecdb)) +- feat: add dependabot interval to weekly ([56c08f4](https://github.com/Your-Ehsan/Treo/commit/56c08f4)) + ## 1.1.5 (2025-02-20) - refactor(ui): all unnecessary ui removed ([ab3e3ec](https://github.com/Your-Ehsan/Treo/commit/ab3e3ec)) diff --git a/package.json b/package.json index 141171f..80c5df0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treo", - "version": "1.1.5", + "version": "1.1.6-0", "description": "An Electron application with React and TypeScript", "main": "./out/main/index.js", "author": "your-ehsan", @@ -38,6 +38,7 @@ "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^4.0.0", "@hookform/resolvers": "^4.1.2", + "@radix-ui/react-alert-dialog": "^1.1.6", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-collapsible": "^1.1.2", @@ -52,7 +53,7 @@ "@radix-ui/react-scroll-area": "^1.2.2", "@radix-ui/react-select": "^2.1.5", "@radix-ui/react-separator": "^1.1.1", - "@radix-ui/react-slot": "^1.1.1", + "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-switch": "^1.1.2", "@radix-ui/react-tabs": "^1.1.2", "@radix-ui/react-toast": "^1.2.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4cc3e70..4435da5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@hookform/resolvers': specifier: ^4.1.2 version: 4.1.3(react-hook-form@7.54.2(react@19.0.0)) + '@radix-ui/react-alert-dialog': + specifier: ^1.1.6 + version: 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@radix-ui/react-avatar': specifier: ^1.1.2 version: 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -60,7 +63,7 @@ importers: specifier: ^1.1.1 version: 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@radix-ui/react-slot': - specifier: ^1.1.1 + specifier: ^1.1.2 version: 1.1.2(@types/react@19.0.10)(react@19.0.0) '@radix-ui/react-switch': specifier: ^1.1.2 @@ -1268,6 +1271,19 @@ packages: '@radix-ui/primitive@1.1.1': resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} + '@radix-ui/react-alert-dialog@1.1.6': + resolution: {integrity: sha512-p4XnPqgej8sZAAReCAKgz1REYZEBLR8hU9Pg27wFnCWIMc8g1ccCs0FjBcy05V15VTu8pAePw/VDYeOm/uZ6yQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-arrow@1.1.2': resolution: {integrity: sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==} peerDependencies: @@ -6263,6 +6279,20 @@ snapshots: '@radix-ui/primitive@1.1.1': {} + '@radix-ui/react-alert-dialog@1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-dialog': 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) + '@radix-ui/react-arrow@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) diff --git a/src/main/index.ts b/src/main/index.ts index 114011c..a93e70d 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -18,6 +18,7 @@ import { updateNote } from './utils/notes-operations' import { + clearClipboard, deleteClipboardEntry, searchClipboard, togglePinnedClipboardEntry @@ -137,6 +138,7 @@ app.whenReady().then(() => { ipcMain.handle('toggle-favorite-note', (_, values) => toggleFavoriteNote(values)) ipcMain.handle('toggle-pinned-clipboard-entry', (_, values) => togglePinnedClipboardEntry(values)) ipcMain.handle('delete-clipboard-entry', (_, values) => deleteClipboardEntry(values)) + ipcMain.handle('clear-clipboard', clearClipboard) let previousContent = clipboard.readText() async function checkClipboard(): Promise { diff --git a/src/main/utils/clipboard-operations.ts b/src/main/utils/clipboard-operations.ts index a7a3da0..d02e428 100644 --- a/src/main/utils/clipboard-operations.ts +++ b/src/main/utils/clipboard-operations.ts @@ -6,7 +6,7 @@ import { and, between, desc, eq, like, sql } from 'drizzle-orm' // Function to search clipboard entries with pagination export async function searchClipboard({ searchTerm, - fromDate = Date.now() - 24 * 60 * 60 * 1000 * 7, // 7 days before + fromDate = Date.now() - 24 * 60 * 60 * 1000 * 30, // 30 days before toDate = Date.now(), limit = 10, // Default limit (page size) page = 1 // Default page number @@ -78,3 +78,16 @@ export async function togglePinnedClipboardEntry({ return { error } } } + +export async function clearClipboard(): Promise<{ + result?: string + error?: unknown +}> { + try { + await db.delete(clipboardSchema) + return { result: 'success' } + } catch (error) { + console.error(error) + return { error } + } +} diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index c42e8eb..299fbc6 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -81,6 +81,10 @@ interface RendererAPI { result?: string error?: unknown }> + clearClipboard: () => Promise<{ + result?: string + error?: unknown + }> } // Extend the global Window interface to include the Electron API and custom API diff --git a/src/preload/index.ts b/src/preload/index.ts index f785b43..bf8863a 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -20,7 +20,8 @@ const api = { toggleFavoriteNote: (values): Promise => ipcRenderer.invoke('toggle-favorite-note', values), togglePinnedClipboardEntry: (values): Promise => ipcRenderer.invoke('toggle-pinned-clipboard-entry', values), - deleteClipboardEntry: (id): Promise => ipcRenderer.invoke('delete-clipboard-entry', id) + deleteClipboardEntry: (id): Promise => ipcRenderer.invoke('delete-clipboard-entry', id), + clearClipboard: (): Promise => ipcRenderer.invoke('clear-clipboard') } // Use `contextBridge` APIs to expose Electron APIs to // renderer only if context isolation is enabled, otherwise diff --git a/src/renderer/src/components/modals/clear-clipboard-alert.tsx b/src/renderer/src/components/modals/clear-clipboard-alert.tsx new file mode 100644 index 0000000..0c8bf01 --- /dev/null +++ b/src/renderer/src/components/modals/clear-clipboard-alert.tsx @@ -0,0 +1,58 @@ +import { mutationKeys } from '@renderer/constants/mutation-keys' +import { useMutation, useQueryClient } from '@tanstack/react-query' +import React from 'react' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle +} from '../ui/alert-dialog' +import { modalStore } from '@renderer/store/modal-store' +import { queryKeys } from '@renderer/constants/query-keys' +import { toast } from '@renderer/hooks/use-toast' +import { copyWidgetStore } from '@renderer/store/copy-widget-store' + +export function ClearClipboardAlert(): React.JSX.Element { + const { activeModal, closeModal } = modalStore() + const { searchQuery } = copyWidgetStore() + const queryClient = useQueryClient() + const { mutate } = useMutation({ + mutationKey: [mutationKeys['clear-clipboard']], + mutationFn: () => window.api.clearClipboard(), + onError(error) { + toast({ + title: 'Failed to Clear Clipboard ❌ ', + description: error.message, + variant: 'destructive' + }) + }, + onSettled() { + queryClient.invalidateQueries({ queryKey: [queryKeys['clipboard-data'], searchQuery] }) + toast({ + title: 'Clipboard successfully Cleared' + }) + } + }) + + return ( + closeModal()}> + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete all items from your clipboard + history. + + + + Cancel + mutate()}>Continue + + + + ) +} diff --git a/src/renderer/src/components/modals/index.tsx b/src/renderer/src/components/modals/index.tsx index 9e4e5b0..5dd9003 100644 --- a/src/renderer/src/components/modals/index.tsx +++ b/src/renderer/src/components/modals/index.tsx @@ -1,6 +1,10 @@ import React from 'react' -import { CreateNoteModal } from './create-note-modal' +import { ClearClipboardAlert } from './clear-clipboard-alert' export function ModalsProvider(): React.JSX.Element { - return + return ( + <> + + + ) } diff --git a/src/renderer/src/components/ui/alert-dialog.tsx b/src/renderer/src/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..7385163 --- /dev/null +++ b/src/renderer/src/components/ui/alert-dialog.tsx @@ -0,0 +1,142 @@ +import * as React from 'react' +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' +import { cn } from '@renderer/utils' +import { buttonVariants } from './button' + +function AlertDialog({ + ...props +}: React.ComponentProps): React.JSX.Element { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps): React.JSX.Element { + return +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps): React.JSX.Element { + return +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps): React.JSX.Element { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps): React.JSX.Element { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<'div'>): React.JSX.Element { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<'div'>): React.JSX.Element { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps): React.JSX.Element { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps): React.JSX.Element { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps): React.JSX.Element { + return +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps): React.JSX.Element { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel +} diff --git a/src/renderer/src/constants/mutation-keys.ts b/src/renderer/src/constants/mutation-keys.ts index 1f0e1fd..822bf5f 100644 --- a/src/renderer/src/constants/mutation-keys.ts +++ b/src/renderer/src/constants/mutation-keys.ts @@ -3,5 +3,6 @@ export const mutationKeys = { 'create-note': 'create-note', 'update-note': 'update-note', 'delete-clipboard-entry': 'delete-clipboard-entry', - 'pinned-clipboard-entry': 'pinned-clipboard-entry' + 'pinned-clipboard-entry': 'pinned-clipboard-entry', + 'clear-clipboard': 'clear-clipboard' } diff --git a/src/renderer/src/store/modal-store.ts b/src/renderer/src/store/modal-store.ts index 95b7c66..8cb5990 100644 --- a/src/renderer/src/store/modal-store.ts +++ b/src/renderer/src/store/modal-store.ts @@ -1,7 +1,7 @@ import { create } from 'zustand' // Define the keys for each modal (you can add more as needed) -export const modalKeys = ['create-note-modal'] as const +export const modalKeys = ['create-note-modal', 'clear-clipboard-dialog'] as const // Define the type for modal keys type ModalKey = (typeof modalKeys)[number] diff --git a/src/renderer/src/windows/copy-widget/app/components/widget-menu.tsx b/src/renderer/src/windows/copy-widget/app/components/widget-menu.tsx new file mode 100644 index 0000000..4142865 --- /dev/null +++ b/src/renderer/src/windows/copy-widget/app/components/widget-menu.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from '@renderer/components/ui/dropdown-menu' +import { ClipboardXIcon, MoreHorizontal } from 'lucide-react' +import { modalStore } from '@renderer/store/modal-store' + +export function WidgetMenu(): React.JSX.Element { + const { openModal } = modalStore() + return ( + + + + + + openModal('clear-clipboard-dialog')}> + + Clear Clipboard + + + + ) +} diff --git a/src/renderer/src/windows/copy-widget/app/index.tsx b/src/renderer/src/windows/copy-widget/app/index.tsx index 1a0dff3..72fde13 100644 --- a/src/renderer/src/windows/copy-widget/app/index.tsx +++ b/src/renderer/src/windows/copy-widget/app/index.tsx @@ -1,20 +1,21 @@ import { useRef, useEffect } from 'react' -import { LoaderCircleIcon, Loader2Icon } from 'lucide-react' +import { Loader2Icon } from 'lucide-react' import { Dialog, DialogContent } from '@renderer/components/ui/dialog' -import { Command, CommandEmpty, CommandInput, CommandList } from '@renderer/components/ui/command' -import { CommandLoading, Command as CommandPrimitive } from 'cmdk' +import { Command, CommandInput, CommandList } from '@renderer/components/ui/command' +import { Command as CommandPrimitive } from 'cmdk' import { cn } from '@renderer/utils' import { useInfiniteQuery } from '@tanstack/react-query' import { copyWidgetStore } from '@renderer/store/copy-widget-store' import { WidgetCommandItem } from './components/widget-command-item' import { queryKeys } from '@renderer/constants/query-keys' +import { WidgetMenu } from './components/widget-menu' export function CopyWidget(): React.JSX.Element { const listEndRef = useRef(null) const inputRef = useRef>(null) const itemRef = useRef>(null) const { state, searchQuery, setState, setSearchQuery } = copyWidgetStore() - const { data, isLoading, fetchNextPage, isFetchingNextPage, hasNextPage } = useInfiniteQuery({ + const { data, fetchNextPage, isFetchingNextPage, hasNextPage } = useInfiniteQuery({ queryKey: [queryKeys['clipboard-data'], searchQuery], queryFn: ({ pageParam }) => window.api.search({ page: pageParam, searchTerm: searchQuery, limit: 15 }), @@ -105,29 +106,24 @@ export function CopyWidget(): React.JSX.Element { return ( - - - {isLoading ? ( - - - - ) : ( - No results found. - )} - +
+ + +
+ {allItems.map((clipboardData) => ( @@ -15,6 +16,7 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( +