kaneo (minimalist kanban) fork to experiment adding a tangled integration github.com/usekaneo/kaneo
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: fix linting issues

Andrej 44cf37f2 aa5d86ac

+647 -588
+22 -22
apps/web/components.json
··· 1 1 { 2 - "$schema": "https://ui.shadcn.com/schema.json", 3 - "style": "new-york", 4 - "rsc": false, 5 - "tsx": true, 6 - "tailwind": { 7 - "config": "tailwind.config.js", 8 - "css": "src/index.css", 9 - "baseColor": "zinc", 10 - "cssVariables": true, 11 - "prefix": "" 12 - }, 13 - "iconLibrary": "lucide", 14 - "aliases": { 15 - "components": "@/components", 16 - "utils": "@/lib/cn", 17 - "ui": "@/components/ui", 18 - "lib": "@/lib", 19 - "hooks": "@/hooks" 20 - }, 21 - "registries": { 22 - "@coss": "https://coss.com/ui/r/{name}.json" 23 - } 2 + "$schema": "https://ui.shadcn.com/schema.json", 3 + "style": "new-york", 4 + "rsc": false, 5 + "tsx": true, 6 + "tailwind": { 7 + "config": "tailwind.config.js", 8 + "css": "src/index.css", 9 + "baseColor": "zinc", 10 + "cssVariables": true, 11 + "prefix": "" 12 + }, 13 + "iconLibrary": "lucide", 14 + "aliases": { 15 + "components": "@/components", 16 + "utils": "@/lib/cn", 17 + "ui": "@/components/ui", 18 + "lib": "@/lib", 19 + "hooks": "@/hooks" 20 + }, 21 + "registries": { 22 + "@coss": "https://coss.com/ui/r/{name}.json" 23 + } 24 24 }
+4 -4
apps/web/src/components/activity/comment-card.tsx
··· 30 30 Underline, 31 31 X, 32 32 } from "lucide-react"; 33 - import { toast } from "@/lib/toast"; 33 + import CustomSlashMenu from "@/components/blocknote/custom-slash-menu"; 34 34 import { useAuth } from "@/components/providers/auth-provider/hooks/use-auth"; 35 35 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 36 36 import { Button } from "@/components/ui/button"; 37 - import CustomSlashMenu from "@/components/blocknote/custom-slash-menu"; 37 + import { KbdSequence } from "@/components/ui/kbd"; 38 38 import { 39 39 HoverCard, 40 40 HoverCardContent, 41 41 HoverCardTrigger, 42 42 } from "@/components/ui/preview-card"; 43 - import { KbdSequence } from "@/components/ui/kbd"; 44 43 import { 45 44 Tooltip, 46 45 TooltipContent, ··· 50 49 import useUpdateComment from "@/hooks/mutations/comment/use-update-comment"; 51 50 import { getModifierKeyText } from "@/hooks/use-keyboard-shortcuts"; 52 51 import { cn } from "@/lib/cn"; 52 + import { toast } from "@/lib/toast"; 53 53 import { useUserPreferencesStore } from "@/store/user-preferences"; 54 54 55 55 type CommentCardProps = { ··· 227 227 <div className="w-full group"> 228 228 <div className="flex items-center gap-2 mb-2"> 229 229 <HoverCard> 230 - <HoverCardTrigger asChild> 230 + <HoverCardTrigger> 231 231 <div className="flex items-center gap-2 cursor-pointer"> 232 232 <Avatar className="h-6 w-6"> 233 233 <AvatarImage src={user?.image ?? ""} alt={user?.name || ""} />
+2 -2
apps/web/src/components/activity/comment-input.tsx
··· 25 25 Type, 26 26 Underline, 27 27 } from "lucide-react"; 28 - import { toast } from "@/lib/toast"; 28 + import CustomSlashMenu from "@/components/blocknote/custom-slash-menu"; 29 29 import { Button } from "@/components/ui/button"; 30 - import CustomSlashMenu from "@/components/blocknote/custom-slash-menu"; 31 30 import { KbdSequence } from "@/components/ui/kbd"; 32 31 import { 33 32 Tooltip, ··· 38 37 import useCreateComment from "@/hooks/mutations/comment/use-create-comment"; 39 38 import { getModifierKeyText } from "@/hooks/use-keyboard-shortcuts"; 40 39 import { cn } from "@/lib/cn"; 40 + import { toast } from "@/lib/toast"; 41 41 import { useUserPreferencesStore } from "@/store/user-preferences"; 42 42 43 43 type CommentInputProps = {
+2 -6
apps/web/src/components/auth/otp-sign-in-form.tsx
··· 2 2 import { useRouter } from "@tanstack/react-router"; 3 3 import { useState } from "react"; 4 4 import { useForm } from "react-hook-form"; 5 - import { toast } from "@/lib/toast"; 6 5 import { z } from "zod/v4"; 7 6 import { Button } from "@/components/ui/button"; 8 7 import { ··· 15 14 } from "@/components/ui/form"; 16 15 import { Input } from "@/components/ui/input"; 17 16 import { authClient } from "@/lib/auth-client"; 17 + import { toast } from "@/lib/toast"; 18 18 19 19 type OtpSignInFormProps = { 20 20 invitationId?: string; ··· 87 87 )} 88 88 /> 89 89 90 - <Button 91 - type="submit" 92 - disabled={isPending} 93 - className="w-full mt-4" 94 - > 90 + <Button type="submit" disabled={isPending} className="w-full mt-4"> 95 91 {isPending ? "Sending..." : "Send Verification Code"} 96 92 </Button> 97 93 </form>
+1 -1
apps/web/src/components/auth/sign-in-form.tsx
··· 2 2 import { Eye, EyeOff } from "lucide-react"; 3 3 import { useState } from "react"; 4 4 import { useForm } from "react-hook-form"; 5 - import { toast } from "@/lib/toast"; 6 5 import { z } from "zod/v4"; 7 6 import { Button } from "@/components/ui/button"; 8 7 import { ··· 15 14 } from "@/components/ui/form"; 16 15 import { Input } from "@/components/ui/input"; 17 16 import { authClient } from "@/lib/auth-client"; 17 + import { toast } from "@/lib/toast"; 18 18 19 19 export type SignInFormValues = { 20 20 email: string;
+2 -6
apps/web/src/components/auth/sign-up-form.tsx
··· 3 3 import { Eye, EyeOff } from "lucide-react"; 4 4 import { useState } from "react"; 5 5 import { useForm } from "react-hook-form"; 6 - import { toast } from "@/lib/toast"; 7 6 import { z } from "zod/v4"; 8 7 import { Button } from "@/components/ui/button"; 9 8 import { ··· 16 15 } from "@/components/ui/form"; 17 16 import { Input } from "@/components/ui/input"; 18 17 import { authClient } from "@/lib/auth-client"; 18 + import { toast } from "@/lib/toast"; 19 19 20 20 export type SignUpFormValues = { 21 21 email: string; ··· 151 151 /> 152 152 </div> 153 153 154 - <Button 155 - type="submit" 156 - disabled={isPending} 157 - className="w-full mt-4" 158 - > 154 + <Button type="submit" disabled={isPending} className="w-full mt-4"> 159 155 {isPending ? "Creating Account..." : "Create Account"} 160 156 </Button> 161 157 </form>
+1 -2
apps/web/src/components/backlog-list-view/backlog-task-row.tsx
··· 4 4 import { format } from "date-fns"; 5 5 import { Calendar, CalendarClock, CalendarX } from "lucide-react"; 6 6 import { type CSSProperties, useMemo, useState } from "react"; 7 - import { toast } from "@/lib/toast"; 8 7 import { 9 8 AlertDialog, 10 9 AlertDialogClose, 11 - 12 10 AlertDialogContent, 13 11 AlertDialogDescription, 14 12 AlertDialogFooter, ··· 22 20 import { cn } from "@/lib/cn"; 23 21 import { dueDateStatusColors, getDueDateStatus } from "@/lib/due-date-status"; 24 22 import { getPriorityIcon } from "@/lib/priority"; 23 + import { toast } from "@/lib/toast"; 25 24 import queryClient from "@/query-client"; 26 25 import useBacklogBulkSelectionStore from "@/store/backlog-bulk-selection"; 27 26 import useProjectStore from "@/store/project";
+1 -2
apps/web/src/components/backlog-list-view/index.tsx
··· 297 297 <div 298 298 className={cn( 299 299 "border-b border-border/50 transition-all duration-200 overflow-auto", 300 - showDropIndicator && 301 - "border-l-4 border-l-ring bg-accent/35", 300 + showDropIndicator && "border-l-4 border-l-ring bg-accent/35", 302 301 )} 303 302 > 304 303 <div className="flex items-center justify-between py-2 px-4 bg-muted/60 border-b border-border/50">
+3 -2
apps/web/src/components/blocknote/custom-slash-menu.tsx
··· 35 35 className={cn("kaneo-slash-menu-item", { 36 36 "is-selected": selectedIndex === index, 37 37 })} 38 - aria-selected={selectedIndex === index} 39 38 onMouseDown={(event) => event.preventDefault()} 40 39 onClick={() => onItemClick?.(item)} 41 40 > 42 - {item.icon && <span className="kaneo-slash-menu-icon">{item.icon}</span>} 41 + {item.icon && ( 42 + <span className="kaneo-slash-menu-icon">{item.icon}</span> 43 + )} 43 44 <span className="kaneo-slash-menu-title">{item.title}</span> 44 45 {shortcut && ( 45 46 <span className="kaneo-slash-menu-shortcut">{shortcut}</span>
+52 -32
apps/web/src/components/bulk-selection/backlog-bulk-toolbar.tsx
··· 6 6 Trash2, 7 7 X, 8 8 } from "lucide-react"; 9 - import { Fragment, type ReactNode, useEffect, useMemo, useState } from "react"; 10 - import { toast } from "@/lib/toast"; 9 + import { 10 + Fragment, 11 + type ReactNode, 12 + useCallback, 13 + useEffect, 14 + useMemo, 15 + useState, 16 + } from "react"; 11 17 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 12 18 import { 13 19 Command, ··· 33 39 import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 34 40 import { useGetActiveWorkspaceUsers } from "@/hooks/queries/workspace-users/use-get-active-workspace-users"; 35 41 import { getColumnIcon } from "@/lib/column"; 42 + import { toast } from "@/lib/toast"; 36 43 import useBacklogBulkSelectionStore from "@/store/backlog-bulk-selection"; 37 44 import useProjectStore from "@/store/project"; 38 45 import { Button } from "../ui/button"; ··· 81 88 return () => document.removeEventListener("keydown", handleKeyDown); 82 89 }, [selectAll, clearSelection]); 83 90 84 - const handleMoveToBoard = async (status: string) => { 85 - try { 86 - await bulkMoveToBoard({ 87 - taskIds: Array.from(selectedTaskIds), 88 - status, 89 - }); 90 - toast.success(`${selectedCount} tasks moved to board`); 91 - clearSelection(); 92 - } catch (_error) { 93 - toast.error("Failed to move tasks to board"); 94 - } 95 - }; 91 + const handleMoveToBoard = useCallback( 92 + async (status: string) => { 93 + try { 94 + await bulkMoveToBoard({ 95 + taskIds: Array.from(selectedTaskIds), 96 + status, 97 + }); 98 + toast.success(`${selectedCount} tasks moved to board`); 99 + clearSelection(); 100 + } catch (_error) { 101 + toast.error("Failed to move tasks to board"); 102 + } 103 + }, 104 + [bulkMoveToBoard, selectedTaskIds, selectedCount, clearSelection], 105 + ); 96 106 97 - const handleBulkDelete = async () => { 107 + const handleBulkDelete = useCallback(async () => { 98 108 if ( 99 109 !confirm(`Delete ${selectedCount} tasks? This action cannot be undone.`) 100 110 ) { ··· 109 119 } catch (_error) { 110 120 toast.error("Failed to delete tasks"); 111 121 } 112 - }; 122 + }, [bulkDelete, selectedTaskIds, selectedCount, clearSelection]); 113 123 114 - const handleBulkArchive = async () => { 124 + const handleBulkArchive = useCallback(async () => { 115 125 try { 116 126 await bulkArchive(Array.from(selectedTaskIds)); 117 127 toast.success(`${selectedCount} tasks archived`); ··· 120 130 } catch (_error) { 121 131 toast.error("Failed to archive tasks"); 122 132 } 123 - }; 133 + }, [bulkArchive, selectedTaskIds, selectedCount, clearSelection]); 124 134 125 - const handleBulkAssign = async (userId: string) => { 126 - try { 127 - await bulkAssign({ taskIds: Array.from(selectedTaskIds), userId }); 128 - toast.success(`${selectedCount} tasks assigned`); 129 - clearSelection(); 130 - setIsActionsOpen(false); 131 - } catch (_error) { 132 - toast.error("Failed to assign tasks"); 133 - } 134 - }; 135 - 136 - if (selectedCount === 0) return null; 135 + const handleBulkAssign = useCallback( 136 + async (userId: string) => { 137 + try { 138 + await bulkAssign({ taskIds: Array.from(selectedTaskIds), userId }); 139 + toast.success(`${selectedCount} tasks assigned`); 140 + clearSelection(); 141 + setIsActionsOpen(false); 142 + } catch (_error) { 143 + toast.error("Failed to assign tasks"); 144 + } 145 + }, 146 + [bulkAssign, selectedTaskIds, selectedCount, clearSelection], 147 + ); 137 148 138 149 const groupedItems = useMemo<BacklogActionGroup[]>( 139 150 () => [ ··· 182 193 })), 183 194 }, 184 195 ], 185 - [workspaceUsers?.members], 196 + [ 197 + workspaceUsers?.members, 198 + handleBulkDelete, 199 + handleBulkArchive, 200 + handleBulkAssign, 201 + ], 186 202 ); 203 + 204 + if (selectedCount === 0) return null; 187 205 188 206 return ( 189 207 <div className="fixed bottom-6 left-1/2 transform -translate-x-1/2 z-50"> ··· 263 281 )} 264 282 </CommandCollection> 265 283 </CommandGroup> 266 - {groupIndex < groupedItems.length - 1 && <CommandSeparator />} 284 + {groupIndex < groupedItems.length - 1 && ( 285 + <CommandSeparator /> 286 + )} 267 287 </Fragment> 268 288 )} 269 289 </CommandList>
+57 -32
apps/web/src/components/bulk-selection/bulk-toolbar.tsx
··· 1 1 import { Archive, ArrowDownToLine, Menu, Trash2, X } from "lucide-react"; 2 - import { Fragment, type ReactNode, useEffect, useMemo, useState } from "react"; 3 - import { toast } from "@/lib/toast"; 2 + import { 3 + Fragment, 4 + type ReactNode, 5 + useCallback, 6 + useEffect, 7 + useMemo, 8 + useState, 9 + } from "react"; 4 10 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 5 11 import { 6 12 Command, ··· 20 26 import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 21 27 import { useGetActiveWorkspaceUsers } from "@/hooks/queries/workspace-users/use-get-active-workspace-users"; 22 28 import { getColumnIcon } from "@/lib/column"; 29 + import { toast } from "@/lib/toast"; 23 30 import useBulkSelectionStore from "@/store/bulk-selection"; 24 31 import useProjectStore from "@/store/project"; 25 32 import { Button } from "../ui/button"; ··· 73 80 return () => document.removeEventListener("keydown", handleKeyDown); 74 81 }, [selectAll, clearSelection]); 75 82 76 - const handleMoveToBacklog = async () => { 83 + const handleMoveToBacklog = useCallback(async () => { 77 84 try { 78 85 await bulkMoveToBacklog(Array.from(selectedTaskIds)); 79 86 toast.success(`${selectedCount} tasks moved to backlog`); ··· 81 88 } catch (_error) { 82 89 toast.error("Failed to move tasks to backlog"); 83 90 } 84 - }; 91 + }, [bulkMoveToBacklog, selectedTaskIds, selectedCount, clearSelection]); 85 92 86 - const handleBulkDelete = async () => { 93 + const handleBulkDelete = useCallback(async () => { 87 94 if ( 88 95 !confirm(`Delete ${selectedCount} tasks? This action cannot be undone.`) 89 96 ) { ··· 98 105 } catch (_error) { 99 106 toast.error("Failed to delete tasks"); 100 107 } 101 - }; 108 + }, [bulkDelete, selectedTaskIds, selectedCount, clearSelection]); 102 109 103 - const handleBulkArchive = async () => { 110 + const handleBulkArchive = useCallback(async () => { 104 111 try { 105 112 await bulkArchive(Array.from(selectedTaskIds)); 106 113 toast.success(`${selectedCount} tasks archived`); ··· 109 116 } catch (_error) { 110 117 toast.error("Failed to archive tasks"); 111 118 } 112 - }; 119 + }, [bulkArchive, selectedTaskIds, selectedCount, clearSelection]); 113 120 114 - const handleBulkChangeStatus = async (status: string) => { 115 - try { 116 - await bulkChangeStatus({ taskIds: Array.from(selectedTaskIds), status }); 117 - toast.success(`${selectedCount} tasks updated`); 118 - clearSelection(); 119 - setIsActionsOpen(false); 120 - } catch (_error) { 121 - toast.error("Failed to update tasks"); 122 - } 123 - }; 121 + const handleBulkChangeStatus = useCallback( 122 + async (status: string) => { 123 + try { 124 + await bulkChangeStatus({ 125 + taskIds: Array.from(selectedTaskIds), 126 + status, 127 + }); 128 + toast.success(`${selectedCount} tasks updated`); 129 + clearSelection(); 130 + setIsActionsOpen(false); 131 + } catch (_error) { 132 + toast.error("Failed to update tasks"); 133 + } 134 + }, 135 + [bulkChangeStatus, selectedTaskIds, selectedCount, clearSelection], 136 + ); 124 137 125 - const handleBulkAssign = async (userId: string) => { 126 - try { 127 - await bulkAssign({ taskIds: Array.from(selectedTaskIds), userId }); 128 - toast.success(`${selectedCount} tasks assigned`); 129 - clearSelection(); 130 - setIsActionsOpen(false); 131 - } catch (_error) { 132 - toast.error("Failed to assign tasks"); 133 - } 134 - }; 135 - 136 - if (selectedCount === 0) return null; 138 + const handleBulkAssign = useCallback( 139 + async (userId: string) => { 140 + try { 141 + await bulkAssign({ taskIds: Array.from(selectedTaskIds), userId }); 142 + toast.success(`${selectedCount} tasks assigned`); 143 + clearSelection(); 144 + setIsActionsOpen(false); 145 + } catch (_error) { 146 + toast.error("Failed to assign tasks"); 147 + } 148 + }, 149 + [bulkAssign, selectedTaskIds, selectedCount, clearSelection], 150 + ); 137 151 138 152 const groupedItems = useMemo<BulkActionGroup[]>( 139 153 () => [ ··· 194 208 })), 195 209 }, 196 210 ], 197 - [project?.columns, workspaceUsers?.members, selectedCount], 211 + [ 212 + project?.columns, 213 + workspaceUsers?.members, 214 + handleBulkDelete, 215 + handleBulkArchive, 216 + handleBulkChangeStatus, 217 + handleBulkAssign, 218 + ], 198 219 ); 220 + 221 + if (selectedCount === 0) return null; 199 222 200 223 return ( 201 224 <div className="fixed bottom-6 left-1/2 transform -translate-x-1/2 z-50"> ··· 259 282 )} 260 283 </CommandCollection> 261 284 </CommandGroup> 262 - {groupIndex < groupedItems.length - 1 && <CommandSeparator />} 285 + {groupIndex < groupedItems.length - 1 && ( 286 + <CommandSeparator /> 287 + )} 263 288 </Fragment> 264 289 )} 265 290 </CommandList>
+21 -13
apps/web/src/components/command-palette/index.tsx
··· 1 1 import { useNavigate } from "@tanstack/react-router"; 2 - import { 3 - ArrowDownIcon, 4 - ArrowUpIcon, 5 - CornerDownLeftIcon, 6 - } from "lucide-react"; 7 - import { Fragment, useEffect, useMemo, useState } from "react"; 2 + import { ArrowDownIcon, ArrowUpIcon, CornerDownLeftIcon } from "lucide-react"; 3 + import { Fragment, useCallback, useEffect, useMemo, useState } from "react"; 8 4 import SearchCommandMenu from "@/components/search-command-menu"; 9 5 import CreateTaskModal from "@/components/shared/modals/create-task-modal"; 10 6 import CreateWorkspaceModal from "@/components/shared/modals/create-workspace-modal"; ··· 89 85 }, 90 86 }); 91 87 92 - const runCommand = (command: () => void) => { 88 + const runCommand = useCallback((command: () => void) => { 93 89 command(); 94 90 setOpen(false); 95 - }; 91 + }, []); 96 92 97 93 const groupedItems = useMemo<PaletteGroup[]>( 98 94 () => [ ··· 191 187 for (const group of groupedItems) { 192 188 for (const item of group.items) { 193 189 if (!item.shortcut) continue; 194 - handlers.set(item.shortcut.replace(/\s+/g, "").toLowerCase(), item.onRun); 190 + handlers.set( 191 + item.shortcut.replace(/\s+/g, "").toLowerCase(), 192 + item.onRun, 193 + ); 195 194 } 196 195 } 197 196 return handlers; ··· 204 203 let timeout: ReturnType<typeof setTimeout> | undefined; 205 204 206 205 const onKeyDown = (event: KeyboardEvent) => { 207 - if (event.metaKey || event.ctrlKey || event.altKey || event.key === "Shift") { 206 + if ( 207 + event.metaKey || 208 + event.ctrlKey || 209 + event.altKey || 210 + event.key === "Shift" 211 + ) { 208 212 return; 209 213 } 210 214 ··· 232 236 clearTimeout(timeout); 233 237 document.removeEventListener("keydown", onKeyDown); 234 238 }; 235 - }, [open, shortcutHandlers]); 239 + }, [open, shortcutHandlers, runCommand]); 236 240 237 241 return ( 238 242 <> ··· 258 262 > 259 263 <span className="flex-1">{item.label}</span> 260 264 {item.shortcut && ( 261 - <CommandShortcut>{item.shortcut}</CommandShortcut> 265 + <CommandShortcut> 266 + {item.shortcut} 267 + </CommandShortcut> 262 268 )} 263 269 </CommandItem> 264 270 ); 265 271 }} 266 272 </CommandCollection> 267 273 </CommandGroup> 268 - {groupIndex < groupedItems.length - 1 && <CommandSeparator />} 274 + {groupIndex < groupedItems.length - 1 && ( 275 + <CommandSeparator /> 276 + )} 269 277 </Fragment> 270 278 )} 271 279 </CommandList>
+1 -1
apps/web/src/components/kanban-board/task-card-context-menu/task-card-context-menu-content.tsx
··· 1 1 import { X } from "lucide-react"; 2 2 import { useMemo } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 5 4 import { Calendar } from "@/components/ui/calendar"; 6 5 import { ··· 23 22 import { getColumnIcon } from "@/lib/column"; 24 23 import { generateLink } from "@/lib/generate-link"; 25 24 import { getPriorityIcon } from "@/lib/priority"; 25 + import { toast } from "@/lib/toast"; 26 26 import useProjectStore from "@/store/project"; 27 27 import type Task from "@/types/task"; 28 28
+2 -3
apps/web/src/components/list-view/index.tsx
··· 22 22 import { produce } from "immer"; 23 23 import { Archive, ChevronRight, Flag, Plus } from "lucide-react"; 24 24 import { useEffect, useState } from "react"; 25 - import { toast } from "@/lib/toast"; 26 25 import { priorityColorsTaskCard } from "@/constants/priority-colors"; 27 26 import { useUpdateTask } from "@/hooks/mutations/task/use-update-task"; 28 27 import { useRegisterShortcuts } from "@/hooks/use-keyboard-shortcuts"; 29 28 import { cn } from "@/lib/cn"; 30 29 import { getColumnIcon } from "@/lib/column"; 31 30 import toKebabCase from "@/lib/to-kebab-case"; 31 + import { toast } from "@/lib/toast"; 32 32 import useBulkSelectionStore from "@/store/bulk-selection"; 33 33 import useProjectStore from "@/store/project"; 34 34 import type { ProjectWithTasks } from "@/types/project"; ··· 266 266 <div 267 267 className={cn( 268 268 "border-b border-border/50 transition-all duration-200 overflow-auto", 269 - showDropIndicator && 270 - "border-l-4 border-l-ring bg-accent/35", 269 + showDropIndicator && "border-l-4 border-l-ring bg-accent/35", 271 270 )} 272 271 > 273 272 <div className="flex items-center justify-between py-2 px-4 bg-muted/60 border-b border-border/50">
+1 -2
apps/web/src/components/list-view/task-row.tsx
··· 10 10 GitPullRequest, 11 11 } from "lucide-react"; 12 12 import { type CSSProperties, useMemo, useState } from "react"; 13 - import { toast } from "@/lib/toast"; 14 13 import { 15 14 AlertDialog, 16 15 AlertDialogClose, 17 - 18 16 AlertDialogContent, 19 17 AlertDialogDescription, 20 18 AlertDialogFooter, ··· 34 32 import { cn } from "@/lib/cn"; 35 33 import { dueDateStatusColors, getDueDateStatus } from "@/lib/due-date-status"; 36 34 import { getPriorityIcon } from "@/lib/priority"; 35 + import { toast } from "@/lib/toast"; 37 36 import queryClient from "@/query-client"; 38 37 import useBulkSelectionStore from "@/store/bulk-selection"; 39 38 import useProjectStore from "@/store/project";
+1 -2
apps/web/src/components/notification/notification-dropdown.tsx
··· 4 4 import { 5 5 AlertDialog, 6 6 AlertDialogClose, 7 - 8 7 AlertDialogContent, 9 8 AlertDialogDescription, 10 9 AlertDialogFooter, ··· 13 12 } from "@/components/ui/alert-dialog"; 14 13 import { Badge } from "@/components/ui/badge"; 15 14 import { Button } from "@/components/ui/button"; 15 + import { KbdSequence } from "@/components/ui/kbd"; 16 16 import { 17 17 DropdownMenu, 18 18 DropdownMenuContent, 19 19 DropdownMenuTrigger, 20 20 } from "@/components/ui/menu"; 21 - import { KbdSequence } from "@/components/ui/kbd"; 22 21 import { 23 22 Tooltip, 24 23 TooltipContent,
+1 -2
apps/web/src/components/onboarding/onboarding-flow.tsx
··· 5 5 import { CheckCircle2 } from "lucide-react"; 6 6 import { useState } from "react"; 7 7 import { useForm } from "react-hook-form"; 8 - import { toast } from "@/lib/toast"; 9 8 import { z } from "zod/v4"; 10 - 11 9 import { Logo } from "@/components/common/logo"; 12 10 import PageTitle from "@/components/page-title"; 13 11 import useAuth from "@/components/providers/auth-provider/hooks/use-auth"; ··· 23 21 import { Input } from "@/components/ui/input"; 24 22 import useCreateWorkspace from "@/hooks/queries/workspace/use-create-workspace"; 25 23 import { authClient } from "@/lib/auth-client"; 24 + import { toast } from "@/lib/toast"; 26 25 27 26 type OnboardingStep = "workspace" | "success"; 28 27
+1 -2
apps/web/src/components/profile-setup/profile-setup-flow.tsx
··· 5 5 import { CheckCircle2, User } from "lucide-react"; 6 6 import { useState } from "react"; 7 7 import { useForm } from "react-hook-form"; 8 - import { toast } from "@/lib/toast"; 9 8 import { z } from "zod/v4"; 10 - 11 9 import { Logo } from "@/components/common/logo"; 12 10 import PageTitle from "@/components/page-title"; 13 11 import useAuth from "@/components/providers/auth-provider/hooks/use-auth"; ··· 22 20 } from "@/components/ui/form"; 23 21 import { Input } from "@/components/ui/input"; 24 22 import useUpdateUserProfile from "@/hooks/mutations/use-update-user-profile"; 23 + import { toast } from "@/lib/toast"; 25 24 26 25 type ProfileSetupStep = "profile" | "success"; 27 26
+1 -1
apps/web/src/components/project/column-editor.tsx
··· 1 1 import { CheckCircle2, Circle, GripVertical, Plus, Trash2 } from "lucide-react"; 2 2 import { useState } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import { Button } from "@/components/ui/button"; 5 4 import { Input } from "@/components/ui/input"; 6 5 import { Switch } from "@/components/ui/switch"; ··· 9 8 import { useReorderColumns } from "@/hooks/mutations/column/use-reorder-columns"; 10 9 import { useUpdateColumn } from "@/hooks/mutations/column/use-update-column"; 11 10 import { useGetColumns } from "@/hooks/queries/column/use-get-columns"; 11 + import { toast } from "@/lib/toast"; 12 12 13 13 type ColumnEditorProps = { 14 14 projectId: string;
+1 -1
apps/web/src/components/project/github-integration-settings.tsx
··· 13 13 } from "lucide-react"; 14 14 import React from "react"; 15 15 import { useForm } from "react-hook-form"; 16 - import { toast } from "@/lib/toast"; 17 16 import { z } from "zod/v4"; 18 17 import { RepositoryBrowserModal } from "@/components/project/repository-browser-modal"; 19 18 import { Badge } from "@/components/ui/badge"; ··· 37 36 import useImportGithubIssues from "@/hooks/mutations/github-integration/use-import-github-issues"; 38 37 import useGetGithubIntegration from "@/hooks/queries/github-integration/use-get-github-integration"; 39 38 import { cn } from "@/lib/cn"; 39 + import { toast } from "@/lib/toast"; 40 40 41 41 const githubIntegrationSchema = z.object({ 42 42 repositoryOwner: z
+72 -68
apps/web/src/components/project/tasks-import-export.tsx
··· 2 2 import { saveAs } from "file-saver"; 3 3 import { Download, Loader2, Upload, X } from "lucide-react"; 4 4 import { useRef, useState } from "react"; 5 - import { toast } from "@/lib/toast"; 6 5 import { Button } from "@/components/ui/button"; 7 - import { Dialog, DialogClose, DialogPopup, DialogTitle } from "@/components/ui/dialog"; 6 + import { 7 + Dialog, 8 + DialogClose, 9 + DialogPopup, 10 + DialogTitle, 11 + } from "@/components/ui/dialog"; 8 12 import useExportTasks from "@/hooks/mutations/task/use-export-tasks"; 9 13 import useImportTasks from "@/hooks/mutations/task/use-import-tasks"; 10 14 import { cn } from "@/lib/cn"; 15 + import { toast } from "@/lib/toast"; 11 16 import type { ProjectWithTasks } from "@/types/project"; 12 17 13 18 type TasksImportExportProps = { ··· 154 159 </div> 155 160 156 161 <Dialog open={isImportOpen} onOpenChange={resetAndCloseModal}> 157 - <DialogPopup className="w-full max-w-md"> 158 - <div className="bg-card rounded-lg shadow-xl border border-border"> 159 - <div className="flex items-center justify-between p-4 border-b border-border"> 160 - <DialogTitle className="text-lg font-semibold text-foreground"> 161 - Import Tasks 162 - </DialogTitle> 163 - <DialogClose 164 - className="text-muted-foreground hover:text-foreground" 165 - render={<button type="button" />} 166 - > 167 - <X size={20} className="cursor-pointer" /> 168 - </DialogClose> 169 - </div> 162 + <DialogPopup className="w-full max-w-md"> 163 + <div className="bg-card rounded-lg shadow-xl border border-border"> 164 + <div className="flex items-center justify-between p-4 border-b border-border"> 165 + <DialogTitle className="text-lg font-semibold text-foreground"> 166 + Import Tasks 167 + </DialogTitle> 168 + <DialogClose 169 + className="text-muted-foreground hover:text-foreground" 170 + render={<button type="button" />} 171 + > 172 + <X size={20} className="cursor-pointer" /> 173 + </DialogClose> 174 + </div> 170 175 171 - <div className="p-4"> 172 - <p className="text-sm text-muted-foreground mb-2"> 173 - Upload a JSON file containing tasks to import into this 174 - project. 175 - </p> 176 + <div className="p-4"> 177 + <p className="text-sm text-muted-foreground mb-2"> 178 + Upload a JSON file containing tasks to import into this project. 179 + </p> 176 180 177 - <div className="mb-4 p-3 bg-muted rounded-md border border-border/50 font-mono text-sm"> 178 - <p className="text-muted-foreground mb-1 text-xs"> 179 - Expected format: 180 - </p> 181 - <pre className="text-foreground overflow-auto max-h-32 text-xs"> 182 - {`{ 181 + <div className="mb-4 p-3 bg-muted rounded-md border border-border/50 font-mono text-sm"> 182 + <p className="text-muted-foreground mb-1 text-xs"> 183 + Expected format: 184 + </p> 185 + <pre className="text-foreground overflow-auto max-h-32 text-xs"> 186 + {`{ 183 187 "tasks": [ 184 188 { 185 189 "title": "Task title", ··· 191 195 } 192 196 ] 193 197 }`} 194 - </pre> 198 + </pre> 199 + </div> 200 + 201 + {/** biome-ignore lint/a11y/noStaticElementInteractions: false positive for onDrop and onDragOver */} 202 + <div 203 + className={cn( 204 + "border-2 border-dashed rounded-lg p-8 text-center mb-4", 205 + "border-border", 206 + "hover:border-ring", 207 + "bg-muted/60", 208 + "transition-colors", 209 + )} 210 + onDrop={handleDrop} 211 + onDragOver={handleDragOver} 212 + > 213 + <div className="flex flex-col items-center justify-center gap-2"> 214 + <Upload className="h-8 w-8 text-muted-foreground" /> 215 + <p className="text-sm text-muted-foreground"> 216 + Drag and drop your JSON file here 217 + </p> 218 + <Button 219 + className="mt-2 bg-card hover:bg-accent text-foreground border border-border" 220 + size="sm" 221 + onClick={handleImportClick} 222 + disabled={isImporting} 223 + > 224 + {isImporting ? ( 225 + <Loader2 className="h-4 w-4 mr-2 animate-spin" /> 226 + ) : ( 227 + "Select File" 228 + )} 229 + </Button> 195 230 </div> 231 + </div> 196 232 197 - {/** biome-ignore lint/a11y/noStaticElementInteractions: false positive for onDrop and onDragOver */} 198 - <div 199 - className={cn( 200 - "border-2 border-dashed rounded-lg p-8 text-center mb-4", 201 - "border-border", 202 - "hover:border-ring", 203 - "bg-muted/60", 204 - "transition-colors", 205 - )} 206 - onDrop={handleDrop} 207 - onDragOver={handleDragOver} 233 + <div className="flex justify-end gap-2"> 234 + <DialogClose 235 + render={ 236 + <Button className="bg-card hover:bg-accent text-foreground border border-border" /> 237 + } 208 238 > 209 - <div className="flex flex-col items-center justify-center gap-2"> 210 - <Upload className="h-8 w-8 text-muted-foreground" /> 211 - <p className="text-sm text-muted-foreground"> 212 - Drag and drop your JSON file here 213 - </p> 214 - <Button 215 - className="mt-2 bg-card hover:bg-accent text-foreground border border-border" 216 - size="sm" 217 - onClick={handleImportClick} 218 - disabled={isImporting} 219 - > 220 - {isImporting ? ( 221 - <Loader2 className="h-4 w-4 mr-2 animate-spin" /> 222 - ) : ( 223 - "Select File" 224 - )} 225 - </Button> 226 - </div> 227 - </div> 228 - 229 - <div className="flex justify-end gap-2"> 230 - <DialogClose 231 - render={ 232 - <Button className="bg-card hover:bg-accent text-foreground border border-border" /> 233 - } 234 - > 235 - Cancel 236 - </DialogClose> 237 - </div> 239 + Cancel 240 + </DialogClose> 238 241 </div> 239 242 </div> 240 - </DialogPopup> 243 + </div> 244 + </DialogPopup> 241 245 </Dialog> 242 246 </div> 243 247 );
+1 -1
apps/web/src/components/project/workflow-editor.tsx
··· 1 - import { toast } from "@/lib/toast"; 2 1 import { 3 2 Select, 4 3 SelectContent, ··· 9 8 import { useUpsertWorkflowRule } from "@/hooks/mutations/workflow-rule/use-upsert-workflow-rule"; 10 9 import { useGetColumns } from "@/hooks/queries/column/use-get-columns"; 11 10 import { useGetWorkflowRules } from "@/hooks/queries/workflow-rule/use-get-workflow-rules"; 11 + import { toast } from "@/lib/toast"; 12 12 13 13 const GITHUB_EVENTS = [ 14 14 { eventType: "branch_push", label: "Branch Push" },
+1 -1
apps/web/src/components/public-project/copy-url-button.tsx
··· 1 1 import { Check, Copy } from "lucide-react"; 2 2 import { useState } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import { Button } from "@/components/ui/button"; 4 + import { toast } from "@/lib/toast"; 5 5 6 6 export function CopyUrlButton() { 7 7 const [copied, setCopied] = useState(false);
+172 -172
apps/web/src/components/public-project/task-detail-modal.tsx
··· 10 10 X, 11 11 } from "lucide-react"; 12 12 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 13 - import { Dialog, DialogClose, DialogPopup, DialogTitle } from "@/components/ui/dialog"; 13 + import { Dialog, DialogClose, DialogPopup } from "@/components/ui/dialog"; 14 14 import { dueDateStatusColors, getDueDateStatus } from "@/lib/due-date-status"; 15 15 import { getPriorityIcon } from "@/lib/priority"; 16 16 import type { ExternalLink } from "@/types/external-link"; ··· 73 73 74 74 return ( 75 75 <Dialog open={open} onOpenChange={onOpenChange}> 76 - <DialogPopup className="w-full max-w-3xl max-h-[85vh]"> 77 - <div className="bg-background border border-border rounded-lg flex flex-col max-h-[85vh] shadow-lg"> 78 - <div className="flex items-center justify-between p-4 border-b border-border shrink-0"> 79 - <div className="flex items-center gap-2 min-w-0 flex-1"> 80 - <span className="text-xs font-mono text-muted-foreground shrink-0"> 81 - {projectSlug.toUpperCase()}-{task.number} 82 - </span> 83 - <span className="text-xs text-muted-foreground px-1.5 py-0.5 bg-muted rounded capitalize shrink-0"> 84 - {task.status?.replace("-", " ")} 85 - </span> 86 - </div> 87 - <DialogClose 88 - className="shrink-0 p-1.5 hover:bg-muted rounded transition-colors" 89 - render={<button type="button" />} 90 - > 91 - <X className="w-4 h-4 text-muted-foreground" /> 92 - </DialogClose> 76 + <DialogPopup className="w-full max-w-3xl max-h-[85vh]"> 77 + <div className="bg-background border border-border rounded-lg flex flex-col max-h-[85vh] shadow-lg"> 78 + <div className="flex items-center justify-between p-4 border-b border-border shrink-0"> 79 + <div className="flex items-center gap-2 min-w-0 flex-1"> 80 + <span className="text-xs font-mono text-muted-foreground shrink-0"> 81 + {projectSlug.toUpperCase()}-{task.number} 82 + </span> 83 + <span className="text-xs text-muted-foreground px-1.5 py-0.5 bg-muted rounded capitalize shrink-0"> 84 + {task.status?.replace("-", " ")} 85 + </span> 93 86 </div> 87 + <DialogClose 88 + className="shrink-0 p-1.5 hover:bg-muted rounded transition-colors" 89 + render={<button type="button" />} 90 + > 91 + <X className="w-4 h-4 text-muted-foreground" /> 92 + </DialogClose> 93 + </div> 94 94 95 - <div className="flex-1 overflow-y-auto p-6 space-y-6"> 96 - <div className="space-y-4"> 97 - <h2 className="text-xl font-semibold text-foreground pr-8"> 98 - {task.title} 99 - </h2> 95 + <div className="flex-1 overflow-y-auto p-6 space-y-6"> 96 + <div className="space-y-4"> 97 + <h2 className="text-xl font-semibold text-foreground pr-8"> 98 + {task.title} 99 + </h2> 100 100 101 - <div className="flex flex-wrap gap-2"> 102 - {task.priority && ( 103 - <div className="flex items-center gap-1.5 px-2.5 py-1 text-xs bg-muted text-muted-foreground rounded-md"> 104 - {getPriorityIcon(task.priority)} 105 - <span className="capitalize">{task.priority}</span> 106 - </div> 107 - )} 101 + <div className="flex flex-wrap gap-2"> 102 + {task.priority && ( 103 + <div className="flex items-center gap-1.5 px-2.5 py-1 text-xs bg-muted text-muted-foreground rounded-md"> 104 + {getPriorityIcon(task.priority)} 105 + <span className="capitalize">{task.priority}</span> 106 + </div> 107 + )} 108 108 109 - {task.dueDate && ( 110 - <div 111 - className={`flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-md ${dueDateStatusColors[getDueDateStatus(task.dueDate)]}`} 112 - > 113 - {getDueDateStatus(task.dueDate) === "overdue" && ( 114 - <CalendarX className="w-3 h-3" /> 115 - )} 116 - {getDueDateStatus(task.dueDate) === "due-soon" && ( 117 - <CalendarClock className="w-3 h-3" /> 118 - )} 119 - {(getDueDateStatus(task.dueDate) === "far-future" || 120 - getDueDateStatus(task.dueDate) === "no-due-date") && ( 121 - <Calendar className="w-3 h-3" /> 122 - )} 123 - <span>Due {format(new Date(task.dueDate), "MMM d")}</span> 124 - </div> 125 - )} 109 + {task.dueDate && ( 110 + <div 111 + className={`flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-md ${dueDateStatusColors[getDueDateStatus(task.dueDate)]}`} 112 + > 113 + {getDueDateStatus(task.dueDate) === "overdue" && ( 114 + <CalendarX className="w-3 h-3" /> 115 + )} 116 + {getDueDateStatus(task.dueDate) === "due-soon" && ( 117 + <CalendarClock className="w-3 h-3" /> 118 + )} 119 + {(getDueDateStatus(task.dueDate) === "far-future" || 120 + getDueDateStatus(task.dueDate) === "no-due-date") && ( 121 + <Calendar className="w-3 h-3" /> 122 + )} 123 + <span>Due {format(new Date(task.dueDate), "MMM d")}</span> 124 + </div> 125 + )} 126 126 127 - {task.assigneeName && ( 128 - <div className="flex items-center gap-2 px-2.5 py-1 text-xs bg-muted text-muted-foreground rounded-md"> 129 - <Avatar className="h-4 w-4"> 130 - <AvatarImage 131 - src={task.assigneeImage ?? ""} 132 - alt={task.assigneeName ?? ""} 133 - /> 134 - <AvatarFallback className="text-[10px]"> 135 - {task.assigneeName.charAt(0).toUpperCase()} 136 - </AvatarFallback> 137 - </Avatar> 138 - <span>{task.assigneeName}</span> 139 - </div> 140 - )} 141 - </div> 127 + {task.assigneeName && ( 128 + <div className="flex items-center gap-2 px-2.5 py-1 text-xs bg-muted text-muted-foreground rounded-md"> 129 + <Avatar className="h-4 w-4"> 130 + <AvatarImage 131 + src={task.assigneeImage ?? ""} 132 + alt={task.assigneeName ?? ""} 133 + /> 134 + <AvatarFallback className="text-[10px]"> 135 + {task.assigneeName.charAt(0).toUpperCase()} 136 + </AvatarFallback> 137 + </Avatar> 138 + <span>{task.assigneeName}</span> 139 + </div> 140 + )} 142 141 </div> 142 + </div> 143 143 144 - {labels.length > 0 && ( 145 - <div className="space-y-2"> 146 - <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wide"> 147 - Labels 148 - </h3> 149 - <PublicTaskLabels labels={labels} /> 150 - </div> 151 - )} 144 + {labels.length > 0 && ( 145 + <div className="space-y-2"> 146 + <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wide"> 147 + Labels 148 + </h3> 149 + <PublicTaskLabels labels={labels} /> 150 + </div> 151 + )} 152 152 153 - {task.description && ( 154 - <div className="space-y-2"> 155 - <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wide"> 156 - Description 157 - </h3> 158 - <div className="text-sm text-foreground leading-relaxed bg-muted/30 p-4 rounded-md border border-border/50"> 159 - <MarkdownRenderer content={task.description} /> 160 - </div> 153 + {task.description && ( 154 + <div className="space-y-2"> 155 + <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wide"> 156 + Description 157 + </h3> 158 + <div className="text-sm text-foreground leading-relaxed bg-muted/30 p-4 rounded-md border border-border/50"> 159 + <MarkdownRenderer content={task.description} /> 161 160 </div> 162 - )} 161 + </div> 162 + )} 163 163 164 - {externalLinks.length > 0 && ( 165 - <div className="space-y-3"> 166 - <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wide"> 167 - External Links 168 - </h3> 169 - 170 - {pullRequests.length > 0 && ( 171 - <div className="space-y-2"> 172 - {pullRequests.map((pr) => { 173 - const status = getPRStatus(pr); 174 - const repoMatch = pr.url.match( 175 - /github\.com\/([^/]+\/[^/]+)\/pull/, 176 - ); 177 - const repoName = repoMatch ? repoMatch[1] : null; 178 - return ( 179 - <a 180 - key={pr.id} 181 - href={pr.url} 182 - target="_blank" 183 - rel="noopener noreferrer" 184 - className="flex items-center justify-between p-3 bg-muted/50 hover:bg-muted rounded-md border border-border/50 transition-colors group" 185 - > 186 - <div className="flex items-center gap-2.5 flex-1 min-w-0"> 187 - <div className="flex flex-col gap-0.5 flex-1 min-w-0"> 188 - <span className="text-sm font-medium text-foreground truncate"> 189 - {pr.title || "Pull Request"} 190 - </span> 191 - <span className="text-xs text-muted-foreground"> 192 - {repoName}#{pr.externalId} 193 - </span> 194 - </div> 195 - </div> 196 - <div className="flex items-center gap-2 shrink-0"> 197 - <span 198 - className={`text-xs font-medium flex items-center gap-1 ${status.className}`} 199 - > 200 - {status.icon} 201 - {status.label} 202 - </span> 203 - <ExternalLinkIcon className="w-3.5 h-3.5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" /> 204 - </div> 205 - </a> 206 - ); 207 - })} 208 - </div> 209 - )} 164 + {externalLinks.length > 0 && ( 165 + <div className="space-y-3"> 166 + <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wide"> 167 + External Links 168 + </h3> 210 169 211 - {issues.length > 0 && ( 212 - <div className="space-y-2"> 213 - {issues.map((issue) => ( 170 + {pullRequests.length > 0 && ( 171 + <div className="space-y-2"> 172 + {pullRequests.map((pr) => { 173 + const status = getPRStatus(pr); 174 + const repoMatch = pr.url.match( 175 + /github\.com\/([^/]+\/[^/]+)\/pull/, 176 + ); 177 + const repoName = repoMatch ? repoMatch[1] : null; 178 + return ( 214 179 <a 215 - key={issue.id} 216 - href={issue.url} 180 + key={pr.id} 181 + href={pr.url} 217 182 target="_blank" 218 183 rel="noopener noreferrer" 219 184 className="flex items-center justify-between p-3 bg-muted/50 hover:bg-muted rounded-md border border-border/50 transition-colors group" 220 185 > 221 186 <div className="flex items-center gap-2.5 flex-1 min-w-0"> 222 - <GitPullRequest className="w-3.5 h-3.5 text-muted-foreground" /> 223 187 <div className="flex flex-col gap-0.5 flex-1 min-w-0"> 224 188 <span className="text-sm font-medium text-foreground truncate"> 225 - {issue.title || "Issue"} 189 + {pr.title || "Pull Request"} 226 190 </span> 227 191 <span className="text-xs text-muted-foreground"> 228 - #{issue.externalId} 192 + {repoName}#{pr.externalId} 229 193 </span> 230 194 </div> 231 195 </div> 232 - <ExternalLinkIcon className="w-3.5 h-3.5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" /> 196 + <div className="flex items-center gap-2 shrink-0"> 197 + <span 198 + className={`text-xs font-medium flex items-center gap-1 ${status.className}`} 199 + > 200 + {status.icon} 201 + {status.label} 202 + </span> 203 + <ExternalLinkIcon className="w-3.5 h-3.5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" /> 204 + </div> 233 205 </a> 234 - ))} 235 - </div> 236 - )} 206 + ); 207 + })} 208 + </div> 209 + )} 237 210 238 - {branches.length > 0 && ( 239 - <div className="space-y-2"> 240 - {branches.map((branch) => ( 241 - <a 242 - key={branch.id} 243 - href={branch.url} 244 - target="_blank" 245 - rel="noopener noreferrer" 246 - className="flex items-center justify-between p-3 bg-muted/50 hover:bg-muted rounded-md border border-border/50 transition-colors group" 247 - > 248 - <div className="flex items-center gap-2.5 flex-1 min-w-0"> 249 - <GitBranch className="w-3.5 h-3.5 text-muted-foreground" /> 211 + {issues.length > 0 && ( 212 + <div className="space-y-2"> 213 + {issues.map((issue) => ( 214 + <a 215 + key={issue.id} 216 + href={issue.url} 217 + target="_blank" 218 + rel="noopener noreferrer" 219 + className="flex items-center justify-between p-3 bg-muted/50 hover:bg-muted rounded-md border border-border/50 transition-colors group" 220 + > 221 + <div className="flex items-center gap-2.5 flex-1 min-w-0"> 222 + <GitPullRequest className="w-3.5 h-3.5 text-muted-foreground" /> 223 + <div className="flex flex-col gap-0.5 flex-1 min-w-0"> 250 224 <span className="text-sm font-medium text-foreground truncate"> 251 - {branch.title || branch.externalId} 225 + {issue.title || "Issue"} 226 + </span> 227 + <span className="text-xs text-muted-foreground"> 228 + #{issue.externalId} 252 229 </span> 253 230 </div> 254 - <ExternalLinkIcon className="w-3.5 h-3.5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" /> 255 - </a> 256 - ))} 257 - </div> 258 - )} 259 - </div> 260 - )} 231 + </div> 232 + <ExternalLinkIcon className="w-3.5 h-3.5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" /> 233 + </a> 234 + ))} 235 + </div> 236 + )} 261 237 262 - <div className="grid grid-cols-2 gap-4 pt-4 border-t border-border/50"> 238 + {branches.length > 0 && ( 239 + <div className="space-y-2"> 240 + {branches.map((branch) => ( 241 + <a 242 + key={branch.id} 243 + href={branch.url} 244 + target="_blank" 245 + rel="noopener noreferrer" 246 + className="flex items-center justify-between p-3 bg-muted/50 hover:bg-muted rounded-md border border-border/50 transition-colors group" 247 + > 248 + <div className="flex items-center gap-2.5 flex-1 min-w-0"> 249 + <GitBranch className="w-3.5 h-3.5 text-muted-foreground" /> 250 + <span className="text-sm font-medium text-foreground truncate"> 251 + {branch.title || branch.externalId} 252 + </span> 253 + </div> 254 + <ExternalLinkIcon className="w-3.5 h-3.5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" /> 255 + </a> 256 + ))} 257 + </div> 258 + )} 259 + </div> 260 + )} 261 + 262 + <div className="grid grid-cols-2 gap-4 pt-4 border-t border-border/50"> 263 + <div> 264 + <div className="text-xs text-muted-foreground mb-1"> 265 + Created 266 + </div> 267 + <div className="text-sm text-foreground"> 268 + {format(new Date(task.createdAt), "MMM d, yyyy")} 269 + </div> 270 + </div> 271 + {task.dueDate && ( 263 272 <div> 264 273 <div className="text-xs text-muted-foreground mb-1"> 265 - Created 274 + Due Date 266 275 </div> 267 276 <div className="text-sm text-foreground"> 268 - {format(new Date(task.createdAt), "MMM d, yyyy")} 277 + {format(new Date(task.dueDate), "MMM d, yyyy")} 269 278 </div> 270 279 </div> 271 - {task.dueDate && ( 272 - <div> 273 - <div className="text-xs text-muted-foreground mb-1"> 274 - Due Date 275 - </div> 276 - <div className="text-sm text-foreground"> 277 - {format(new Date(task.dueDate), "MMM d, yyyy")} 278 - </div> 279 - </div> 280 - )} 281 - </div> 280 + )} 282 281 </div> 283 282 </div> 284 - </DialogPopup> 283 + </div> 284 + </DialogPopup> 285 285 </Dialog> 286 286 ); 287 287 }
+1 -1
apps/web/src/components/settings/api-key-table.tsx
··· 1 1 import { Trash2 } from "lucide-react"; 2 2 import { useState } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import useDeleteApiKey from "@/hooks/mutations/api-key/use-delete-api-key"; 4 + import { toast } from "@/lib/toast"; 5 5 import type { ApiKey } from "@/types/api-key"; 6 6 import { Button } from "../ui/button"; 7 7 import {
+1 -1
apps/web/src/components/settings/create-api-key-dialog.tsx
··· 1 1 import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"; 2 2 import { useState } from "react"; 3 3 import { useForm } from "react-hook-form"; 4 - import { toast } from "@/lib/toast"; 5 4 import { z } from "zod"; 6 5 import useCreateApiKey from "@/hooks/mutations/api-key/use-create-api-key"; 6 + import { toast } from "@/lib/toast"; 7 7 import type { CreateApiKeyResponse } from "@/types/api-key"; 8 8 import { Button } from "../ui/button"; 9 9 import {
+1 -1
apps/web/src/components/shared/modals/create-project-modal.tsx
··· 1 1 import { useQueryClient } from "@tanstack/react-query"; 2 2 import { useNavigate } from "@tanstack/react-router"; 3 3 import { useState } from "react"; 4 - import { toast } from "@/lib/toast"; 5 4 import { 6 5 Breadcrumb, 7 6 BreadcrumbItem, ··· 28 27 import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 29 28 import { cn } from "@/lib/cn"; 30 29 import generateProjectSlug from "@/lib/generate-project-id"; 30 + import { toast } from "@/lib/toast"; 31 31 32 32 type CreateProjectModalProps = { 33 33 open: boolean;
+46 -10
apps/web/src/components/shared/modals/create-task-modal.tsx
··· 10 10 X, 11 11 } from "lucide-react"; 12 12 import { useCallback, useEffect, useRef, useState } from "react"; 13 - import { toast } from "@/lib/toast"; 14 13 import TaskDescriptionEditor from "@/components/task/task-description-editor"; 15 14 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 16 15 import { Badge } from "@/components/ui/badge"; ··· 42 41 import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 43 42 import { cn } from "@/lib/cn"; 44 43 import { getPriorityIcon } from "@/lib/priority"; 44 + import { toast } from "@/lib/toast"; 45 45 import useProjectStore from "@/store/project"; 46 46 47 47 type CreateTaskModalProps = { ··· 75 75 type PopoverStep = "select" | "color"; 76 76 77 77 const labelColors = [ 78 - { value: "gray" as LabelColor, label: "Stone", color: "var(--color-stone-500)" }, 79 - { value: "dark-gray" as LabelColor, label: "Slate", color: "var(--color-slate-500)" }, 80 - { value: "purple" as LabelColor, label: "Lavender", color: "var(--color-violet-500)" }, 81 - { value: "teal" as LabelColor, label: "Sage", color: "var(--color-emerald-600)" }, 82 - { value: "green" as LabelColor, label: "Forest", color: "var(--color-green-600)" }, 83 - { value: "yellow" as LabelColor, label: "Amber", color: "var(--color-amber-600)" }, 84 - { value: "orange" as LabelColor, label: "Terracotta", color: "var(--color-orange-600)" }, 85 - { value: "pink" as LabelColor, label: "Rose", color: "var(--color-rose-600)" }, 86 - { value: "red" as LabelColor, label: "Crimson", color: "var(--color-red-600)" }, 78 + { 79 + value: "gray" as LabelColor, 80 + label: "Stone", 81 + color: "var(--color-stone-500)", 82 + }, 83 + { 84 + value: "dark-gray" as LabelColor, 85 + label: "Slate", 86 + color: "var(--color-slate-500)", 87 + }, 88 + { 89 + value: "purple" as LabelColor, 90 + label: "Lavender", 91 + color: "var(--color-violet-500)", 92 + }, 93 + { 94 + value: "teal" as LabelColor, 95 + label: "Sage", 96 + color: "var(--color-emerald-600)", 97 + }, 98 + { 99 + value: "green" as LabelColor, 100 + label: "Forest", 101 + color: "var(--color-green-600)", 102 + }, 103 + { 104 + value: "yellow" as LabelColor, 105 + label: "Amber", 106 + color: "var(--color-amber-600)", 107 + }, 108 + { 109 + value: "orange" as LabelColor, 110 + label: "Terracotta", 111 + color: "var(--color-orange-600)", 112 + }, 113 + { 114 + value: "pink" as LabelColor, 115 + label: "Rose", 116 + color: "var(--color-rose-600)", 117 + }, 118 + { 119 + value: "red" as LabelColor, 120 + label: "Crimson", 121 + color: "var(--color-red-600)", 122 + }, 87 123 ]; 88 124 89 125 function CreateTaskModal({ open, onClose, status }: CreateTaskModalProps) {
+1 -1
apps/web/src/components/shared/modals/create-workspace-modal.tsx
··· 1 1 import { useQueryClient } from "@tanstack/react-query"; 2 2 import { useNavigate } from "@tanstack/react-router"; 3 3 import { useEffect, useRef, useState } from "react"; 4 - import { toast } from "@/lib/toast"; 5 4 import { 6 5 Breadcrumb, 7 6 BreadcrumbItem, ··· 20 19 import { Input } from "@/components/ui/input"; 21 20 import useCreateWorkspace from "@/hooks/queries/workspace/use-create-workspace"; 22 21 import { authClient } from "@/lib/auth-client"; 22 + import { toast } from "@/lib/toast"; 23 23 24 24 type CreateWorkspaceModalProps = { 25 25 open: boolean;
+1 -1
apps/web/src/components/task/task-assignee-popover.tsx
··· 1 1 import { Check } from "lucide-react"; 2 2 import { useCallback, useMemo, useState } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 5 4 import { Button } from "@/components/ui/button"; 6 5 import { ··· 12 11 import { useUpdateTaskAssignee } from "@/hooks/mutations/task/use-update-task-assignee"; 13 12 import { useGetActiveWorkspaceUsers } from "@/hooks/queries/workspace-users/use-get-active-workspace-users"; 14 13 import { useNumberedShortcuts } from "@/hooks/use-numbered-shortcuts"; 14 + import { toast } from "@/lib/toast"; 15 15 import type Task from "@/types/task"; 16 16 17 17 type TaskAssigneePopoverProps = {
+1 -2
apps/web/src/components/task/task-description-editor.tsx
··· 23 23 Type, 24 24 Underline, 25 25 } from "lucide-react"; 26 - 26 + import CustomSlashMenu from "@/components/blocknote/custom-slash-menu"; 27 27 import { Button } from "@/components/ui/button"; 28 - import CustomSlashMenu from "@/components/blocknote/custom-slash-menu"; 29 28 import { KbdSequence } from "@/components/ui/kbd"; 30 29 import { 31 30 Tooltip,
+1 -2
apps/web/src/components/task/task-description.tsx
··· 24 24 Type, 25 25 Underline, 26 26 } from "lucide-react"; 27 - 27 + import CustomSlashMenu from "@/components/blocknote/custom-slash-menu"; 28 28 import { Button } from "@/components/ui/button"; 29 - import CustomSlashMenu from "@/components/blocknote/custom-slash-menu"; 30 29 import { Form, FormControl, FormField } from "@/components/ui/form"; 31 30 import { KbdSequence } from "@/components/ui/kbd"; 32 31 import {
+1 -1
apps/web/src/components/task/task-due-date-popover.tsx
··· 1 1 import { X } from "lucide-react"; 2 2 import { useState } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import { Button } from "@/components/ui/button"; 5 4 import { Calendar } from "@/components/ui/calendar"; 6 5 import { ··· 9 8 PopoverTrigger, 10 9 } from "@/components/ui/popover"; 11 10 import { useUpdateTaskDueDate } from "@/hooks/mutations/task/use-update-task-due-date"; 11 + import { toast } from "@/lib/toast"; 12 12 import type Task from "@/types/task"; 13 13 14 14 type TaskDueDatePopoverProps = {
+1 -1
apps/web/src/components/task/task-labels-popover.tsx
··· 1 1 import { useQueryClient } from "@tanstack/react-query"; 2 2 import { Check, Plus, Search, X } from "lucide-react"; 3 3 import { useEffect, useMemo, useRef, useState } from "react"; 4 - import { toast } from "@/lib/toast"; 5 4 import { Input } from "@/components/ui/input"; 6 5 import { 7 6 Popover, ··· 13 12 import useGetLabelsByTask from "@/hooks/queries/label/use-get-labels-by-task"; 14 13 import useGetLabelsByWorkspace from "@/hooks/queries/label/use-get-labels-by-workspace"; 15 14 import { cn } from "@/lib/cn"; 15 + import { toast } from "@/lib/toast"; 16 16 import type Task from "@/types/task"; 17 17 18 18 const labelColors = [
+1 -1
apps/web/src/components/task/task-priority-popover.tsx
··· 1 1 import { Check } from "lucide-react"; 2 2 import { useCallback, useMemo, useState } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import { Button } from "@/components/ui/button"; 5 4 import { 6 5 Popover, ··· 11 10 import { useUpdateTaskPriority } from "@/hooks/mutations/task/use-update-task-status-priority"; 12 11 import { useNumberedShortcuts } from "@/hooks/use-numbered-shortcuts"; 13 12 import { getPriorityIcon } from "@/lib/priority"; 13 + import { toast } from "@/lib/toast"; 14 14 import type Task from "@/types/task"; 15 15 16 16 type TaskPriorityPopoverProps = {
+1 -1
apps/web/src/components/task/task-properties-sidebar.tsx
··· 7 7 GitBranch, 8 8 Plus, 9 9 } from "lucide-react"; 10 - import { toast } from "@/lib/toast"; 11 10 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 12 11 import { Badge } from "@/components/ui/badge"; 13 12 import { Button } from "@/components/ui/button"; ··· 27 26 import { getColumnIcon } from "@/lib/column"; 28 27 import { dueDateStatusColors, getDueDateStatus } from "@/lib/due-date-status"; 29 28 import { getPriorityIcon } from "@/lib/priority"; 29 + import { toast } from "@/lib/toast"; 30 30 import TaskAssigneePopover from "./task-assignee-popover"; 31 31 import TaskDueDatePopover from "./task-due-date-popover"; 32 32 import TaskLabelsPopover from "./task-labels-popover";
+1 -1
apps/web/src/components/task/task-status-popover.tsx
··· 1 1 import { Check } from "lucide-react"; 2 2 import { useCallback, useMemo, useState } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import { Button } from "@/components/ui/button"; 5 4 import { 6 5 Popover, ··· 11 10 import { useUpdateTaskStatus } from "@/hooks/mutations/task/use-update-task-status"; 12 11 import { useNumberedShortcuts } from "@/hooks/use-numbered-shortcuts"; 13 12 import { getColumnIcon } from "@/lib/column"; 13 + import { toast } from "@/lib/toast"; 14 14 import useProjectStore from "@/store/project"; 15 15 import type Task from "@/types/task"; 16 16
+33 -35
apps/web/src/components/team/delete-team-member-modal.tsx
··· 34 34 return ( 35 35 <Dialog open={open} onOpenChange={onClose}> 36 36 <DialogPopup className="w-full max-w-md"> 37 - <div className="bg-card rounded-lg shadow-xl"> 38 - <div className="flex items-center justify-between p-4 border-b border-border"> 39 - <DialogTitle className="text-lg font-semibold text-foreground"> 40 - Remove Team Member 41 - </DialogTitle> 37 + <div className="bg-card rounded-lg shadow-xl"> 38 + <div className="flex items-center justify-between p-4 border-b border-border"> 39 + <DialogTitle className="text-lg font-semibold text-foreground"> 40 + Remove Team Member 41 + </DialogTitle> 42 + <DialogClose 43 + className="text-muted-foreground hover:text-foreground" 44 + render={<button type="button" />} 45 + > 46 + <X size={20} /> 47 + </DialogClose> 48 + </div> 49 + 50 + <div className="p-4"> 51 + <p className="text-sm text-muted-foreground mb-6"> 52 + Are you sure you want to remove{" "} 53 + <span className="font-medium text-foreground">{userId}</span> from 54 + the team? This action cannot be undone. 55 + </p> 56 + 57 + <div className="flex justify-end gap-2"> 42 58 <DialogClose 43 - className="text-muted-foreground hover:text-foreground" 44 - render={<button type="button" />} 59 + render={ 60 + <Button 61 + className="bg-muted text-foreground hover:bg-accent" 62 + type="button" 63 + /> 64 + } 45 65 > 46 - <X size={20} /> 66 + Cancel 47 67 </DialogClose> 48 - </div> 49 - 50 - <div className="p-4"> 51 - <p className="text-sm text-muted-foreground mb-6"> 52 - Are you sure you want to remove{" "} 53 - <span className="font-medium text-foreground"> 54 - {userId} 55 - </span>{" "} 56 - from the team? This action cannot be undone. 57 - </p> 58 - 59 - <div className="flex justify-end gap-2"> 60 - <DialogClose 61 - render={ 62 - <Button className="bg-muted text-foreground hover:bg-accent" type="button" /> 63 - } 64 - > 65 - Cancel 66 - </DialogClose> 67 - <Button 68 - onClick={onRemoveMember} 69 - variant="destructive" 70 - > 71 - <Trash2 className="w-4 h-4 mr-2" /> 72 - Remove Member 73 - </Button> 74 - </div> 68 + <Button onClick={onRemoveMember} variant="destructive"> 69 + <Trash2 className="w-4 h-4 mr-2" /> 70 + Remove Member 71 + </Button> 75 72 </div> 76 73 </div> 74 + </div> 77 75 </DialogPopup> 78 76 </Dialog> 79 77 );
+55 -54
apps/web/src/components/team/invite-team-member-modal.tsx
··· 2 2 import { useQueryClient } from "@tanstack/react-query"; 3 3 import { X } from "lucide-react"; 4 4 import { useForm } from "react-hook-form"; 5 - import { toast } from "@/lib/toast"; 6 5 import { z } from "zod/v4"; 7 6 import useInviteWorkspaceUser from "@/hooks/mutations/workspace-user/use-invite-workspace-user"; 7 + import { toast } from "@/lib/toast"; 8 8 import { Route } from "@/routes/_layout/_authenticated/dashboard/workspace/$workspaceId/members"; 9 9 import { Button } from "../ui/button"; 10 + import { Dialog, DialogClose, DialogPopup, DialogTitle } from "../ui/dialog"; 10 11 import { 11 12 Form, 12 13 FormControl, ··· 16 17 FormMessage, 17 18 } from "../ui/form"; 18 19 import { Input } from "../ui/input"; 19 - import { Dialog, DialogClose, DialogPopup, DialogTitle } from "../ui/dialog"; 20 20 21 21 type Props = { 22 22 open: boolean; ··· 74 74 return ( 75 75 <Dialog open={open} onOpenChange={resetAndCloseModal}> 76 76 <DialogPopup className="w-full max-w-md"> 77 - <div className="bg-card rounded-lg shadow-xl"> 78 - <div className="flex items-center justify-between p-4 border-b border-border"> 79 - <DialogTitle className="text-lg font-semibold text-foreground"> 80 - Invite Team Member 81 - </DialogTitle> 82 - <DialogClose 83 - className="text-muted-foreground hover:text-foreground" 84 - render={<button type="button" />} 85 - > 86 - <X size={20} /> 87 - </DialogClose> 88 - </div> 77 + <div className="bg-card rounded-lg shadow-xl"> 78 + <div className="flex items-center justify-between p-4 border-b border-border"> 79 + <DialogTitle className="text-lg font-semibold text-foreground"> 80 + Invite Team Member 81 + </DialogTitle> 82 + <DialogClose 83 + className="text-muted-foreground hover:text-foreground" 84 + render={<button type="button" />} 85 + > 86 + <X size={20} /> 87 + </DialogClose> 88 + </div> 89 89 90 - <Form {...form}> 91 - <form onSubmit={form.handleSubmit(onSubmit)} className="p-4"> 92 - <div className="space-y-4"> 93 - <div> 94 - <FormField 95 - control={form.control} 96 - name="email" 97 - render={({ field }) => ( 98 - <FormItem> 99 - <FormLabel className="block text-sm font-medium text-foreground mb-1"> 100 - Email 101 - </FormLabel> 102 - <FormControl> 103 - <Input 104 - {...field} 105 - placeholder="colleague@company.com" 106 - className="bg-card/50" 107 - autoFocus 108 - /> 109 - </FormControl> 110 - <FormMessage /> 111 - </FormItem> 112 - )} 113 - /> 114 - </div> 90 + <Form {...form}> 91 + <form onSubmit={form.handleSubmit(onSubmit)} className="p-4"> 92 + <div className="space-y-4"> 93 + <div> 94 + <FormField 95 + control={form.control} 96 + name="email" 97 + render={({ field }) => ( 98 + <FormItem> 99 + <FormLabel className="block text-sm font-medium text-foreground mb-1"> 100 + Email 101 + </FormLabel> 102 + <FormControl> 103 + <Input 104 + {...field} 105 + placeholder="colleague@company.com" 106 + className="bg-card/50" 107 + autoFocus 108 + /> 109 + </FormControl> 110 + <FormMessage /> 111 + </FormItem> 112 + )} 113 + /> 115 114 </div> 115 + </div> 116 116 117 - <div className="flex justify-end gap-2 mt-6"> 118 - <DialogClose 119 - render={ 120 - <Button className="bg-muted text-foreground hover:bg-accent" type="button" /> 121 - } 122 - > 123 - Cancel 124 - </DialogClose> 125 - <Button type="submit"> 126 - Send Invitation 127 - </Button> 128 - </div> 129 - </form> 130 - </Form> 131 - </div> 117 + <div className="flex justify-end gap-2 mt-6"> 118 + <DialogClose 119 + render={ 120 + <Button 121 + className="bg-muted text-foreground hover:bg-accent" 122 + type="button" 123 + /> 124 + } 125 + > 126 + Cancel 127 + </DialogClose> 128 + <Button type="submit">Send Invitation</Button> 129 + </div> 130 + </form> 131 + </Form> 132 + </div> 132 133 </DialogPopup> 133 134 </Dialog> 134 135 );
+2 -5
apps/web/src/components/team/members-table.tsx
··· 1 1 import { Trash2 } from "lucide-react"; 2 2 import { useState } from "react"; 3 - import { toast } from "@/lib/toast"; 4 3 import useCancelInvitation from "@/hooks/mutations/workspace-user/use-cancel-invitation"; 5 4 import useDeleteWorkspaceUser from "@/hooks/mutations/workspace-user/use-delete-workspace-user"; 5 + import { toast } from "@/lib/toast"; 6 6 import { Route } from "@/routes/_layout/_authenticated/dashboard/workspace/$workspaceId/members"; 7 7 import type { 8 8 WorkspaceUser, ··· 12 12 import { 13 13 AlertDialog, 14 14 AlertDialogClose, 15 - 16 15 AlertDialogContent, 17 16 AlertDialogDescription, 18 17 AlertDialogFooter, ··· 277 276 </AlertDialogDescription> 278 277 </AlertDialogHeader> 279 278 <AlertDialogFooter> 280 - <AlertDialogClose disabled={isCancelling}> 281 - Cancel 282 - </AlertDialogClose> 279 + <AlertDialogClose disabled={isCancelling}>Cancel</AlertDialogClose> 283 280 <AlertDialogClose 284 281 onClick={handleCancelInvitation} 285 282 disabled={isCancelling}
+1 -2
apps/web/src/components/ui/autocomplete.tsx
··· 2 2 3 3 import { Autocomplete as AutocompletePrimitive } from "@base-ui/react/autocomplete"; 4 4 import { ChevronsUpDownIcon, XIcon } from "lucide-react"; 5 - 6 - import { cn } from "@/lib/cn"; 7 5 import { Input } from "@/components/ui/input"; 8 6 import { ScrollArea } from "@/components/ui/scroll-area"; 7 + import { cn } from "@/lib/cn"; 9 8 10 9 const Autocomplete = AutocompletePrimitive.Root; 11 10
+1 -2
apps/web/src/components/ui/badge.tsx
··· 23 23 variant: { 24 24 default: 25 25 "bg-primary text-primary-foreground [button&,a&]:hover:bg-primary/90", 26 - destructive: 27 - "bg-destructive [button&,a&]:hover:bg-destructive/90", 26 + destructive: "bg-destructive [button&,a&]:hover:bg-destructive/90", 28 27 error: 29 28 "bg-destructive/8 text-destructive-foreground dark:bg-destructive/16", 30 29 info: "bg-info/8 text-info-foreground dark:bg-info/16",
+2
apps/web/src/components/ui/checkbox.tsx
··· 21 21 <span {...props}> 22 22 {state.indeterminate ? ( 23 23 <svg 24 + aria-hidden="true" 24 25 className="size-3.5 sm:size-3" 25 26 fill="none" 26 27 height="24" ··· 36 37 </svg> 37 38 ) : ( 38 39 <svg 40 + aria-hidden="true" 39 41 className="size-3.5 sm:size-3" 40 42 fill="none" 41 43 height="24"
+2 -2
apps/web/src/components/ui/combobox.tsx
··· 3 3 import { Combobox as ComboboxPrimitive } from "@base-ui/react/combobox"; 4 4 import { ChevronsUpDownIcon, XIcon } from "lucide-react"; 5 5 import * as React from "react"; 6 - 7 - import { cn } from "@/lib/cn"; 8 6 import { Input } from "@/components/ui/input"; 9 7 import { ScrollArea } from "@/components/ui/scroll-area"; 8 + import { cn } from "@/lib/cn"; 10 9 11 10 const ComboboxContext = React.createContext<{ 12 11 chipsRef: React.RefObject<Element | null> | null; ··· 205 204 > 206 205 <ComboboxPrimitive.ItemIndicator className="col-start-1"> 207 206 <svg 207 + aria-hidden="true" 208 208 fill="none" 209 209 height="24" 210 210 stroke="currentColor"
+1 -1
apps/web/src/components/ui/command.tsx
··· 3 3 import { Dialog as CommandDialogPrimitive } from "@base-ui/react/dialog"; 4 4 import { SearchIcon } from "lucide-react"; 5 5 import type * as React from "react"; 6 - import { cn } from "@/lib/cn"; 7 6 import { 8 7 Autocomplete, 9 8 AutocompleteCollection, ··· 15 14 AutocompleteList, 16 15 AutocompleteSeparator, 17 16 } from "@/components/ui/autocomplete"; 17 + import { cn } from "@/lib/cn"; 18 18 19 19 const CommandDialog = CommandDialogPrimitive.Root; 20 20
+1 -1
apps/web/src/components/ui/dialog.tsx
··· 2 2 3 3 import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"; 4 4 import { XIcon } from "lucide-react"; 5 - import { cn } from "@/lib/cn"; 6 5 import { Button } from "@/components/ui/button"; 7 6 import { ScrollArea } from "@/components/ui/scroll-area"; 7 + import { cn } from "@/lib/cn"; 8 8 9 9 const DialogCreateHandle = DialogPrimitive.createHandle; 10 10
+1 -3
apps/web/src/components/ui/error-display.tsx
··· 67 67 key={`step-${index}-${step.slice(0, 10)}`} 68 68 className="flex items-start gap-2" 69 69 > 70 - <span className="text-muted-foreground mt-0.5"> 71 - 72 - </span> 70 + <span className="text-muted-foreground mt-0.5">•</span> 73 71 <span>{step}</span> 74 72 </li> 75 73 ))}
+14 -7
apps/web/src/components/ui/form.tsx
··· 4 4 import * as React from "react"; 5 5 import { 6 6 Controller, 7 - FormProvider, 8 - useFormContext, 9 7 type ControllerProps, 10 8 type FieldPath, 11 9 type FieldValues, 10 + FormProvider, 11 + useFormContext, 12 12 } from "react-hook-form"; 13 - 13 + import { Label } from "@/components/ui/label"; 14 14 import { cn } from "@/lib/cn"; 15 - import { Label } from "@/components/ui/label"; 16 15 17 16 const Form = FormProvider; 18 17 ··· 85 84 ); 86 85 } 87 86 88 - function FormLabel({ className, ...props }: React.ComponentProps<typeof Label>) { 87 + function FormLabel({ 88 + className, 89 + ...props 90 + }: React.ComponentProps<typeof Label>) { 89 91 const { error, formItemId } = useFormField(); 90 92 91 93 return ( ··· 99 101 } 100 102 101 103 function FormControl({ ...props }: React.ComponentProps<typeof Slot>) { 102 - const { error, formDescriptionId, formItemId, formMessageId } = useFormField(); 104 + const { error, formDescriptionId, formItemId, formMessageId } = 105 + useFormField(); 103 106 104 107 return ( 105 108 <Slot ··· 127 130 ); 128 131 } 129 132 130 - function FormMessage({ className, children, ...props }: React.ComponentProps<"p">) { 133 + function FormMessage({ 134 + className, 135 + children, 136 + ...props 137 + }: React.ComponentProps<"p">) { 131 138 const { error, formMessageId } = useFormField(); 132 139 const body = error ? String(error?.message ?? "") : children; 133 140
+1 -3
apps/web/src/components/ui/group.tsx
··· 4 4 import { useRender } from "@base-ui/react/use-render"; 5 5 import { cva, type VariantProps } from "class-variance-authority"; 6 6 import type * as React from "react"; 7 - 7 + import { Separator } from "@/components/ui/separator"; 8 8 import { cn } from "@/lib/cn"; 9 - import { Separator } from "@/components/ui/separator"; 10 9 11 10 const groupVariants = cva( 12 11 "flex w-fit *:focus-visible:z-1 has-[>[data-slot=group]]:gap-2 *:has-focus-visible:z-1 dark:*:[[data-slot=button]:hover~[data-slot=separator]:not([data-slot]:hover~[data-slot=separator]~[data-slot=separator]),[data-slot][data-pressed]~[data-slot=separator]:not([data-slot][data-pressed]~[data-slot=separator]~[data-slot=separator])]:before:bg-input/64 dark:*:[[data-slot=separator]:has(~[data-slot=button]:hover):not(:has(~[data-slot=separator]~[data-slot]:hover)),[data-slot=separator]:has(~[data-slot][data-pressed]):not(:has(~[data-slot=separator]~[data-slot][data-pressed]))]:before:bg-input/64", ··· 40 39 className={cn(groupVariants({ orientation }), className)} 41 40 data-orientation={orientation} 42 41 data-slot="group" 43 - role="group" 44 42 {...props} 45 43 > 46 44 {children}
+1 -18
apps/web/src/components/ui/input-group.tsx
··· 2 2 3 3 import { cva, type VariantProps } from "class-variance-authority"; 4 4 import type * as React from "react"; 5 - 6 - import { cn } from "@/lib/cn"; 7 5 import { Input, type InputProps } from "@/components/ui/input"; 8 6 import { Textarea, type TextareaProps } from "@/components/ui/textarea"; 7 + import { cn } from "@/lib/cn"; 9 8 10 9 function InputGroup({ className, ...props }: React.ComponentProps<"div">) { 11 10 return ( ··· 15 14 className, 16 15 )} 17 16 data-slot="input-group" 18 - role="group" 19 17 {...props} 20 18 /> 21 19 ); ··· 52 50 className={cn(inputGroupAddonVariants({ align }), className)} 53 51 data-align={align} 54 52 data-slot="input-group-addon" 55 - onMouseDown={(e) => { 56 - const target = e.target as HTMLElement; 57 - const isInteractive = target.closest( 58 - "button, a, input, select, textarea, [role='button'], [role='combobox'], [role='listbox'], [data-slot='select-trigger']", 59 - ); 60 - if (isInteractive) return; 61 - e.preventDefault(); 62 - const parent = e.currentTarget.parentElement; 63 - const input = parent?.querySelector< 64 - HTMLInputElement | HTMLTextAreaElement 65 - >("input, textarea"); 66 - if (input && !parent?.querySelector("input:focus, textarea:focus")) { 67 - input.focus(); 68 - } 69 - }} 70 53 {...props} 71 54 /> 72 55 );
+2
apps/web/src/components/ui/menu.tsx
··· 145 145 width="24" 146 146 xmlns="http://www.w3.org/2000/svg" 147 147 > 148 + <title>Check</title> 148 149 <path d="M5.252 12.7 10.2 18.63 18.748 5.37" /> 149 150 </svg> 150 151 </MenuPrimitive.CheckboxItemIndicator> ··· 185 186 width="24" 186 187 xmlns="http://www.w3.org/2000/svg" 187 188 > 189 + <title>Check</title> 188 190 <path d="M5.252 12.7 10.2 18.63 18.748 5.37" /> 189 191 </svg> 190 192 </MenuPrimitive.RadioItemIndicator>
+4 -1
apps/web/src/components/ui/menubar.tsx
··· 24 24 function Menubar({ className, ...props }: MenubarPrimitive.Props) { 25 25 return ( 26 26 <MenubarPrimitive 27 - className={cn("flex items-center gap-1 rounded-lg border bg-background p-1", className)} 27 + className={cn( 28 + "flex items-center gap-1 rounded-lg border bg-background p-1", 29 + className, 30 + )} 28 31 data-slot="menubar" 29 32 {...props} 30 33 />
+2 -2
apps/web/src/components/ui/number-field.tsx
··· 3 3 import { NumberField as NumberFieldPrimitive } from "@base-ui/react/number-field"; 4 4 import { MinusIcon, PlusIcon } from "lucide-react"; 5 5 import * as React from "react"; 6 - 6 + import { Label } from "@/components/ui/label"; 7 7 import { cn } from "@/lib/cn"; 8 - import { Label } from "@/components/ui/label"; 9 8 10 9 const NumberFieldContext = React.createContext<{ 11 10 fieldId: string; ··· 137 136 function CursorGrowIcon(props: React.ComponentProps<"svg">) { 138 137 return ( 139 138 <svg 139 + aria-hidden="true" 140 140 fill="black" 141 141 height="14" 142 142 stroke="white"
+1 -2
apps/web/src/components/ui/pagination.tsx
··· 8 8 MoreHorizontalIcon, 9 9 } from "lucide-react"; 10 10 import type * as React from "react"; 11 - 11 + import { type Button, buttonVariants } from "@/components/ui/button"; 12 12 import { cn } from "@/lib/cn"; 13 - import { type Button, buttonVariants } from "@/components/ui/button"; 14 13 15 14 function Pagination({ className, ...props }: React.ComponentProps<"nav">) { 16 15 return (
+1
apps/web/src/components/ui/select.tsx
··· 181 181 > 182 182 <SelectPrimitive.ItemIndicator className="col-start-1"> 183 183 <svg 184 + aria-hidden="true" 184 185 fill="none" 185 186 height="24" 186 187 stroke="currentColor"
+1 -1
apps/web/src/components/ui/sheet.tsx
··· 2 2 3 3 import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"; 4 4 import { XIcon } from "lucide-react"; 5 - import { cn } from "@/lib/cn"; 6 5 import { Button } from "@/components/ui/button"; 7 6 import { ScrollArea } from "@/components/ui/scroll-area"; 7 + import { cn } from "@/lib/cn"; 8 8 9 9 const Sheet = SheetPrimitive.Root; 10 10
+3 -7
apps/web/src/components/ui/sidebar.tsx
··· 5 5 import { cva, type VariantProps } from "class-variance-authority"; 6 6 import { PanelLeftIcon } from "lucide-react"; 7 7 import * as React from "react"; 8 - import { useIsMobile } from "@/hooks/use-mobile"; 9 - import { cn } from "@/lib/cn"; 10 8 import { Button } from "@/components/ui/button"; 11 9 import { Input } from "@/components/ui/input"; 12 10 import { ScrollArea } from "@/components/ui/scroll-area"; ··· 19 17 SheetTitle, 20 18 } from "@/components/ui/sheet"; 21 19 import { Skeleton } from "@/components/ui/skeleton"; 22 - import { 23 - Tooltip, 24 - TooltipPopup, 25 - TooltipTrigger, 26 - } from "@/components/ui/tooltip"; 20 + import { Tooltip, TooltipPopup, TooltipTrigger } from "@/components/ui/tooltip"; 21 + import { useIsMobile } from "@/hooks/use-mobile"; 22 + import { cn } from "@/lib/cn"; 27 23 28 24 const SIDEBAR_COOKIE_NAME = "sidebar_state"; 29 25 const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
+1 -2
apps/web/src/components/ui/toast.tsx
··· 8 8 LoaderCircleIcon, 9 9 TriangleAlertIcon, 10 10 } from "lucide-react"; 11 - 11 + import { buttonVariants } from "@/components/ui/button"; 12 12 import { cn } from "@/lib/cn"; 13 - import { buttonVariants } from "@/components/ui/button"; 14 13 15 14 const toastManager = Toast.createToastManager(); 16 15 const anchoredToastManager = Toast.createToastManager();
+1 -2
apps/web/src/components/ui/toggle-group.tsx
··· 4 4 import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group"; 5 5 import type { VariantProps } from "class-variance-authority"; 6 6 import * as React from "react"; 7 - 8 - import { cn } from "@/lib/cn"; 9 7 import { Separator } from "@/components/ui/separator"; 10 8 import { 11 9 Toggle as ToggleComponent, 12 10 type toggleVariants, 13 11 } from "@/components/ui/toggle"; 12 + import { cn } from "@/lib/cn"; 14 13 15 14 const ToggleGroupContext = React.createContext< 16 15 VariantProps<typeof toggleVariants>
+9 -3
apps/web/src/lib/priority.tsx
··· 13 13 <CircleAlert className="h-[12px] w-[12px] text-destructive-foreground" /> 14 14 ); 15 15 case "high": 16 - return <ChevronsUp className="h-[12px] w-[12px] text-warning-foreground" />; 16 + return ( 17 + <ChevronsUp className="h-[12px] w-[12px] text-warning-foreground" /> 18 + ); 17 19 case "medium": 18 - return <ChevronUp className="h-[12px] w-[12px] text-warning-foreground/80" />; 20 + return ( 21 + <ChevronUp className="h-[12px] w-[12px] text-warning-foreground/80" /> 22 + ); 19 23 case "low": 20 - return <ChevronDown className="h-[12px] w-[12px] text-info-foreground/85" />; 24 + return ( 25 + <ChevronDown className="h-[12px] w-[12px] text-info-foreground/85" /> 26 + ); 21 27 case "no-priority": 22 28 return <Minus className="h-[12px] w-[12px] text-muted-foreground" />; 23 29 default:
+1 -3
apps/web/src/lib/status.tsx
··· 3 3 export function getStatusIcon(status: "active" | "pending") { 4 4 switch (status) { 5 5 case "active": 6 - return ( 7 - <CheckCircle2 className="h-4 w-4 text-success-foreground" /> 8 - ); 6 + return <CheckCircle2 className="h-4 w-4 text-success-foreground" />; 9 7 case "pending": 10 8 return <Clock className="h-4 w-4 text-warning-foreground" />; 11 9 }
+6 -3
apps/web/src/lib/toast.ts
··· 42 42 43 43 type ToastFn = (title: string, options?: ToastOptions) => string; 44 44 45 - const success: ToastFn = (title, options) => addToast(title, "success", options); 45 + const success: ToastFn = (title, options) => 46 + addToast(title, "success", options); 46 47 const error: ToastFn = (title, options) => addToast(title, "error", options); 47 48 const info: ToastFn = (title, options) => addToast(title, "info", options); 48 - const warning: ToastFn = (title, options) => addToast(title, "warning", options); 49 - const message: ToastFn = (title, options) => addToast(title, undefined, options); 49 + const warning: ToastFn = (title, options) => 50 + addToast(title, "warning", options); 51 + const message: ToastFn = (title, options) => 52 + addToast(title, undefined, options); 50 53 51 54 const toast = Object.assign(message, { 52 55 success,
+1 -1
apps/web/src/routes/_layout/_authenticated/dashboard/invitations.tsx
··· 2 2 import { createFileRoute, useNavigate } from "@tanstack/react-router"; 3 3 import { CheckCircle, Loader2, Mail, X } from "lucide-react"; 4 4 import { useState } from "react"; 5 - import { toast } from "@/lib/toast"; 6 5 import Layout from "@/components/common/layout"; 7 6 import PageTitle from "@/components/page-title"; 8 7 import { Badge } from "@/components/ui/badge"; ··· 20 19 import { usePendingInvitations } from "@/hooks/queries/invitation/use-pending-invitations"; 21 20 import { authClient } from "@/lib/auth-client"; 22 21 import { cn } from "@/lib/cn"; 22 + import { toast } from "@/lib/toast"; 23 23 24 24 export const Route = createFileRoute( 25 25 "/_layout/_authenticated/dashboard/invitations",
+1 -1
apps/web/src/routes/_layout/_authenticated/dashboard/settings/account/information.tsx
··· 3 3 import { createFileRoute } from "@tanstack/react-router"; 4 4 import { useCallback, useEffect, useRef } from "react"; 5 5 import { useForm } from "react-hook-form"; 6 - import { toast } from "@/lib/toast"; 7 6 import { z } from "zod"; 8 7 import PageTitle from "@/components/page-title"; 9 8 import useAuth from "@/components/providers/auth-provider/hooks/use-auth"; ··· 19 18 import { Input } from "@/components/ui/input"; 20 19 import { Separator } from "@/components/ui/separator"; 21 20 import useUpdateUserProfile from "@/hooks/mutations/use-update-user-profile"; 21 + import { toast } from "@/lib/toast"; 22 22 23 23 export const Route = createFileRoute( 24 24 "/_layout/_authenticated/dashboard/settings/account/information",
+6 -2
apps/web/src/routes/_layout/_authenticated/dashboard/settings/account/preferences.tsx
··· 76 76 <div className="flex items-center gap-3"> 77 77 <div className="flex items-center gap-1 rounded-md border border-border bg-muted p-1"> 78 78 <span className="rounded-full size-2 bg-primary" /> 79 - <span className="text-xs font-normal text-foreground">Aa</span> 79 + <span className="text-xs font-normal text-foreground"> 80 + Aa 81 + </span> 80 82 </div> 81 83 <span className="text-xs font-normal">Light</span> 82 84 </div> ··· 85 87 <div className="flex items-center gap-3"> 86 88 <div className="flex items-center gap-1 rounded-md border border-border bg-card p-1"> 87 89 <span className="rounded-full size-2 bg-primary" /> 88 - <span className="text-xs font-normal text-foreground">Aa</span> 90 + <span className="text-xs font-normal text-foreground"> 91 + Aa 92 + </span> 89 93 </div> 90 94 <span className="text-xs font-normal">Dark</span> 91 95 </div>
+1 -2
apps/web/src/routes/_layout/_authenticated/dashboard/settings/projects/$projectId/general.tsx
··· 7 7 } from "@tanstack/react-router"; 8 8 import { useCallback, useEffect, useRef, useState } from "react"; 9 9 import { useForm } from "react-hook-form"; 10 - import { toast } from "@/lib/toast"; 11 10 import { z } from "zod"; 12 11 import PageTitle from "@/components/page-title"; 13 12 import { 14 13 AlertDialog, 15 14 AlertDialogClose, 16 - 17 15 AlertDialogContent, 18 16 AlertDialogDescription, 19 17 AlertDialogFooter, ··· 42 40 import useGetProject from "@/hooks/queries/project/use-get-project"; 43 41 import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 44 42 import { cn } from "@/lib/cn"; 43 + import { toast } from "@/lib/toast"; 45 44 46 45 export const Route = createFileRoute( 47 46 "/_layout/_authenticated/dashboard/settings/projects/$projectId/general",
+1 -1
apps/web/src/routes/_layout/_authenticated/dashboard/settings/projects/$projectId/visibility.tsx
··· 1 1 import { useQueryClient } from "@tanstack/react-query"; 2 2 import { createFileRoute, useParams } from "@tanstack/react-router"; 3 3 import { useCallback, useRef } from "react"; 4 - import { toast } from "@/lib/toast"; 5 4 import PageTitle from "@/components/page-title"; 6 5 import { Button } from "@/components/ui/button"; 7 6 import { Input } from "@/components/ui/input"; ··· 11 10 import useUpdateProject from "@/hooks/mutations/project/use-update-project"; 12 11 import useGetProject from "@/hooks/queries/project/use-get-project"; 13 12 import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 13 + import { toast } from "@/lib/toast"; 14 14 15 15 export const Route = createFileRoute( 16 16 "/_layout/_authenticated/dashboard/settings/projects/$projectId/visibility",
+1 -2
apps/web/src/routes/_layout/_authenticated/dashboard/settings/workspace/general.tsx
··· 3 3 import { createFileRoute, useNavigate } from "@tanstack/react-router"; 4 4 import { useCallback, useEffect, useRef, useState } from "react"; 5 5 import { useForm } from "react-hook-form"; 6 - import { toast } from "@/lib/toast"; 7 6 import { z } from "zod"; 8 7 import PageTitle from "@/components/page-title"; 9 8 import { 10 9 AlertDialog, 11 10 AlertDialogClose, 12 - 13 11 AlertDialogContent, 14 12 AlertDialogDescription, 15 13 AlertDialogFooter, ··· 30 28 import useDeleteWorkspace from "@/hooks/mutations/workspace/use-delete-workspace"; 31 29 import useUpdateWorkspace from "@/hooks/mutations/workspace/use-update-workspace"; 32 30 import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 31 + import { toast } from "@/lib/toast"; 33 32 34 33 export const Route = createFileRoute( 35 34 "/_layout/_authenticated/dashboard/settings/workspace/general",
+1 -4
apps/web/src/routes/_layout/_authenticated/dashboard/workspace/$workspaceId/index.tsx
··· 145 145 Get started by creating your first project. 146 146 </p> 147 147 </div> 148 - <Button 149 - onClick={handleCreateProject} 150 - className="gap-2 " 151 - > 148 + <Button onClick={handleCreateProject} className="gap-2 "> 152 149 <Plus className="w-4 h-4" /> 153 150 Create project 154 151 </Button>
+1 -2
apps/web/src/routes/_layout/_authenticated/dashboard/workspace/create.tsx
··· 2 2 import { createFileRoute, useNavigate } from "@tanstack/react-router"; 3 3 import { Building2 } from "lucide-react"; 4 4 import { useEffect, useRef, useState } from "react"; 5 - import { toast } from "@/lib/toast"; 6 - 7 5 import PageTitle from "@/components/page-title"; 8 6 import { Button } from "@/components/ui/button"; 9 7 import { Card, CardContent } from "@/components/ui/card"; 10 8 import { Input } from "@/components/ui/input"; 11 9 import useCreateWorkspace from "@/hooks/queries/workspace/use-create-workspace"; 12 10 import { authClient } from "@/lib/auth-client"; 11 + import { toast } from "@/lib/toast"; 13 12 14 13 export const Route = createFileRoute( 15 14 "/_layout/_authenticated/dashboard/workspace/create",
+1 -1
apps/web/src/routes/_layout/_authenticated/invitations.tsx
··· 2 2 import { createFileRoute, useNavigate } from "@tanstack/react-router"; 3 3 import { CheckCircle, Loader2, Mail, X } from "lucide-react"; 4 4 import { useState } from "react"; 5 - import { toast } from "@/lib/toast"; 6 5 import PageTitle from "@/components/page-title"; 7 6 import useAuth from "@/components/providers/auth-provider/hooks/use-auth"; 8 7 import { Badge } from "@/components/ui/badge"; ··· 18 17 import { usePendingInvitations } from "@/hooks/queries/invitation/use-pending-invitations"; 19 18 import { authClient } from "@/lib/auth-client"; 20 19 import { cn } from "@/lib/cn"; 20 + import { toast } from "@/lib/toast"; 21 21 22 22 export const Route = createFileRoute("/_layout/_authenticated/invitations")({ 23 23 component: InvitationsPage,
+1 -1
apps/web/src/routes/auth/sign-in.tsx
··· 5 5 } from "@tanstack/react-router"; 6 6 import { Github, KeyRound, UserCheck } from "lucide-react"; 7 7 import { useState } from "react"; 8 - import { toast } from "@/lib/toast"; 9 8 import { z } from "zod/v4"; 10 9 import PageTitle from "@/components/page-title"; 11 10 import { Alert, AlertDescription } from "@/components/ui/alert"; ··· 13 12 import useGetConfig from "@/hooks/queries/config/use-get-config"; 14 13 import { authClient } from "@/lib/auth-client"; 15 14 import { cn } from "@/lib/cn"; 15 + import { toast } from "@/lib/toast"; 16 16 import { AuthLayout } from "../../components/auth/layout"; 17 17 import { OtpSignInForm } from "../../components/auth/otp-sign-in-form"; 18 18 import { SignInForm } from "../../components/auth/sign-in-form";
+1 -1
apps/web/src/routes/auth/sign-up.tsx
··· 5 5 } from "@tanstack/react-router"; 6 6 import { UserCheck } from "lucide-react"; 7 7 import { useState } from "react"; 8 - import { toast } from "@/lib/toast"; 9 8 import { z } from "zod/v4"; 10 9 import { AuthLayout } from "@/components/auth/layout"; 11 10 import { SignUpForm } from "@/components/auth/sign-up-form"; ··· 15 14 import { Button } from "@/components/ui/button"; 16 15 import useGetConfig from "@/hooks/queries/config/use-get-config"; 17 16 import { authClient } from "@/lib/auth-client"; 17 + import { toast } from "@/lib/toast"; 18 18 19 19 const signUpSearchSchema = z.object({ 20 20 invitationId: z.string().optional(),
+2 -6
apps/web/src/routes/auth/verify-otp.tsx
··· 3 3 import { REGEXP_ONLY_DIGITS } from "input-otp"; 4 4 import { useCallback, useEffect, useState } from "react"; 5 5 import { useForm } from "react-hook-form"; 6 - import { toast } from "@/lib/toast"; 7 6 import { z } from "zod/v4"; 8 7 import PageTitle from "@/components/page-title"; 9 8 import { Button } from "@/components/ui/button"; ··· 21 20 InputOTPSlot, 22 21 } from "@/components/ui/input-otp"; 23 22 import { authClient } from "@/lib/auth-client"; 23 + import { toast } from "@/lib/toast"; 24 24 import { AuthLayout } from "../../components/auth/layout"; 25 25 26 26 const verifyOtpSchema = z.object({ ··· 156 156 )} 157 157 /> 158 158 159 - <Button 160 - type="submit" 161 - disabled={isPending} 162 - className="w-full" 163 - > 159 + <Button type="submit" disabled={isPending} className="w-full"> 164 160 {isPending ? "Verifying..." : "Verify & Sign In"} 165 161 </Button> 166 162
+1 -1
apps/web/src/routes/invitation/accept.$inviteId.tsx
··· 14 14 XCircle, 15 15 } from "lucide-react"; 16 16 import { useState } from "react"; 17 - import { toast } from "@/lib/toast"; 18 17 import PageTitle from "@/components/page-title"; 19 18 import { Alert, AlertDescription } from "@/components/ui/alert"; 20 19 import { Button } from "@/components/ui/button"; 21 20 import { useGetInvitationDetails } from "@/hooks/queries/invitation/use-get-invitation-details"; 22 21 import { authClient } from "@/lib/auth-client"; 22 + import { toast } from "@/lib/toast"; 23 23 import { AuthLayout } from "../../components/auth/layout"; 24 24 25 25 export const Route = createFileRoute("/invitation/accept/$inviteId")({