From a8da7950e574e5aa78e42f5949698610f8153bff Mon Sep 17 00:00:00 2001 From: Lokiwich Date: Sat, 22 Nov 2025 17:03:15 +0330 Subject: [PATCH 1/7] feat: add bookmark permission info modal with alert image --- public/images/bookmark-permission-alert.jpg | Bin 0 -> 55736 bytes .../modal/bookmark-permission-info.modal.tsx | 81 ++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 public/images/bookmark-permission-alert.jpg create mode 100644 src/layouts/bookmark/components/modal/bookmark-permission-info.modal.tsx diff --git a/public/images/bookmark-permission-alert.jpg b/public/images/bookmark-permission-alert.jpg new file mode 100644 index 0000000000000000000000000000000000000000..11f8a0a7aacc053ff0af1bc6d718450f0695703b GIT binary patch literal 55736 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 literal 0 HcmV?d00001 diff --git a/src/layouts/bookmark/components/modal/bookmark-permission-info.modal.tsx b/src/layouts/bookmark/components/modal/bookmark-permission-info.modal.tsx new file mode 100644 index 00000000..53fe1d11 --- /dev/null +++ b/src/layouts/bookmark/components/modal/bookmark-permission-info.modal.tsx @@ -0,0 +1,81 @@ +import Modal from '@/components/modal' +import { Button } from '@/components/button/button' + +interface BookmarkPermissionInfoModalProps { + isOpen: boolean + onClose: () => void + onConfirm: () => void +} + +export function BookmarkPermissionInfoModal({ + isOpen, + onClose, + onConfirm, +}: BookmarkPermissionInfoModalProps) { + const handleConfirm = () => { + onConfirm() + onClose() + } + + return ( + +
+
+ {/* Type badge and title */} +
+

+ اجازه دسترسی به بوکمارک های مرورگر +

+
+ +
+
+ Browser permission dialog example +
+
+ + {/* Content */} +
+

+ برای وارد کردن بوکمارک‌های مرورگر به ویجتی‌فای، بعد از تایید کردن این + پیام، یک پیغام به شکل زیر روی صفحه شما ظاهر می‌شود که باید روی دکمه{' '} + "Allow" کلیک کنید.

+
+
+ + {/* Actions */} +
+ + +
+
+
+ ) +} From 4dc213a530d4ece3ff4d4eae151ceedb3842d712 Mon Sep 17 00:00:00 2001 From: Lokiwich Date: Sat, 22 Nov 2025 17:08:02 +0330 Subject: [PATCH 2/7] feat: implement import bookmark modal for browser bookmarks with selection and permission handling --- .../modal/import-bookmark.modal.tsx | 426 ++++++++++++++++++ 1 file changed, 426 insertions(+) create mode 100644 src/layouts/bookmark/components/modal/import-bookmark.modal.tsx diff --git a/src/layouts/bookmark/components/modal/import-bookmark.modal.tsx b/src/layouts/bookmark/components/modal/import-bookmark.modal.tsx new file mode 100644 index 00000000..6f7a3daf --- /dev/null +++ b/src/layouts/bookmark/components/modal/import-bookmark.modal.tsx @@ -0,0 +1,426 @@ +import { useEffect, useState } from 'react' +import { Button } from '@/components/button/button' +import Modal from '@/components/modal' +import { FiFolder, FiChevronLeft } from 'react-icons/fi' +import { getFaviconFromUrl } from '@/common/utils/icon' +import { useGeneralSetting } from '@/context/general-setting.context' +import { useBookmarkStore } from '../../context/bookmark.context' +import { + type FetchedBrowserBookmark, + getBrowserBookmarks, +} from '../../utils/browser-bookmarks.util' +import { BookmarkPermissionInfoModal } from './bookmark-permission-info.modal' +import { v4 as uuidv4 } from 'uuid' +import { toast } from 'react-hot-toast' +import { setToStorage } from '@/common/storage' +import { callEvent } from '@/common/utils/call-event' +import { SyncTarget } from '@/layouts/navbar/sync/sync' +import Analytics from '@/analytics' +import type { Bookmark, LocalBookmark } from '../../types/bookmark.types' + +interface ImportBookmarkModalProps { + isOpen: boolean + onClose: () => void + parentId: string | null + availableSlots: number +} + +interface SelectedItem { + id: string + title: string + url: string | null + type: 'BOOKMARK' | 'FOLDER' + children?: FetchedBrowserBookmark[] + importChildren?: boolean +} + +export function ImportBookmarkModal({ + isOpen, + onClose, + parentId, + availableSlots, +}: ImportBookmarkModalProps) { + const [browserBookmarks, setBrowserBookmarks] = useState([]) + const [loading, setLoading] = useState(false) + const [selectedItems, setSelectedItems] = useState>(new Map()) + const [expandedFolders, setExpandedFolders] = useState>(new Set()) + const [showPermissionInfoModal, setShowPermissionInfoModal] = useState(false) + const [isImporting, setIsImporting] = useState(false) + + const { browserBookmarksEnabled, setBrowserBookmarksEnabled } = useGeneralSetting() + const { bookmarks: existingBookmarks, setBookmarks, getCurrentFolderItems } = useBookmarkStore() + + // Check permission when modal opens + useEffect(() => { + if (isOpen && !browserBookmarksEnabled) { + browser.permissions.contains({ permissions: ['bookmarks'] }).then((hasPermission) => { + if (!hasPermission) { + setShowPermissionInfoModal(true) + } + }) + } + }, [isOpen, browserBookmarksEnabled]) + + useEffect(() => { + async function loadBookmarks() { + if (!browserBookmarksEnabled) return + + setLoading(true) + try { + const fetched = await getBrowserBookmarks({ includeFolders: true, asTree: true }) + // Filter out root folders (Bookmarks bar, Other bookmarks, etc.) + const filtered = fetched + .filter((root) => root.children && root.children.length > 0) + .flatMap((root) => root.children || []) + setBrowserBookmarks(filtered) + } catch (error) { + console.error('Error loading browser bookmarks:', error) + } finally { + setLoading(false) + } + } + + if (isOpen && browserBookmarksEnabled) { + loadBookmarks() + } + }, [isOpen, browserBookmarksEnabled]) + + const handlePermissionInfoConfirm = () => { + browser.permissions + .request({ permissions: ['bookmarks'] }) + .then((granted) => { + if (granted) { + setBrowserBookmarksEnabled(true) + setShowPermissionInfoModal(false) + } + }) + .catch((error) => { + console.error('Error requesting permission:', error) + }) + } + + const toggleItemSelection = (item: FetchedBrowserBookmark) => { + const newSelected = new Map(selectedItems) + + if (item.type === 'FOLDER') { + if (newSelected.has(item.id)) { + newSelected.delete(item.id) + } else { + newSelected.set(item.id, { + id: item.id, + title: item.title, + url: item.url, + type: item.type, + children: item.children, + importChildren: false, + }) + } + } else { + if (newSelected.has(item.id)) { + newSelected.delete(item.id) + } else { + if (getSelectedCount(newSelected) >= availableSlots) { + toast.error(`فقط ${availableSlots} جایگاه خالی دارید`) + return + } + newSelected.set(item.id, { + id: item.id, + title: item.title, + url: item.url, + type: item.type, + }) + } + } + + setSelectedItems(newSelected) + } + + const toggleFolderExpansion = (folderId: string) => { + const newExpanded = new Set(expandedFolders) + if (newExpanded.has(folderId)) { + newExpanded.delete(folderId) + } else { + newExpanded.add(folderId) + } + setExpandedFolders(newExpanded) + } + + const toggleImportChildren = (folderId: string) => { + const newSelected = new Map(selectedItems) + const item = newSelected.get(folderId) + if (item && item.type === 'FOLDER') { + const childrenCount = item.children?.filter(c => c.type === 'BOOKMARK').length || 0 + // Check limit based on the new folder's capacity (50 slots for folders) + const folderCapacity = 50 + const wouldExceed = !item.importChildren && (childrenCount > folderCapacity) + + if (wouldExceed) { + toast.error(`این پوشه ${childrenCount} بوکمارک دارد که از ${folderCapacity} جایگاه مجاز بیشتر است`) + return + } + + newSelected.set(folderId, { + ...item, + importChildren: !item.importChildren, + }) + setSelectedItems(newSelected) + } + } + + const getSelectedCount = (selected: Map): number => { + let count = 0 + selected.forEach((item) => { + if (item.type === 'BOOKMARK') { + count++ + } else if (item.type === 'FOLDER' && item.importChildren) { + count += item.children?.filter(c => c.type === 'BOOKMARK').length || 0 + } + }) + return count + } + + const renderBookmarkItem = (item: FetchedBrowserBookmark, level: number = 0) => { + const isSelected = selectedItems.has(item.id) + const isExpanded = expandedFolders.has(item.id) + const selectedItem = selectedItems.get(item.id) + const isFolder = item.type === 'FOLDER' + const hasChildren = item.children && item.children.length > 0 + + return ( +
+
+ toggleItemSelection(item)} + className="checkbox w-4 h-4 cursor-pointer" + disabled={!isFolder && getSelectedCount(selectedItems) >= availableSlots && !isSelected} + /> + + {isFolder ? ( + + )} + + + ) : ( + + + )} + + +
+ + {isFolder && isExpanded && hasChildren && ( +
+ {item.children?.map((child) => renderBookmarkItem(child, level + 1))} +
+ )} +
+ ) + } + + const handleImport = async () => { + if (selectedItems.size === 0) { + toast.error('لطفاً حداقل یک مورد را انتخاب کنید') + return + } + + setIsImporting(true) + try { + const currentFolderItems = getCurrentFolderItems(parentId) + const maxOrder = currentFolderItems.reduce( + (max, item) => Math.max(max, item.order || 0), + -1 + ) + + const newBookmarks: LocalBookmark[] = [] + let currentOrder = maxOrder + 1 + + // Import folders first + for (const [id, selectedItem] of selectedItems) { + if (selectedItem.type === 'FOLDER') { + const newFolder: LocalBookmark = { + id: uuidv4(), + order: currentOrder++, + isLocal: true, + onlineId: null, + parentId: parentId, + title: selectedItem.title, + type: 'FOLDER', + url: null, + icon: null, + customBackground: null, + customTextColor: null, + sticker: null, + } + newBookmarks.push(newFolder) + + // Import children if requested + if (selectedItem.importChildren && selectedItem.children) { + const childBookmarks = selectedItem.children.filter(c => c.type === 'BOOKMARK') + for (const child of childBookmarks) { + if (child.url) { + const newBookmark: LocalBookmark = { + id: uuidv4(), + order: currentOrder++, + isLocal: true, + onlineId: null, + parentId: newFolder.id, + title: child.title, + type: 'BOOKMARK', + url: child.url, + icon: null, + customBackground: null, + customTextColor: null, + sticker: null, + } + newBookmarks.push(newBookmark) + } + } + } + } + } + + // Import bookmarks + for (const [id, selectedItem] of selectedItems) { + if (selectedItem.type === 'BOOKMARK' && selectedItem.url) { + const newBookmark: LocalBookmark = { + id: uuidv4(), + order: currentOrder++, + isLocal: true, + onlineId: null, + parentId: parentId, + title: selectedItem.title, + type: 'BOOKMARK', + url: selectedItem.url, + icon: null, + customBackground: null, + customTextColor: null, + sticker: null, + } + newBookmarks.push(newBookmark) + } + } + + // Add all new bookmarks to existing bookmarks + const updatedBookmarks = [...existingBookmarks, ...newBookmarks] + setBookmarks(updatedBookmarks) + const localBookmarks = updatedBookmarks.filter((b) => b.isLocal) + await setToStorage('bookmarks', localBookmarks) + + Analytics.event('import_bookmarks') + callEvent('startSync', SyncTarget.BOOKMARKS) + + toast.success(`${newBookmarks.length} مورد با موفقیت اضافه شد`) + onClose() + } catch (error) { + console.error('Error importing bookmarks:', error) + toast.error('خطا در import کردن بوکمارک‌ها') + } finally { + setIsImporting(false) + } + } + + const selectedCount = getSelectedCount(selectedItems) + + if (!browserBookmarksEnabled || showPermissionInfoModal) { + return ( + { + setShowPermissionInfoModal(false) + onClose() + }} + onConfirm={handlePermissionInfoConfirm} + /> + ) + } + + return ( + +
+
+ {loading ? ( +
+ در حال بارگذاری... +
+ ) : browserBookmarks.length === 0 ? ( +
+ بوکمارکی یافت نشد +
+ ) : ( +
+ {browserBookmarks.map((item) => renderBookmarkItem(item))} +
+ )} +
+ +
+ + {selectedCount} از {availableSlots} جایگاه پر شده + + {selectedCount > 0 && ( + + )} +
+ +
+
+ ) +} + From 217a6c867bfdedf22e33555e22c4685f8deabb10 Mon Sep 17 00:00:00 2001 From: Lokiwich Date: Sat, 22 Nov 2025 17:08:36 +0330 Subject: [PATCH 3/7] refactor: clean up default function implementations in bookmark context --- src/layouts/bookmark/context/bookmark.context.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/layouts/bookmark/context/bookmark.context.tsx b/src/layouts/bookmark/context/bookmark.context.tsx index ef250a38..5a2b2ecd 100644 --- a/src/layouts/bookmark/context/bookmark.context.tsx +++ b/src/layouts/bookmark/context/bookmark.context.tsx @@ -29,11 +29,11 @@ export interface BookmarkStoreContext { const bookmarkContext = createContext({ bookmarks: [], - setBookmarks: () => {}, + setBookmarks: () => { }, getCurrentFolderItems: () => [], - addBookmark: async () => {}, - editBookmark: () => {}, - deleteBookmark: () => {}, + addBookmark: async () => { }, + editBookmark: () => { }, + deleteBookmark: () => { }, }) export const BookmarkProvider: React.FC<{ children: React.ReactNode }> = ({ From 8280e9c186da1eed35e874d611fb784c9c7391df Mon Sep 17 00:00:00 2001 From: Lokiwich Date: Sat, 22 Nov 2025 17:09:04 +0330 Subject: [PATCH 4/7] feat: add optional import modal trigger to bookmark creation for enhanced user experience --- .../components/modal/add-bookmark.modal.tsx | 250 ++++++++++-------- 1 file changed, 136 insertions(+), 114 deletions(-) diff --git a/src/layouts/bookmark/components/modal/add-bookmark.modal.tsx b/src/layouts/bookmark/components/modal/add-bookmark.modal.tsx index 78807055..56f91e8d 100644 --- a/src/layouts/bookmark/components/modal/add-bookmark.modal.tsx +++ b/src/layouts/bookmark/components/modal/add-bookmark.modal.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useState, useEffect } from 'react' import { Button } from '@/components/button/button' import Modal from '@/components/modal' import { TextInput } from '@/components/text-input' @@ -19,6 +19,7 @@ interface AddBookmarkModalProps { onClose: () => void onAdd: (bookmark: BookmarkCreateFormFields) => void parentId: string | null + onOpenImportModal?: () => void } export interface BookmarkCreateFormFields { @@ -55,6 +56,7 @@ export function AddBookmarkModal({ onClose, onAdd, parentId = null, + onOpenImportModal, }: AddBookmarkModalProps) { const [type, setType] = useState('BOOKMARK') const [iconSource, setIconSource] = useState('auto') @@ -152,6 +154,7 @@ export function AddBookmarkModal({ } } + const handleAdvancedModalClose = ( data: { background: string | null @@ -183,129 +186,148 @@ export function AddBookmarkModal({ }, [isOpen]) return ( - onCloseHandler()} - size="md" - title={`${type === 'FOLDER' ? 'پوشه جدید' : 'بوکمارک جدید'}`} - direction="rtl" - className="!overflow-y-hidden" - closeOnBackdropClick={false} - > -
+ onCloseHandler()} + size="md" + title={`${type === 'FOLDER' ? 'پوشه جدید' : 'بوکمارک جدید'}`} + direction="rtl" + className="!overflow-y-hidden" + closeOnBackdropClick={false} > -
-
- -
+ +
+
+ +
+ + {/* Import from browser bookmarks button */} + {type === 'BOOKMARK' && onOpenImportModal && ( +
+ +
+ )} -
- {' '} -
+ {' '} +
+ > + {type === 'BOOKMARK' && ( + + )} + {renderIconPreview( + formData.icon, + type === 'FOLDER' ? 'upload' : iconSource, + setIconSource, + (value) => updateFormData('icon', value) + )} +
+ + handleImageUpload( + e, + (file) => updateFormData('icon', file), + setIconSource + ) + } + /> + updateFormData('title', v)} + className={ + 'mt-2 w-full px-4 py-3 text-right rounded-lg transition-all duration-200 ' + } + /> +
+ {type === 'BOOKMARK' && ( + handleUrlChange(v)} + className={ + 'mt-2 w-full px-4 py-3 text-right absolute rounded-lg transition-all duration-300' + } + /> + )} +
+ {type === 'BOOKMARK' && ( - - )} - {renderIconPreview( - formData.icon, - type === 'FOLDER' ? 'upload' : iconSource, - setIconSource, - (value) => updateFormData('icon', value) + )}
- - handleImageUpload( - e, - (file) => updateFormData('icon', file), - setIconSource - ) - } - /> - updateFormData('title', v)} - className={ - 'mt-2 w-full px-4 py-3 text-right rounded-lg transition-all duration-200 ' - } + + -
- {type === 'BOOKMARK' && ( - handleUrlChange(v)} - className={ - 'mt-2 w-full px-4 py-3 text-right absolute rounded-lg transition-all duration-300' - } - /> - )} -
- {type === 'BOOKMARK' && ( - - )}
- -
- -
- - -
- - +
+ + +
+ + +
-
- - + + + ) } From f7017b410ac7b313f4aed11ec48f0b3700def522 Mon Sep 17 00:00:00 2001 From: Lokiwich Date: Sat, 22 Nov 2025 17:09:12 +0330 Subject: [PATCH 5/7] feat: add BrowserBookmarkSelector component for displaying and selecting browser bookmarks --- .../components/browser-bookmark-selector.tsx | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/layouts/bookmark/components/browser-bookmark-selector.tsx diff --git a/src/layouts/bookmark/components/browser-bookmark-selector.tsx b/src/layouts/bookmark/components/browser-bookmark-selector.tsx new file mode 100644 index 00000000..f43a30b9 --- /dev/null +++ b/src/layouts/bookmark/components/browser-bookmark-selector.tsx @@ -0,0 +1,103 @@ +import { useEffect, useState } from 'react' +import { FaGlobe } from 'react-icons/fa' +import { FiFolder } from 'react-icons/fi' +import { getFaviconFromUrl } from '@/common/utils/icon' +import { SectionPanel } from '@/components/section-panel' +import { useGeneralSetting } from '@/context/general-setting.context' +import { + type FetchedBrowserBookmark, + getBrowserBookmarks, +} from '../utils/browser-bookmarks.util' + +interface BrowserBookmarkSelectorProps { + onSelect: (bookmark: { title: string; url: string; icon: string | null }) => void +} + +export function BrowserBookmarkSelector({ onSelect }: BrowserBookmarkSelectorProps) { + const { browserBookmarksEnabled } = useGeneralSetting() + const [bookmarks, setBookmarks] = useState([]) + const [loading, setLoading] = useState(false) + + useEffect(() => { + async function loadBookmarks() { + if (!browserBookmarksEnabled) return + + setLoading(true) + try { + const fetched = await getBrowserBookmarks({ includeFolders: false }) + // فقط بوکمارک‌ها (نه پوشه‌ها) و حداکثر 20 تا + const bookmarksOnly = fetched + .filter((b) => b.type === 'BOOKMARK' && b.url) + .slice(0, 20) + setBookmarks(bookmarksOnly) + } catch (error) { + console.error('Error loading browser bookmarks:', error) + } finally { + setLoading(false) + } + } + + loadBookmarks() + }, [browserBookmarksEnabled]) + + if (!browserBookmarksEnabled) { + return null + } + + if (loading) { + return ( +
+ +
+ در حال بارگذاری... +
+
+
+ ) + } + + if (bookmarks.length === 0) { + return null + } + + return ( +
+ +
+ {bookmarks.map((bookmark) => ( +
+ onSelect({ + title: bookmark.title, + url: bookmark.url || '', + icon: bookmark.url ? getFaviconFromUrl(bookmark.url) : null, + }) + } + className="p-2 flex flex-col items-center gap-y-0.5 text-center transition-colors duration-200 bg-content hover:!bg-base-300/75 border border-base-300/40 rounded-xl cursor-pointer" + > +
+ {bookmark.url ? ( + {bookmark.title} { + const target = e.target as HTMLImageElement + target.style.display = 'none' + target.nextElementSibling?.classList.remove('hidden') + }} + /> + ) : null} + +
+

+ {bookmark.title} +

+
+ ))} +
+
+
+ ) +} From 011c8726a8cd0c9183b773acc7bc74acd1a6426f Mon Sep 17 00:00:00 2001 From: Lokiwich Date: Sat, 22 Nov 2025 17:09:20 +0330 Subject: [PATCH 6/7] feat: integrate import bookmark modal into bookmarks list with available slots calculation --- src/layouts/bookmark/bookmarks.tsx | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/layouts/bookmark/bookmarks.tsx b/src/layouts/bookmark/bookmarks.tsx index d21b133d..9b594baf 100644 --- a/src/layouts/bookmark/bookmarks.tsx +++ b/src/layouts/bookmark/bookmarks.tsx @@ -10,6 +10,7 @@ import { useState } from 'react' import Analytics from '@/analytics' import { FolderHeader } from './components/folder-header' import { AddBookmarkModal } from './components/modal/add-bookmark.modal' +import { ImportBookmarkModal } from './components/modal/import-bookmark.modal' import type { Bookmark, FolderPathItem } from './types/bookmark.types' import { BookmarkGrid } from './bookmark-grid' import { useBookmarkStore } from './context/bookmark.context' @@ -22,6 +23,7 @@ export function BookmarksList() { const { isAuthenticated } = useAuth() const [showAddBookmarkModal, setShowAddBookmarkModal] = useState(false) + const [showImportBookmarkModal, setShowImportBookmarkModal] = useState(false) const [currentFolderId, setCurrentFolderId] = useState(null) @@ -139,6 +141,17 @@ export function BookmarksList() { const currentFolderItems = getCurrentFolderItems(currentFolderId) + // Calculate available slots + const getAvailableSlots = (): number => { + if (!currentFolderId) { + return Math.max(0, TOTAL_BOOKMARKS - currentFolderItems.length) + } + // For folders, use a larger limit (e.g., 50) + return Math.max(0, 50 - currentFolderItems.length) + } + + const availableSlots = getAvailableSlots() + const getDisplayedBookmarks = (): Bookmark[] => { if (!currentFolderId) { const baseItems = currentFolderItems.slice(0, TOTAL_BOOKMARKS) @@ -186,7 +199,10 @@ export function BookmarksList() { folderPath={folderPath} setCurrentFolderId={(id) => setCurrentFolderId(id)} setFolderPath={(path) => setFolderPath(path)} - openAddBookmarkModal={() => setShowAddBookmarkModal(true)} + openAddBookmarkModal={() => { + setShowAddBookmarkModal(true) + setShowImportBookmarkModal(false) + }} />
@@ -198,6 +214,18 @@ export function BookmarksList() { addBookmark(bookmark, () => setShowAddBookmarkModal(false)) } parentId={currentFolderId} + onOpenImportModal={() => { + setShowAddBookmarkModal(false) + setShowImportBookmarkModal(true) + }} + /> + )} + {showImportBookmarkModal && ( + setShowImportBookmarkModal(false)} + parentId={currentFolderId} + availableSlots={availableSlots} /> )} From 53bd5da7813d4bbd78e4b3094cd548ca049df996 Mon Sep 17 00:00:00 2001 From: Lokiwich Date: Sat, 22 Nov 2025 17:22:10 +0330 Subject: [PATCH 7/7] refactor: improve code formatting and readability in bookmark components --- .../components/browser-bookmark-selector.tsx | 8 +- .../components/modal/add-bookmark.modal.tsx | 6 +- .../modal/bookmark-permission-info.modal.tsx | 139 +++++++++--------- .../modal/import-bookmark.modal.tsx | 90 ++++++++---- .../bookmark/context/bookmark.context.tsx | 8 +- 5 files changed, 144 insertions(+), 107 deletions(-) diff --git a/src/layouts/bookmark/components/browser-bookmark-selector.tsx b/src/layouts/bookmark/components/browser-bookmark-selector.tsx index f43a30b9..03a168e3 100644 --- a/src/layouts/bookmark/components/browser-bookmark-selector.tsx +++ b/src/layouts/bookmark/components/browser-bookmark-selector.tsx @@ -71,7 +71,9 @@ export function BrowserBookmarkSelector({ onSelect }: BrowserBookmarkSelectorPro onSelect({ title: bookmark.title, url: bookmark.url || '', - icon: bookmark.url ? getFaviconFromUrl(bookmark.url) : null, + icon: bookmark.url + ? getFaviconFromUrl(bookmark.url) + : null, }) } className="p-2 flex flex-col items-center gap-y-0.5 text-center transition-colors duration-200 bg-content hover:!bg-base-300/75 border border-base-300/40 rounded-xl cursor-pointer" @@ -85,7 +87,9 @@ export function BrowserBookmarkSelector({ onSelect }: BrowserBookmarkSelectorPro onError={(e) => { const target = e.target as HTMLImageElement target.style.display = 'none' - target.nextElementSibling?.classList.remove('hidden') + target.nextElementSibling?.classList.remove( + 'hidden' + ) }} /> ) : null} diff --git a/src/layouts/bookmark/components/modal/add-bookmark.modal.tsx b/src/layouts/bookmark/components/modal/add-bookmark.modal.tsx index 56f91e8d..9a68505a 100644 --- a/src/layouts/bookmark/components/modal/add-bookmark.modal.tsx +++ b/src/layouts/bookmark/components/modal/add-bookmark.modal.tsx @@ -154,7 +154,6 @@ export function AddBookmarkModal({ } } - const handleAdvancedModalClose = ( data: { background: string | null @@ -257,7 +256,9 @@ export function AddBookmarkModal({ updateFormData('title', v)} className={ @@ -278,7 +279,6 @@ export function AddBookmarkModal({ /> )}
- {type === 'BOOKMARK' && ( )} diff --git a/src/layouts/bookmark/components/modal/bookmark-permission-info.modal.tsx b/src/layouts/bookmark/components/modal/bookmark-permission-info.modal.tsx index 53fe1d11..d6ee2ca2 100644 --- a/src/layouts/bookmark/components/modal/bookmark-permission-info.modal.tsx +++ b/src/layouts/bookmark/components/modal/bookmark-permission-info.modal.tsx @@ -2,80 +2,83 @@ import Modal from '@/components/modal' import { Button } from '@/components/button/button' interface BookmarkPermissionInfoModalProps { - isOpen: boolean - onClose: () => void - onConfirm: () => void + isOpen: boolean + onClose: () => void + onConfirm: () => void } export function BookmarkPermissionInfoModal({ - isOpen, - onClose, - onConfirm, + isOpen, + onClose, + onConfirm, }: BookmarkPermissionInfoModalProps) { - const handleConfirm = () => { - onConfirm() - onClose() - } + const handleConfirm = () => { + onConfirm() + onClose() + } - return ( - -
-
- {/* Type badge and title */} -
-

- اجازه دسترسی به بوکمارک های مرورگر -

-
+ return ( + +
+
+ {/* Type badge and title */} +
+

+ اجازه دسترسی به بوکمارک های مرورگر +

+
-
-
- Browser permission dialog example -
-
+
+
+ Browser permission dialog example +
+
- {/* Content */} -
-

- برای وارد کردن بوکمارک‌های مرورگر به ویجتی‌فای، بعد از تایید کردن این - پیام، یک پیغام به شکل زیر روی صفحه شما ظاهر می‌شود که باید روی دکمه{' '} - "Allow" کلیک کنید.

-
-
+ {/* Content */} +
+

+ برای وارد کردن بوکمارک‌های مرورگر به ویجتی‌فای، بعد از تایید + کردن این پیام، یک پیغام به شکل زیر روی صفحه شما ظاهر می‌شود که + باید روی دکمه{' '} + "Allow"{' '} + کلیک کنید.{' '} +

+
+
- {/* Actions */} -
- - -
-
-
- ) + {/* Actions */} +
+ + +
+ +
+ ) } diff --git a/src/layouts/bookmark/components/modal/import-bookmark.modal.tsx b/src/layouts/bookmark/components/modal/import-bookmark.modal.tsx index 6f7a3daf..39243323 100644 --- a/src/layouts/bookmark/components/modal/import-bookmark.modal.tsx +++ b/src/layouts/bookmark/components/modal/import-bookmark.modal.tsx @@ -42,22 +42,30 @@ export function ImportBookmarkModal({ }: ImportBookmarkModalProps) { const [browserBookmarks, setBrowserBookmarks] = useState([]) const [loading, setLoading] = useState(false) - const [selectedItems, setSelectedItems] = useState>(new Map()) + const [selectedItems, setSelectedItems] = useState>( + new Map() + ) const [expandedFolders, setExpandedFolders] = useState>(new Set()) const [showPermissionInfoModal, setShowPermissionInfoModal] = useState(false) const [isImporting, setIsImporting] = useState(false) const { browserBookmarksEnabled, setBrowserBookmarksEnabled } = useGeneralSetting() - const { bookmarks: existingBookmarks, setBookmarks, getCurrentFolderItems } = useBookmarkStore() + const { + bookmarks: existingBookmarks, + setBookmarks, + getCurrentFolderItems, + } = useBookmarkStore() // Check permission when modal opens useEffect(() => { if (isOpen && !browserBookmarksEnabled) { - browser.permissions.contains({ permissions: ['bookmarks'] }).then((hasPermission) => { - if (!hasPermission) { - setShowPermissionInfoModal(true) - } - }) + browser.permissions + .contains({ permissions: ['bookmarks'] }) + .then((hasPermission) => { + if (!hasPermission) { + setShowPermissionInfoModal(true) + } + }) } }, [isOpen, browserBookmarksEnabled]) @@ -67,7 +75,10 @@ export function ImportBookmarkModal({ setLoading(true) try { - const fetched = await getBrowserBookmarks({ includeFolders: true, asTree: true }) + const fetched = await getBrowserBookmarks({ + includeFolders: true, + asTree: true, + }) // Filter out root folders (Bookmarks bar, Other bookmarks, etc.) const filtered = fetched .filter((root) => root.children && root.children.length > 0) @@ -149,13 +160,16 @@ export function ImportBookmarkModal({ const newSelected = new Map(selectedItems) const item = newSelected.get(folderId) if (item && item.type === 'FOLDER') { - const childrenCount = item.children?.filter(c => c.type === 'BOOKMARK').length || 0 + const childrenCount = + item.children?.filter((c) => c.type === 'BOOKMARK').length || 0 // Check limit based on the new folder's capacity (50 slots for folders) const folderCapacity = 50 - const wouldExceed = !item.importChildren && (childrenCount > folderCapacity) + const wouldExceed = !item.importChildren && childrenCount > folderCapacity if (wouldExceed) { - toast.error(`این پوشه ${childrenCount} بوکمارک دارد که از ${folderCapacity} جایگاه مجاز بیشتر است`) + toast.error( + `این پوشه ${childrenCount} بوکمارک دارد که از ${folderCapacity} جایگاه مجاز بیشتر است` + ) return } @@ -173,7 +187,7 @@ export function ImportBookmarkModal({ if (item.type === 'BOOKMARK') { count++ } else if (item.type === 'FOLDER' && item.importChildren) { - count += item.children?.filter(c => c.type === 'BOOKMARK').length || 0 + count += item.children?.filter((c) => c.type === 'BOOKMARK').length || 0 } }) return count @@ -189,8 +203,11 @@ export function ImportBookmarkModal({ return (
toggleItemSelection(item)} className="checkbox w-4 h-4 cursor-pointer" - disabled={!isFolder && getSelectedCount(selectedItems) >= availableSlots && !isSelected} + disabled={ + !isFolder && + getSelectedCount(selectedItems) >= availableSlots && + !isSelected + } /> {isFolder ? ( @@ -208,7 +229,9 @@ export function ImportBookmarkModal({ className="flex items-center gap-2 flex-1 text-right" > - {item.title} + + {item.title} + {isFolder && isSelected && hasChildren && ( )} ) : ( - -
{isFolder && isExpanded && hasChildren && (
- {item.children?.map((child) => renderBookmarkItem(child, level + 1))} + {item.children?.map((child) => + renderBookmarkItem(child, level + 1) + )}
)}
@@ -296,7 +326,9 @@ export function ImportBookmarkModal({ // Import children if requested if (selectedItem.importChildren && selectedItem.children) { - const childBookmarks = selectedItem.children.filter(c => c.type === 'BOOKMARK') + const childBookmarks = selectedItem.children.filter( + (c) => c.type === 'BOOKMARK' + ) for (const child of childBookmarks) { if (child.url) { const newBookmark: LocalBookmark = { @@ -418,9 +450,7 @@ export function ImportBookmarkModal({ )} -
) } - diff --git a/src/layouts/bookmark/context/bookmark.context.tsx b/src/layouts/bookmark/context/bookmark.context.tsx index 5a2b2ecd..ef250a38 100644 --- a/src/layouts/bookmark/context/bookmark.context.tsx +++ b/src/layouts/bookmark/context/bookmark.context.tsx @@ -29,11 +29,11 @@ export interface BookmarkStoreContext { const bookmarkContext = createContext({ bookmarks: [], - setBookmarks: () => { }, + setBookmarks: () => {}, getCurrentFolderItems: () => [], - addBookmark: async () => { }, - editBookmark: () => { }, - deleteBookmark: () => { }, + addBookmark: async () => {}, + editBookmark: () => {}, + deleteBookmark: () => {}, }) export const BookmarkProvider: React.FC<{ children: React.ReactNode }> = ({