diff options
Diffstat (limited to 'extension/src/components')
-rw-r--r-- | extension/src/components/BMEditor.tsx | 55 | ||||
-rw-r--r-- | extension/src/components/Body.tsx | 42 | ||||
-rw-r--r-- | extension/src/components/Bookmark.tsx | 139 | ||||
-rw-r--r-- | extension/src/components/ContextMenu.tsx | 51 | ||||
-rw-r--r-- | extension/src/components/FolderBody.tsx | 46 | ||||
-rw-r--r-- | extension/src/components/FolderButton.tsx | 93 | ||||
-rw-r--r-- | extension/src/components/SettingsEditor.tsx | 36 |
7 files changed, 348 insertions, 114 deletions
diff --git a/extension/src/components/BMEditor.tsx b/extension/src/components/BMEditor.tsx new file mode 100644 index 0000000..1ac72c6 --- /dev/null +++ b/extension/src/components/BMEditor.tsx @@ -0,0 +1,55 @@ +import React, {useContext, useEffect, useState} from "react"; +import CloseIcon from "../assets/close.svg?react" +import {ActiveEdit} from "./Body.tsx"; +import {getBrowser} from "../main.tsx"; +import RadioButtonGroup from "./RadioButtonGroup.tsx"; + + +function BMEditor() { + const [activeEdit, setActiveEdit] = useContext(ActiveEdit); + + const [iconOptions, setIconOptions] = useState<string[]>([]); + + useEffect(() => { + if (!activeEdit) return; + getBrowser().storage.local.get("icon-aval-"+activeEdit.id).then( r => { + setIconOptions(r["icon-aval-"+activeEdit.id]); + }); + }, [activeEdit]); + + if (!activeEdit) return; + + let isFolder = activeEdit && activeEdit.children && activeEdit.children.length > 0; + return ( + <div id="settings-menu" className={activeEdit ? "open" : "closed"}> + <button id="settings-close" onClick={_ => setActiveEdit(null)}> + <CloseIcon/> + </button> + + <h1>Edit {isFolder ? "Folder" : "Bookmark"}</h1> + + <h3>Name</h3> + <input type={"text"} defaultValue={activeEdit?.title} onChange={e => { + getBrowser().bookmarks.update(activeEdit!.id, {title: e.target.value}) + }}/> + + {!isFolder && (<> + <h3>URL</h3> + <input type={"url"} defaultValue={activeEdit?.url} onChange={e => { + getBrowser().bookmarks.update(activeEdit!.id, {url: e.target.value}) + }}/> + </>)} + + <h3>Icon</h3> + {/*<RadioButtonGroup value={undefined}>*/} + {iconOptions && iconOptions.map(s => + // <option value={s}> + <img src={s}/> + // </option> + )} + {/*</RadioButtonGroup>*/} + </div> + ); +} + +export default BMEditor;
\ No newline at end of file diff --git a/extension/src/components/Body.tsx b/extension/src/components/Body.tsx index 70f8fce..e4c371b 100644 --- a/extension/src/components/Body.tsx +++ b/extension/src/components/Body.tsx @@ -1,11 +1,13 @@ import React, {useEffect, useState} from "react"; import SettingsEditor from "./SettingsEditor.tsx"; import SettingsIcon from "../assets/settings.svg?react"; -import EditIcon from "../assets/move.svg?react"; +import EditIcon from "../assets/edit.svg?react"; import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; import FolderBody from "./FolderBody.tsx"; import {defaultSettings, ISettings, loadSettings, writeSettings} from "../Settings.ts"; import {getBrowser} from "../main.tsx"; +import BMEditor from "./BMEditor.tsx"; +import EditOffIcon from "../assets/edit_off.svg?react"; export const Settings = React.createContext<[ISettings, (arg0: ISettings) => void]>([ @@ -19,58 +21,58 @@ export const ActiveDrag = () => {} ]) +export const ActiveEdit = + React.createContext<[BookmarkTreeNode | null, (arg0: BookmarkTreeNode | null) => void]>([ + null, + () => {} + ]) + /** * A component for the full body of the application * Also stores the trees and settings */ function Body() { const [settingsOpen, setSettingsOpen] = useState(false); - const [settings, setSettings] = useState<ISettings>(defaultSettings); - const [selectedBookmarkTree, setSelectedBookmarkTree] = useState<BookmarkTreeNode[]>([]) - const [fullBookmarkTree, setFullBookmarkTree] = useState<BookmarkTreeNode[] | null>([]) + const [settings, setSettings] = useState<ISettings | undefined>(undefined); const [activeDrag, setActiveDrag] = useState<BookmarkTreeNode | null>(null); + const [activeEdit, setActiveEdit] = useState<BookmarkTreeNode | null>(null); useEffect(() => { loadSettings().then(r => { setSettings(r); }) - getBrowser().bookmarks.getTree().then(t => { - setFullBookmarkTree(t); - }) }, []) useEffect(() => { - writeSettings(settings); - if (settings.rootFolder) { - getBrowser().bookmarks.getSubTree(settings.rootFolder).then(t => { - setSelectedBookmarkTree(t); - }); - } else { - getBrowser().bookmarks.getTree().then(t => { - setSelectedBookmarkTree(t); - }) + if (settings) { + writeSettings(settings); } }, [settings]); + if (!settings) return; + return ( <Settings.Provider value={[settings!, setSettings]}> <ActiveDrag.Provider value={[activeDrag, setActiveDrag]}> + <ActiveEdit.Provider value={[activeEdit, setActiveEdit]}> {(() => {switch (settings.backgroundMode) { case "color": return (<style>{"body {background-color: " + settings.backgroundColor + "; }"}</style>) case "image": return (<style>{"body {background-image: url(\"" + settings.backgroundImage + "\"); }"}</style>) }})()} <style>{"body > .folderBody, a {color: " + settings.foregroundColor + "; }"}</style> <div id={"action-area"}> - {settings.editMode && <span>Move mode: Drag bookmarks to change order</span>} + {settings.editMode && <span>Edit mode: Drag bookmarks to change order</span>} <button onClick={_ => setSettings({...settings, editMode: !settings.editMode})}> - <EditIcon className={settings.editMode? "enabled" : ""}/> + {settings.editMode ? <EditIcon/> : <EditOffIcon/>} </button> <button onClick={_ => setSettingsOpen(!settingsOpen)}> <SettingsIcon/> </button> </div> - <SettingsEditor tree={fullBookmarkTree!} isOpen={[settingsOpen, setSettingsOpen]}/> - {selectedBookmarkTree[0] && (<FolderBody data={selectedBookmarkTree[0]}/>)} + <SettingsEditor isOpen={[settingsOpen, setSettingsOpen]}/> + <BMEditor/> + <FolderBody id={settings.rootFolder || '0'}/> + </ActiveEdit.Provider> </ActiveDrag.Provider> </Settings.Provider> ) diff --git a/extension/src/components/Bookmark.tsx b/extension/src/components/Bookmark.tsx index 2442e02..e378b0f 100644 --- a/extension/src/components/Bookmark.tsx +++ b/extension/src/components/Bookmark.tsx @@ -1,33 +1,63 @@ import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; -import React, {SyntheticEvent, useEffect} from "react"; +import React, {SyntheticEvent, useContext, useEffect, useState} from "react"; import {getBrowser} from "../main.tsx"; -import {ActiveDrag, Settings} from "./Body.tsx"; +import {ActiveDrag, ActiveEdit, Settings} from "./Body.tsx"; import ColorThief from 'colorthief' import DropTargets from "./DropTargets.tsx"; +import ContextMenu from "./ContextMenu.tsx"; /** * A component for a single bookmark - * - * @param props.data The BookmarkTreeNode with the data for the bookmark */ -function Bookmark(props: {data: BookmarkTreeNode}) { - let [settings, _] = React.useContext(Settings); +function Bookmark(props: {id: string}) { + let [settings] = React.useContext(Settings); let [activeDrag, setActiveDrag] = React.useContext(ActiveDrag); + const [, setActiveEdit] = useContext(ActiveEdit) let [favicon, setFavicon] = React.useState<string | null>(null); let [iconMode, setIconMode] = React.useState<"large" | "small" | "letter">("letter"); let [bgColor, setBgColor] = React.useState<[number, number, number] | null>(null) let [bgColorPriority, setBgColorPriority] = React.useState(0); + const [bmData, setBmData] = useState<BookmarkTreeNode | undefined>() + const [renameMode, setRenameMode] = useState(false); + + useEffect(() => { + getBrowser().bookmarks.get(props.id).then(r => { + setBmData(r[0]); + }) + getBrowser().bookmarks.onChanged.addListener((id: string) => { + if (id !== props.id) return; + getBrowser().bookmarks.get(props.id).then(r => { + setBmData(r[0]); + }) + }) + }, []); useEffect(() => { - faviconURL(props.data).then(r => { + if (!bmData) return; + faviconURL(bmData).then(r => { if (r) { setFavicon(r) setIconMode("small"); } }) - }, []); + }, [bmData]); + + useEffect(() => { + let evl = () => { + console.log("clicked") + renameMode && setRenameMode(false); + console.log("evl unregistered") + document.body.removeEventListener('click', evl); + } + if (renameMode) { + console.log("evl registered") + document.body.addEventListener('click', evl); + } + }, [renameMode]); + + if (!bmData) return; function handleImageLoad(e: SyntheticEvent<HTMLImageElement, Event>) { if (e.currentTarget.naturalWidth >= 75 || favicon!.startsWith("data:image/svg+xml")) { @@ -39,71 +69,92 @@ function Bookmark(props: {data: BookmarkTreeNode}) { } // Dragging - function handleDrag() { - setActiveDrag(props.data); - } + const handleDrag = () => { + setActiveDrag(bmData); + }; - function handleDragEnd() { + const handleDragEnd = () => { setActiveDrag(null); - } + }; // Dropping - function handleDropLeft() { + const handleDropLeft = () => { console.log("drop left bm") getBrowser().bookmarks.move(activeDrag!.id, { - parentId: props.data.parentId, - index: props.data.index + parentId: bmData.parentId, + index: bmData.index }) location.reload() - } + }; - function handleDropRight() { + const handleDropRight = () => { console.log("drop right bm") getBrowser().bookmarks.move(activeDrag!.id, { - parentId: props.data.parentId, - index: (props.data.index! + 1) + parentId: bmData.parentId, + index: (bmData.index! + 1) }) location.reload(); - } + }; - function handleDropCenter() { + const handleDropCenter = () => { console.log("drop center bm") chrome.bookmarks.create({ // type: "folder", - parentId: props.data.parentId, - index: props.data.index, + parentId: bmData.parentId, + index: bmData.index, title: "New Folder" }).then(r => { - getBrowser().bookmarks.move(props.data.id, {parentId: r.id}); + getBrowser().bookmarks.move(bmData.id, {parentId: r.id}); getBrowser().bookmarks.move(activeDrag!.id, {parentId: r.id}); location.reload() }) - } + }; + + const handleDelete = () => { + getBrowser().bookmarks.remove(bmData.id); + location.reload(); + }; + + const handleEdit = (e: React.MouseEvent<HTMLButtonElement>) => { + e.preventDefault() + setRenameMode(true) + // setActiveEdit(bmData); + }; return( <div className={"bookmark"}> - <a href={props.data.url} draggable={settings.editMode} onDrag={handleDrag} onDragEnd={handleDragEnd}> - <div className={"icon-box " + (iconMode)} style={bgColor ? {"--icon-bg": `rgba(${bgColor[0]}, ${bgColor[1]}, ${bgColor[2]}, 0.2)`} as React.CSSProperties : undefined}> - {(() => { switch (iconMode) { - case "letter": { - let url = new URL(props.data.url!); - if (bgColorPriority < 1) { - setBgColor(hashStringToColor(url.hostname)); - setBgColorPriority(1); + <a href={bmData.url} draggable={settings.editMode} onDrag={handleDrag} onDragEnd={handleDragEnd}> + <div className={"icon-box " + (iconMode)} + style={bgColor ? {"--icon-bg": `rgba(${bgColor[0]}, ${bgColor[1]}, ${bgColor[2]}, 0.2)`} as React.CSSProperties : undefined}> + {(() => { + switch (iconMode) { + case "letter": { + let url = new URL(bmData.url!); + if (bgColorPriority < 1) { + setBgColor(hashStringToColor(url.hostname)); + setBgColorPriority(1); + } + return (<span className={"letter"}>{url.hostname.charAt(0)}</span>) + } + case "small": { + return (<img alt="Bookmark icon" src={favicon!} onLoad={handleImageLoad}/>) + } + case "large": { + return (<img alt="Bookmark icon" src={favicon!}/>) } - return (<span className={"letter"}>{url.hostname.charAt(0)}</span>) - } - case "small": { - return (<img alt="Bookmark icon" src={favicon!} onLoad={handleImageLoad}/>) - } - case "large": { - return(<img alt="Bookmark icon" src={favicon!}/>) } - }})()} + })()} </div> - <span>{props.data.title}</span> + {renameMode + ? <input type={'text'} + defaultValue={bmData.title} + onChange={e => { + getBrowser().bookmarks.update(props.id, {title: e.target.value}) + }}/> + : <span>{bmData.title}</span>} </a> - {activeDrag && activeDrag !== props.data && + {settings.editMode && <ContextMenu onEdit={handleEdit} onDelete={handleDelete}/>} + {activeDrag && activeDrag !== bmData && <DropTargets onDropLeft={handleDropLeft} onDropRight={handleDropRight} onDropCenter={handleDropCenter}/>} </div> ); diff --git a/extension/src/components/ContextMenu.tsx b/extension/src/components/ContextMenu.tsx new file mode 100644 index 0000000..058e9ba --- /dev/null +++ b/extension/src/components/ContextMenu.tsx @@ -0,0 +1,51 @@ +import DeleteIcon from "../assets/delete.svg?react"; +import EditIcon from "../assets/edit.svg?react"; +import DragIcon from "../assets/drag.svg?react"; +import MoreIcon from "../assets/more.svg?react"; +import React, {useEffect, useState} from "react"; + +function ContextMenu(props: {onEdit: (e: React.MouseEvent<HTMLButtonElement>) => void, onDelete: (e: React.MouseEvent<HTMLButtonElement>) => void}) { + const [open, setOpen] = useState(false) + + useEffect(() => { + let evl = () => { + console.log("clicked") + open && setOpen(false); + console.log("evl unregistered") + document.body.removeEventListener('click', evl); + } + if (open) { + console.log("evl registered") + document.body.addEventListener('click', evl); + } + }, [open]); + + return ( + <div className={"overflow"}> + <button onClick={e => { + e.preventDefault(); + setOpen(!open); + }}> + <MoreIcon/> + </button> + {open && <div className={"context-menu"}> + <button onClick={e => { + setOpen(false); + props.onEdit(e); + }}> + <EditIcon /> + Edit + </button> + <button className={"del"} onClick={e => { + setOpen(false); + props.onDelete(e); + }}> + <DeleteIcon/> + Delete + </button> + </div>} + </div> + ) +} + +export default ContextMenu;
\ No newline at end of file diff --git a/extension/src/components/FolderBody.tsx b/extension/src/components/FolderBody.tsx index a573a6e..e75fcc7 100644 --- a/extension/src/components/FolderBody.tsx +++ b/extension/src/components/FolderBody.tsx @@ -1,32 +1,48 @@ import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; +import {ReactElement, useContext, useEffect, useState} from "react"; +import {Settings} from "./Body.tsx"; +import {getBrowser} from "../main.tsx"; import Bookmark from "./Bookmark.tsx"; import FolderButton from "./FolderButton.tsx"; -import {useContext} from "react"; -import {Settings} from "./Body.tsx"; /** * A component that displays the contents of a bookmark folder - * - * @param props.data The BookmarkTreeNode with data for the folder - * @constructor */ -function FolderBody (props: {data: BookmarkTreeNode}) { - const [settings, _] = useContext(Settings) +function FolderBody (props: {id: string}) { + + const [settings, ] = useContext(Settings) - if (!props.data.children) return; + const [children, setChildren] = useState<BookmarkTreeNode[]>([]) - let content = [...props.data.children].sort(getSortFunction(settings.sort)) - if (settings.foldersFirst) { - let [bookmarks, folders] = separateFolders(content) - content = folders.concat(bookmarks) + const updateBookmarks = () => { + getBrowser().bookmarks.getSubTree(props.id).then(r => { + let content = [...r[0].children!].sort(getSortFunction(settings.sort)) + if (settings.foldersFirst) { + let [bookmarks, folders] = separateFolders(content) + content = folders.concat(bookmarks) + } + setChildren(content); + }) } + useEffect(() => { + updateBookmarks(); + // getBrowser().bookmarks.onRemoved.addListener((id: string, moveInfo) => { + // if (moveInfo.parentId !== props.id) return; + // updateBookmarks(); + // }) + }, []); + + useEffect(() => { + updateBookmarks(); + }, [settings]); + return ( <div className={"folderBody"}> - {content.map(child => + {children.map(child => child.children - ? <FolderButton data={child} /> - : <Bookmark data={child} /> + ? <FolderButton id={child.id} /> + : <Bookmark id={child.id} /> )} </div> ) diff --git a/extension/src/components/FolderButton.tsx b/extension/src/components/FolderButton.tsx index eff035e..374982a 100644 --- a/extension/src/components/FolderButton.tsx +++ b/extension/src/components/FolderButton.tsx @@ -2,78 +2,111 @@ import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; import FolderBody from "./FolderBody.tsx"; import FolderIcon from "../assets/folder.svg?react" import FolderIconOpen from "../assets/folder_open.svg?react" -import React, {useState} from "react"; +import React, {useEffect, useState} from "react"; import DropTargets from "./DropTargets.tsx"; -import {ActiveDrag, Settings} from "./Body.tsx"; +import {ActiveDrag, ActiveEdit, Settings} from "./Body.tsx"; import {getBrowser} from "../main.tsx"; +import ContextMenu from "./ContextMenu.tsx"; /** * A component for the button used to open a bookmark folder. * This is themed the same as a bookmark - * - * @param props.data The BookmarkTreeNode containing the data of the folder */ -function FolderButton(props: {data: BookmarkTreeNode}) { - let [settings, _] = React.useContext(Settings); +function FolderButton(props: {id: string}) { + let [settings, ] = React.useContext(Settings); let [activeDrag, setActiveDrag] = React.useContext(ActiveDrag); + let [, setActiveEdit] = React.useContext(ActiveEdit) - const [folderOpen, setFolderOpen] = useState(false); + const [folderOpen, setFolderOpen] = useState<undefined | boolean>(undefined); + const [bmData, setBmData] = useState<BookmarkTreeNode | undefined>() + + useEffect(() => { + console.log(props.id+" state="+folderOpen) + getBrowser().storage.local.set({['keepopen-'+props.id]: folderOpen}) + }, [folderOpen]); + + useEffect(() => { + if (settings.keepFoldersOpen) { + getBrowser().storage.local.get('keepopen-' + props.id).then(r => { + setFolderOpen(r['keepopen-' + props.id] == true); + }) + } else { + setFolderOpen(false); + } + getBrowser().bookmarks.get(props.id).then(r => { + setBmData(r[0]) + }) + }, []); + + if (!bmData) return; // Dragging - function handleDragStart(e: React.DragEvent<HTMLAnchorElement>) { + const handleDragStart = (e: React.DragEvent<HTMLAnchorElement>) => { e.dataTransfer.setData("sowgro", "placeholder") - } + }; - function handleDrag() { - setActiveDrag(props.data); - } + const handleDrag = () => { + setActiveDrag(bmData); + }; - function handleDragEnd() { + const handleDragEnd = () => { console.log("drop end") setActiveDrag(null); - } + }; // Dropping - function handleDropLeft() { + const handleDropLeft = () => { console.log("drop left folder") getBrowser().bookmarks.move(activeDrag!.id, { - parentId: props.data.parentId, - index: props.data.index + parentId: bmData.parentId, + index: bmData.index }) location.reload() - } + }; - function handleDropRight() { + const handleDropRight = () => { console.log("drop right folder") getBrowser().bookmarks.move(activeDrag!.id, { - parentId: props.data.parentId, - index: (props.data.index! + 1) + parentId: bmData.parentId, + index: (bmData.index! + 1) }) location.reload(); - } + }; - function handleDropCenter() { + const handleDropCenter = () => { console.log("drop center folder") getBrowser().bookmarks.move(activeDrag!.id, { - parentId: props.data.id + parentId: bmData.id }); location.reload() - } + }; + + const handleDelete = () => { + getBrowser().bookmarks.removeTree(bmData.id); + location.reload(); + }; + + const handleEdit = (e: React.MouseEvent<HTMLButtonElement>) => { + e.preventDefault(); + setActiveEdit(bmData); + }; return( <> <div className={"bookmark"}> - <a onClick={() => setFolderOpen(!folderOpen)} draggable={settings.editMode} onDrag={handleDrag} onDragEnd={handleDragEnd}> + <a onClick={() => setFolderOpen(!folderOpen)} draggable={settings.editMode} onDrag={handleDrag} + onDragStart={handleDragStart} onDragEnd={handleDragEnd}> <div className="icon-box"> {folderOpen ? <FolderIconOpen/> : <FolderIcon/>} </div> - <span>{props.data.title}</span> + <span>{bmData.title}</span> </a> - {activeDrag && activeDrag !== props.data && + {settings.editMode && <ContextMenu onEdit={handleEdit} onDelete={handleDelete}/>} + {activeDrag && activeDrag !== bmData && <DropTargets onDropLeft={handleDropLeft} onDropRight={handleDropRight} onDropCenter={handleDropCenter}/>} </div> - {folderOpen && props.data.children && props.data.children.length > 0 && - <FolderBody data={props.data}/>} + {folderOpen && /*bmData.children && bmData.children.length > 0 &&*/ + <FolderBody id={bmData.id}/>} </> ); } diff --git a/extension/src/components/SettingsEditor.tsx b/extension/src/components/SettingsEditor.tsx index d11158e..2ad5104 100644 --- a/extension/src/components/SettingsEditor.tsx +++ b/extension/src/components/SettingsEditor.tsx @@ -1,5 +1,5 @@ import RadioButtonGroup from "./RadioButtonGroup.tsx"; -import React, {useContext} from "react"; +import React, {useContext, useEffect, useState} from "react"; import CloseIcon from "../assets/close.svg?react" import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; import {Settings} from "./Body.tsx"; @@ -11,9 +11,16 @@ import {getBrowser} from "../main.tsx"; * @param props.tree The full bookmarks tree (for use in the root selector) * @param props.isOpen State for weather the menu is open */ -function SettingsEditor(props: {tree: BookmarkTreeNode[], isOpen: [boolean, React.Dispatch<React.SetStateAction<boolean>>]}) { +function SettingsEditor(props: {isOpen: [boolean, React.Dispatch<React.SetStateAction<boolean>>]}) { const [settings, setSettings] = useContext(Settings) const [open, setOpen] = props.isOpen; + const [folders, setFolders] = useState<BookmarkTreeNode[] | undefined>() + + useEffect(() => { + getFoldersFromTree().then(r => setFolders(r)); + }, []); + + if (!folders) return; return ( <div id="settings-menu" className={open ? "open" : "closed"}> @@ -74,13 +81,31 @@ function SettingsEditor(props: {tree: BookmarkTreeNode[], isOpen: [boolean, Rea <h3>Root folder</h3> <select value={settings.rootFolder!} onChange={e => setSettings({...settings, rootFolder: e.target.value})}> - {getFoldersFromTree(props.tree).map(i => + {folders.map(i => <option value={i.id}>{i.title ? i.title : "Untitled (id:" + i.id + ")"}</option> )} </select> <h3>Icon Cache</h3> - <button onClick={_ => getBrowser().storage.local.clear()}>Clear Icon Cache</button> + <button className={"default"} onClick={_ => getBrowser().storage.local.clear()}>Clear Icon Cache</button> + + {/*<h3>Editing</h3>*/} + {/*<label>*/} + {/* <input type={"checkbox"}*/} + {/* checked={!settings.editMode}*/} + {/* onChange={e => setSettings({...settings, editMode: !e.target.checked})}*/} + {/* />*/} + {/* Prevent editing of bookmarks*/} + {/*</label>*/} + + <h3>Open Folders</h3> + <label> + <input type={"checkbox"} + checked={settings.keepFoldersOpen} + onChange={e => setSettings({...settings, keepFoldersOpen: e.target.checked})} + /> + Keep folders open + </label> </div> ) @@ -91,7 +116,8 @@ function SettingsEditor(props: {tree: BookmarkTreeNode[], isOpen: [boolean, Rea * * @param tree The full tree to walk through */ -function getFoldersFromTree(tree: BookmarkTreeNode[]) { +async function getFoldersFromTree() { + let tree = await getBrowser().bookmarks.getTree(); let folderList: BookmarkTreeNode[] = []; rec(tree); |