Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
8d7b6f9
feat: 미분류 시스템 폴더 도입 및 데이터 무결성 강화
jin2304 Apr 19, 2026
af34c65
feat(backend): 북마크 실시간 검색 성능 최적화 및 상위 폴더 매칭 로직 개발
jin2304 Apr 19, 2026
74e52ef
feat(frontend): 북마크 실시간 검색 성능 최적화 및 상위 폴더 매칭 로직 개발
jin2304 Apr 19, 2026
cddfad4
feat(frontend): 폴더 아키텍처 정교화 및 인터페이스 글로벌화
jin2304 Apr 19, 2026
c3343fa
'오늘 저장한 링크' 기능 신규 도입 및 UX 최적화
jin2304 Apr 20, 2026
b228a81
feat(backend): 미열람 필터 기능 및 북마크 읽음 상태 관리 구현
jin2304 Apr 25, 2026
56fb247
feat(frontend): 미열람 필터 기능 추가 및 공통 드롭다운 편의성 개선
jin2304 Apr 25, 2026
9e4b938
refactor(frontend): 검색 범위(전체/폴더/링크) 필터링 버튼 추가 및 UI 디자인 개선
jin2304 Apr 25, 2026
db6d505
feat(frontend): 미분류 필터 UI 구현 및 우측 패널 동적 제목 적용
jin2304 Apr 25, 2026
dca9bda
fix(frontend): 검색 필터 클릭 시, 선택 폴더 초기화 및 결과 동기화
jin2304 Apr 26, 2026
c30d827
feat(bookmark): 북마크 목록 limit offset 페이징 적용
jin2304 Apr 26, 2026
db17097
fix(bookmark): 검색어 escape 및 MyBatis 파라미터 바인딩 수정
jin2304 Apr 26, 2026
d811abe
refactor(bookmark): Request DTO public 필드 제거
jin2304 Apr 26, 2026
c8a0f3b
fix(frontend): 읽음 처리 시 필요한 북마크 캐시만 갱신
jin2304 Apr 26, 2026
f8e3545
feat(backend): 북마크 검색 필터 고도화 및 예외 처리 로직 개선
jin2304 Apr 27, 2026
625c673
feat(frontend): 실시간 상태 동기화 및 검색 UI 사용자 경험 개선
jin2304 Apr 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
453 changes: 453 additions & 0 deletions docs/Plan/03. my-links_search_feature_plan.md

Large diffs are not rendered by default.

349 changes: 349 additions & 0 deletions docs/Plan/04. unorganized_folder_introduction_plan.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions frontend/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
* {
@apply border-border outline-ring/50;
}
button, [role="button"] {
@apply cursor-pointer;
}
Comment on lines +168 to +170

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

비활성화된 버튼에도 포인터 커서가 적용됩니다.

button/[role="button"]에 무조건 cursor-pointer를 적용하면 disabled 또는 aria-disabled="true" 상태의 버튼에서도 포인터 커서가 표시되어, 클릭 가능한 요소처럼 보이는 UX 문제가 발생합니다. (예: SaveLinkDialog의 Save 버튼이 disabled 상태일 때)

♻️ 제안 변경
-  button, [role="button"] {
-    `@apply` cursor-pointer;
-  }
+  button:not(:disabled):not([aria-disabled="true"]),
+  [role="button"]:not([aria-disabled="true"]) {
+    `@apply` cursor-pointer;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
button, [role="button"] {
@apply cursor-pointer;
}
button:not(:disabled):not([aria-disabled="true"]),
[role="button"]:not([aria-disabled="true"]) {
`@apply` cursor-pointer;
}
🧰 Tools
🪛 Biome (2.4.12)

[error] 169-169: Tailwind-specific syntax is disabled.

(parse)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/app/globals.css` around lines 168 - 170, The rule applying
cursor-pointer to all buttons causes disabled controls to show a pointer cursor;
change the selector from "button, [role=\"button\"]" to exclude disabled states
(e.g., button:not(:disabled):not([aria-disabled=\"true\"]),
[role=\"button\"]:not(:disabled):not([aria-disabled=\"true\"])) so only
interactive buttons get cursor-pointer; update the CSS rule where "button,
[role=\"button\"]" is defined and keep the same `@apply` cursor-pointer
declaration under the new selector.

body {
/* bg, text is handled via layout.tsx classes directly */
}
Expand Down
516 changes: 396 additions & 120 deletions frontend/src/app/my-links/page.tsx

Large diffs are not rendered by default.

23 changes: 18 additions & 5 deletions frontend/src/components/dialogs/SaveLinkDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useCreateBookmark, useAnalyzeUrl } from '@/lib/api/bookmarkApi';
import { useAnalyzeLink } from '@/lib/api/linkAnalysisApi';
import { useAuthStore } from '@/lib/store/authStore';
import type { LinkAnalysisResponse } from '@/lib/types/linkAnalysis';
import { FOLDER_TYPE } from '@/lib/types/folder';

// 디자인 시안에서 추출한 커스텀 테마 매핑
const theme = {
Expand Down Expand Up @@ -61,7 +62,7 @@ export function SaveLinkDialog() {

// --- API 연동 (React Query Hooks) ---
const memberId = useAuthStore((s) => s.member?.memberId);
const { data: folders } = useFolders(memberId); // 기존 폴더 목록 조회
const { data: folders, isLoading: isFoldersLoading } = useFolders(memberId); // 기존 폴더 목록 조회
const { data: tagsData } = useTags(memberId); // 기존 태그 목록 조회
const createBookmarkMutation = useCreateBookmark(); // 북마크 생성 API 연동
const createFolderMutation = useCreateFolder(); // 폴더 생성 API 연동
Expand Down Expand Up @@ -277,7 +278,19 @@ export function SaveLinkDialog() {
}
);
} else {
saveBookmark(selectedFolderId);
// Quick Save 경로: 폴더 미지정 시 미분류(UNORGANIZED) 폴더로 저장
const fallbackFolderId =
selectedFolderId
?? folders?.find((f) => f.folderType === FOLDER_TYPE.UNORGANIZED)?.memberFolderId
?? null;

// [추가] 폴더 목록 로딩이 끝났음에도 불구하고 대상 폴더를 결정할 수 없는 경우 예외 처리
if (fallbackFolderId === null) {
alert('폴더 정보를 불러오는 중이거나 폴더가 존재하지 않습니다. 잠시 후 다시 시도해주세요.');
return;
}

saveBookmark(fallbackFolderId);
}
Comment on lines +281 to 294

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 백엔드가 memberFolderId === null을 어떻게 처리하는지 확인
rg -nP -C3 'memberFolderId' --type=java
# useFolders 훅 동작과 enabled 조건 확인
fd -e ts -e tsx folderApi --exec cat {}

Repository: Searchweb-Dev/Searchweb-Back

Length of output: 29207


🏁 Script executed:

# Find and read SaveLinkDialog.tsx to understand the Save button logic
fd -e tsx SaveLinkDialog --exec wc -l {} \;

Repository: Searchweb-Dev/Searchweb-Back

Length of output: 129


🏁 Script executed:

# Check the SaveLinkDialog component, focusing on Save button conditions
fd -e tsx SaveLinkDialog --exec cat -n {} \; | head -400

Repository: Searchweb-Dev/Searchweb-Back

Length of output: 20366


🏁 Script executed:

# Continue reading SaveLinkDialog.tsx from line 400 onwards to find Save button logic
sed -n '400,550p' frontend/src/components/dialogs/SaveLinkDialog.tsx

Repository: Searchweb-Dev/Searchweb-Back

Length of output: 9454


🏁 Script executed:

# Search for the Save button and its disabled attribute
rg -n "disabled|Save" frontend/src/components/dialogs/SaveLinkDialog.tsx | tail -20

Repository: Searchweb-Dev/Searchweb-Back

Length of output: 2133


folders 로딩 중일 때 fallbackFolderIdnull로 결정될 수 있습니다.

저장 버튼은 URL 유효성과 API 진행 중 여부만 체크하며, 폴더 목록 로딩 상태를 확인하지 않습니다. useFolders 훅이 아직 데이터를 반환하지 않은 상태에서도 사용자가 저장을 클릭할 수 있어, folders?.find()undefined 를 반환하고 fallbackFolderIdnull 로 결정됩니다.

현재 백엔드는 memberFolderId === null 일 때 임시로 폴더 1 로 기본값을 설정하지만, 이 값이 실제로 UNORGANIZED 폴더인지 보장되지 않으며 TODO 주석으로 표시되어 있습니다.

다음 중 하나를 권장합니다:

  • 폴더 목록 로딩 미완료 시 Save 버튼을 비활성화
  • handleSave 내에서 fallbackFolderId === null 체크 후 명시적으로 처리 (예: 조기 종료 및 토스트 메시지)
제안 변경
     } else {
       // Quick Save 경로: 폴더 미지정 시 미분류(UNORGANIZED) 폴더로 저장
       const fallbackFolderId =
         selectedFolderId
         ?? folders?.find((f) => f.folderType === FOLDER_TYPE.UNORGANIZED)?.memberFolderId
         ?? null;
+      if (fallbackFolderId === null) {
+        console.warn('Folders not loaded or UNORGANIZED folder not found');
+        return;
+      }
       saveBookmark(fallbackFolderId);
     }

또는 Save 버튼의 disabled 조건을 다음과 같이 수정하는 것도 고려해주세요:

     disabled={
       !url.trim() 
       || !(url.startsWith('http://') || url.startsWith('https://')) 
       || createBookmarkMutation.isPending 
       || createFolderMutation.isPending
+      || (!pendingNewFolderName && !folders)
     }

이렇게 하면 폴더 목록이 로딩 중일 때는 Save 버튼이 비활성화됩니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Quick Save 경로: 폴더 미지정 시 미분류(UNORGANIZED) 폴더로 저장
const fallbackFolderId =
selectedFolderId
?? folders?.find((f) => f.folderType === FOLDER_TYPE.UNORGANIZED)?.memberFolderId
?? null;
saveBookmark(fallbackFolderId);
}
// Quick Save 경로: 폴더 미지정 시 미분류(UNORGANIZED) 폴더로 저장
const fallbackFolderId =
selectedFolderId
?? folders?.find((f) => f.folderType === FOLDER_TYPE.UNORGANIZED)?.memberFolderId
?? null;
if (fallbackFolderId === null) {
console.warn('Folders not loaded or UNORGANIZED folder not found');
return;
}
saveBookmark(fallbackFolderId);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/dialogs/SaveLinkDialog.tsx` around lines 281 - 287,
The fallbackFolderId can become null when useFolders hasn't returned data yet
(folders is undefined), so either prevent the action by disabling the Save
button while folders are loading or guard in handleSave: check fallbackFolderId
after computing it (using selectedFolderId, folders, FOLDER_TYPE.UNORGANIZED)
and if it's null, show a toast/error and return early instead of calling
saveBookmark; alternatively update the Save button's disabled prop to include
the folders loading flag from useFolders so save cannot be clicked until folders
are ready.

};

Expand Down Expand Up @@ -398,7 +411,7 @@ export function SaveLinkDialog() {
<span className="material-symbols-outlined !text-[13px] !leading-none block text-white font-bold">link</span>
</span>
</div>
<span className="text-[11px] font-bold text-slate-700 dark:text-gray-100 tracking-tight pr-1">복사한 링크 붙여넣기</span>
<span className="text-[11px] font-bold text-slate-700 dark:text-gray-100 tracking-tight pr-1">Paste copied link</span>
</div>
{/* 부드럽고 존재감 있는 곡선형 SVG 꼬리표 - 크기 확대 및 실루엣 최적화 */}
<svg
Expand Down Expand Up @@ -432,7 +445,7 @@ export function SaveLinkDialog() {
{url.trim() && !(url.startsWith('http://') || url.startsWith('https://')) && (
<p className="text-[10px] text-red-500 dark:text-red-400 font-medium flex items-center gap-1 mt-1 ml-10">
<span className="material-symbols-outlined !text-[12px]">error</span>
URL은 http:// 또는 https://로 시작해야 합니다.
URL must start with http:// or https://
</p>
)}
</div>
Expand Down Expand Up @@ -818,7 +831,7 @@ export function SaveLinkDialog() {
</button>
<button
onClick={handleSave}
disabled={!url.trim() || !(url.startsWith('http://') || url.startsWith('https://')) || createBookmarkMutation.isPending || createFolderMutation.isPending}
disabled={!url.trim() || !(url.startsWith('http://') || url.startsWith('https://')) || createBookmarkMutation.isPending || createFolderMutation.isPending || isFoldersLoading}
className={`${styles.btnGradient} text-xs font-bold px-6 py-2.5 rounded-xl transition-all flex items-center gap-2 transform hover:-translate-y-0.5 active:translate-y-0 disabled:opacity-50 disabled:cursor-not-allowed shadow-lg`}
>
{(createBookmarkMutation.isPending || createFolderMutation.isPending) ? 'Saving...' : 'Save to Workspace'}
Expand Down
44 changes: 38 additions & 6 deletions frontend/src/components/my-links/FolderCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import React, { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import type { FolderResponse } from '@/lib/types/folder';
import { FOLDER_TYPE, type FolderResponse } from '@/lib/types/folder';
import { useFolderStore } from '@/lib/store/folderStore';
import { useLinkStore } from '@/lib/store/linkStore';
import { useUIStore } from '@/lib/store/uiStore';
import { FolderEditModal, FolderDeleteModal, FolderMoveModal } from './FolderManagementModals';

interface FolderCardProps {
Expand All @@ -15,8 +17,13 @@ const MENU_OFFSET_Y = 4; // 버튼과 메뉴 사이의 상하 간격

export function FolderCard({ folder, color }: FolderCardProps) {
const setSelectedFolderId = useFolderStore((s) => s.setSelectedFolderId);
const currentSelectedFolderId = useFolderStore((s) => s.selectedFolderId);
const searchQuery = useFolderStore((s) => s.searchQuery);
const setLinkSearchQuery = useLinkStore((s) => s.setSearchQuery);
const [showMenu, setShowMenu] = useState(false); // 드롭다운 메뉴 표시 여부
const [modalType, setModalType] = useState<'edit' | 'delete' | 'move' | null>(null); // 현재 열린 모달 타입
// 시스템 폴더(미분류)는 Move/Delete 불가 (Rename 만 허용)
const isSystemFolder = folder.folderType === FOLDER_TYPE.UNORGANIZED;

// DOM 참조 (메뉴 외부 클릭 감지 및 위치 계산용)
const menuRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -71,7 +78,20 @@ export function FolderCard({ folder, color }: FolderCardProps) {
// 카드 클릭 시 폴더 선택 처리 (메뉴가 열려있지 않을 때만)
const handleCardClick = () => {
if (!showMenu) {
setSelectedFolderId(folder.memberFolderId);
// 1. 이미 선택된 폴더를 다시 클릭하면 선택 해제, 아니면 해당 폴더 선택
if (currentSelectedFolderId === folder.memberFolderId) {
setSelectedFolderId(null);
} else {
setSelectedFolderId(folder.memberFolderId);

// 2. 선택 시에만 수행: 기존 폴더 검색어가 있다면 링크 검색어로 전이
if (searchQuery) {
setLinkSearchQuery(searchQuery);
}

// 3. 선택 시에만 수행: 우측 패널이 닫혀있다면 자동으로 열어줌
useUIStore.getState().toggleRightPanel(true);
}
}
};
Comment on lines 79 to 96

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

선택 해제 시에도 우측 패널을 강제로 여는 동작 확인이 필요합니다.

currentSelectedFolderId === folder.memberFolderId 분기에서 선택을 해제(setSelectedFolderId(null))한 직후에도 toggleRightPanel(true)가 항상 호출되어, 이미 열린 상태였다면 무영향이지만 이미 의도적으로 닫아둔 패널이 갑자기 열릴 여지가 있습니다. 또한 setLinkSearchQuery(searchQuery)가 deselect 시에도 실행되어, 폴더 검색어가 의도치 않게 링크 검색어로 전이될 수 있습니다. 의도가 "선택 시에만 패널을 열고 검색어를 동기화"라면 분기 안으로 이동하는 편이 명확합니다.

♻️ 제안 변경
   const handleCardClick = () => {
     if (!showMenu) {
-      // 1. 이미 선택된 폴더를 다시 클릭하면 선택 해제, 아니면 해당 폴더 선택
       if (currentSelectedFolderId === folder.memberFolderId) {
         setSelectedFolderId(null);
+        return;
-      } else {
-        setSelectedFolderId(folder.memberFolderId);
       }
-      
-      // 2. 기존 폴더 검색어가 있다면 링크 검색어로 전이 (사용자 요청: 클릭 시 링크 필터링되도록)
+      setSelectedFolderId(folder.memberFolderId);
       if (searchQuery) {
         setLinkSearchQuery(searchQuery);
       }
-      
-      // 3. 우측 패널이 닫혀있다면 자동으로 열어줌
       useUIStore.getState().toggleRightPanel(true);
     }
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleCardClick = () => {
if (!showMenu) {
setSelectedFolderId(folder.memberFolderId);
// 1. 이미 선택된 폴더를 다시 클릭하면 선택 해제, 아니면 해당 폴더 선택
if (currentSelectedFolderId === folder.memberFolderId) {
setSelectedFolderId(null);
} else {
setSelectedFolderId(folder.memberFolderId);
}
// 2. 기존 폴더 검색어가 있다면 링크 검색어로 전이 (사용자 요청: 클릭 시 링크 필터링되도록)
if (searchQuery) {
setLinkSearchQuery(searchQuery);
}
// 3. 우측 패널이 닫혀있다면 자동으로 열어줌
useUIStore.getState().toggleRightPanel(true);
}
};
const handleCardClick = () => {
if (!showMenu) {
if (currentSelectedFolderId === folder.memberFolderId) {
setSelectedFolderId(null);
return;
}
setSelectedFolderId(folder.memberFolderId);
if (searchQuery) {
setLinkSearchQuery(searchQuery);
}
useUIStore.getState().toggleRightPanel(true);
}
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/my-links/FolderCard.tsx` around lines 79 - 96, The
click handler handleCardClick currently deselects when currentSelectedFolderId
=== folder.memberFolderId but still runs setLinkSearchQuery(searchQuery) and
useUIStore.getState().toggleRightPanel(true) unconditionally; change the logic
so that only the "select" branch (the else branch where you call
setSelectedFolderId(folder.memberFolderId)) performs
setLinkSearchQuery(searchQuery) and toggleRightPanel(true), while the "deselect"
branch should only call setSelectedFolderId(null) and not open the panel or sync
the search query; update handleCardClick accordingly to keep deselect behavior
inert and selection behavior performing query sync and panel open.


Expand All @@ -84,10 +104,16 @@ export function FolderCard({ folder, color }: FolderCardProps) {
// 메뉴 항목 클릭 시 모달 열기 및 메뉴 닫기
const handleMenuItemClick = (type: 'edit' | 'delete' | 'move', e: React.MouseEvent) => {
e.stopPropagation();
// 시스템 폴더는 Move/Delete 를 허용하지 않음
if (isSystemFolder && (type === 'move' || type === 'delete')) {
return;
}
setModalType(type);
setShowMenu(false);
};

const isSelected = currentSelectedFolderId === folder.memberFolderId;

return (
<>
<div
Expand All @@ -100,10 +126,14 @@ export function FolderCard({ folder, color }: FolderCardProps) {
handleCardClick();
}
}}
className={`bg-white dark:bg-card-dark rounded-lg p-2.5 border border-gray-200/70 dark:border-white/5 shadow-sm hover:shadow-md hover:border-purple-300 dark:hover:border-white/10 transition-all duration-300 group cursor-pointer h-[90px] flex flex-col justify-between focus:ring-1 focus:ring-purple-300 dark:focus:ring-purple-500 outline-none hover:bg-purple-50/30 dark:hover:bg-white/[0.03] relative overflow-visible ${color || ''}`}
className={`bg-white dark:bg-card-dark rounded-lg p-2.5 border transition-all duration-300 group cursor-pointer h-[90px] flex flex-col justify-between outline-none hover:bg-purple-50/30 dark:hover:bg-white/[0.03] relative overflow-visible ${
isSelected
? 'border-purple-500 ring-1 ring-purple-500/20 shadow-md'
: 'border-gray-200/70 dark:border-white/5 shadow-sm hover:shadow-md hover:border-purple-300 dark:hover:border-white/10'
} ${color || ''}`}
>
<div className="flex justify-between items-start">
<div className="p-1.5 bg-purple-50 dark:bg-white/5 text-gray-400 dark:text-gray-400 group-hover:dark:text-white transition-colors rounded-md flex items-center justify-center w-8 h-8">
<div className={`p-1.5 bg-purple-50 dark:bg-white/5 text-gray-400 dark:text-gray-400 group-hover:dark:text-white transition-colors rounded-md flex items-center justify-center w-8 h-8`}>
<span className="material-symbols-outlined text-[16px]">folder_open</span>
</div>

Expand Down Expand Up @@ -148,15 +178,17 @@ export function FolderCard({ folder, color }: FolderCardProps) {
</button>
<button
onClick={(e) => handleMenuItemClick('move', e)}
className="w-full text-left px-3 py-2 text-[11px] text-gray-700 dark:text-white hover:bg-purple-50 dark:hover:bg-purple-600/20 flex items-center gap-2.5 transition-colors"
disabled={isSystemFolder}
className="w-full text-left px-3 py-2 text-[11px] text-gray-700 dark:text-white hover:bg-purple-50 dark:hover:bg-purple-600/20 flex items-center gap-2.5 transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent dark:disabled:hover:bg-transparent"
>
<span className="material-symbols-outlined !text-[16px] !leading-none">drive_file_move</span>
<span className="font-medium">Move</span>
</button>
<div className="h-px bg-gray-50 dark:bg-white/8 my-0.5" />
<button
onClick={(e) => handleMenuItemClick('delete', e)}
className="w-full text-left px-3 py-2 text-[11px] text-rose-500 dark:text-red-400 hover:bg-rose-50 dark:hover:bg-purple-600/20 flex items-center gap-2.5 transition-colors"
disabled={isSystemFolder}
className="w-full text-left px-3 py-2 text-[11px] text-rose-500 dark:text-red-400 hover:bg-rose-50 dark:hover:bg-purple-600/20 flex items-center gap-2.5 transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent dark:disabled:hover:bg-transparent"
>
<span className="material-symbols-outlined !text-[16px] !leading-none text-rose-500 dark:text-red-400">delete</span>
<span className="font-medium">Delete</span>
Expand Down
Loading
Loading