diff options
Diffstat (limited to 'extension/src')
-rw-r--r-- | extension/src/Settings.ts | 4 | ||||
-rw-r--r-- | extension/src/assets/close.svg | 2 | ||||
-rw-r--r-- | extension/src/assets/edit.svg | 1 | ||||
-rw-r--r-- | extension/src/assets/folder.svg | 2 | ||||
-rw-r--r-- | extension/src/assets/folder_open.svg | 2 | ||||
-rw-r--r-- | extension/src/assets/globe.svg | 2 | ||||
-rw-r--r-- | extension/src/assets/settings.svg | 2 | ||||
-rw-r--r-- | extension/src/colortheif.d.ts | 15 | ||||
-rw-r--r-- | extension/src/components/Body.tsx | 17 | ||||
-rw-r--r-- | extension/src/components/Bookmark-backup.txt | 161 | ||||
-rw-r--r-- | extension/src/components/Bookmark.tsx | 71 | ||||
-rw-r--r-- | extension/src/components/FolderButton.tsx | 25 | ||||
-rw-r--r-- | extension/src/components/SettingsEditor.tsx | 13 | ||||
-rw-r--r-- | extension/src/index.css | 129 | ||||
-rw-r--r-- | extension/src/vite-env.d.ts | 1 |
15 files changed, 395 insertions, 52 deletions
diff --git a/extension/src/Settings.ts b/extension/src/Settings.ts index ce6c344..853058f 100644 --- a/extension/src/Settings.ts +++ b/extension/src/Settings.ts @@ -24,12 +24,12 @@ export let defaultSettings: ISettings = { export function loadSettings(): Promise<ISettings> { // @ts-ignore - let tmp: Promise<ISettings> = getBrowser().storage.local.get(defaultSettings); + let tmp: Promise<ISettings> = getBrowser().storage.sync.get(defaultSettings); tmp.then(j => console.log(j)) return tmp; } export function writeSettings(settings: ISettings) { - getBrowser().storage.local.set(settings); + getBrowser().storage.sync.set(settings); } diff --git a/extension/src/assets/close.svg b/extension/src/assets/close.svg index 8c71124..83a6cce 100644 --- a/extension/src/assets/close.svg +++ b/extension/src/assets/close.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>
\ No newline at end of file diff --git a/extension/src/assets/edit.svg b/extension/src/assets/edit.svg new file mode 100644 index 0000000..9182fd3 --- /dev/null +++ b/extension/src/assets/edit.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M120-120v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm584-528 56-56-56-56-56 56 56 56Z"/></svg>
\ No newline at end of file diff --git a/extension/src/assets/folder.svg b/extension/src/assets/folder.svg index 45d526a..c487795 100644 --- a/extension/src/assets/folder.svg +++ b/extension/src/assets/folder.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Z"/></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640v400q0 33-23.5 56.5T800-160H160Z"/></svg>
\ No newline at end of file diff --git a/extension/src/assets/folder_open.svg b/extension/src/assets/folder_open.svg index 75ecf42..a6def6c 100644 --- a/extension/src/assets/folder_open.svg +++ b/extension/src/assets/folder_open.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640H160v400l96-320h684L837-217q-8 26-29.5 41.5T760-160H160Z"/></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640H160v400l96-320h684L837-217q-8 26-29.5 41.5T760-160H160Z"/></svg>
\ No newline at end of file diff --git a/extension/src/assets/globe.svg b/extension/src/assets/globe.svg index b87a4d9..2f98c9d 100644 --- a/extension/src/assets/globe.svg +++ b/extension/src/assets/globe.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm-40-82v-78q-33 0-56.5-23.5T360-320v-40L168-552q-3 18-5.5 36t-2.5 36q0 121 79.5 212T440-162Zm276-102q20-22 36-47.5t26.5-53q10.5-27.5 16-56.5t5.5-59q0-98-54.5-179T600-776v16q0 33-23.5 56.5T520-680h-80v80q0 17-11.5 28.5T400-560h-80v80h240q17 0 28.5 11.5T600-440v120h40q26 0 47 15.5t29 40.5Z"/></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm-40-82v-78q-33 0-56.5-23.5T360-320v-40L168-552q-3 18-5.5 36t-2.5 36q0 121 79.5 212T440-162Zm276-102q20-22 36-47.5t26.5-53q10.5-27.5 16-56.5t5.5-59q0-98-54.5-179T600-776v16q0 33-23.5 56.5T520-680h-80v80q0 17-11.5 28.5T400-560h-80v80h240q17 0 28.5 11.5T600-440v120h40q26 0 47 15.5t29 40.5Z"/></svg>
\ No newline at end of file diff --git a/extension/src/assets/settings.svg b/extension/src/assets/settings.svg index 551161c..cbc41c7 100644 --- a/extension/src/assets/settings.svg +++ b/extension/src/assets/settings.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="m370-80-16-128q-13-5-24.5-12T307-235l-119 50L78-375l103-78q-1-7-1-13.5v-27q0-6.5 1-13.5L78-585l110-190 119 50q11-8 23-15t24-12l16-128h220l16 128q13 5 24.5 12t22.5 15l119-50 110 190-103 78q1 7 1 13.5v27q0 6.5-2 13.5l103 78-110 190-118-50q-11 8-23 15t-24 12L590-80H370Zm112-260q58 0 99-41t41-99q0-58-41-99t-99-41q-59 0-99.5 41T342-480q0 58 40.5 99t99.5 41Z"/></svg>
\ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="m370-80-16-128q-13-5-24.5-12T307-235l-119 50L78-375l103-78q-1-7-1-13.5v-27q0-6.5 1-13.5L78-585l110-190 119 50q11-8 23-15t24-12l16-128h220l16 128q13 5 24.5 12t22.5 15l119-50 110 190-103 78q1 7 1 13.5v27q0 6.5-2 13.5l103 78-110 190-118-50q-11 8-23 15t-24 12L590-80H370Zm112-260q58 0 99-41t41-99q0-58-41-99t-99-41q-59 0-99.5 41T342-480q0 58 40.5 99t99.5 41Z"/></svg>
\ No newline at end of file diff --git a/extension/src/colortheif.d.ts b/extension/src/colortheif.d.ts new file mode 100644 index 0000000..8e98fdf --- /dev/null +++ b/extension/src/colortheif.d.ts @@ -0,0 +1,15 @@ +declare module "colorthief" { + export type RGBColor = [number, number, number] + export default class ColorThief { + getColor: ( + img: HTMLImageElement | null, + quality: number = 10, + ) => RGBColor | null + + getPalette: ( + img: HTMLImageElement | null, + colorCount: number = 10, + quality: number = 10, + ) => RGBColor[] | null + } +}
\ No newline at end of file diff --git a/extension/src/components/Body.tsx b/extension/src/components/Body.tsx index 6498a0a..e575d89 100644 --- a/extension/src/components/Body.tsx +++ b/extension/src/components/Body.tsx @@ -1,6 +1,7 @@ import React, {useEffect, useState} from "react"; import SettingsEditor from "./SettingsEditor.tsx"; -import imageUrl from "../assets/settings.svg" +import SettingsIcon from "../assets/settings.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"; @@ -33,7 +34,7 @@ function Body() { useEffect(() => { writeSettings(settings); - if (settings?.rootFolder) { + if (settings.rootFolder) { getBrowser().bookmarks.getSubTree(settings.rootFolder).then(t => { setSelectedBookmarkTree(t); }); @@ -51,9 +52,15 @@ function Body() { case "image": return (<style>{"body {background-image: url(\"" + settings.backgroundImage + "\"); }"}</style>) }})()} <style>{"body > .folderBody, a {color: " + settings.foregroundColor + "; }"}</style> - <button id="settings-button" onClick={_ => setSettingsOpen(!settingsOpen)}> - <img alt="open settings" src={imageUrl}/> - </button> + <div id={"action-area"}> + {settings.editMode && <span>Move mode: Drag bookmarks to change order</span>} + <button onClick={_ => setSettings({...settings, editMode: !settings.editMode})}> + <EditIcon fill={settings.editMode? "lime" : "currentColor"}/> + </button> + <button onClick={_ => setSettingsOpen(!settingsOpen)}> + <SettingsIcon/> + </button> + </div> <SettingsEditor tree={fullBookmarkTree!} isOpen={[settingsOpen, setSettingsOpen]}/> {selectedBookmarkTree[0] && (<FolderBody data={selectedBookmarkTree[0]}/>)} </Settings.Provider> diff --git a/extension/src/components/Bookmark-backup.txt b/extension/src/components/Bookmark-backup.txt new file mode 100644 index 0000000..4d1eb60 --- /dev/null +++ b/extension/src/components/Bookmark-backup.txt @@ -0,0 +1,161 @@ +import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; +import React, {SyntheticEvent, useEffect} from "react"; +import {getBrowser} from "../main.tsx"; +import {Settings} from "./Body.tsx"; +import react from "@vitejs/plugin-react"; + +/** + * A component for a single bookmark + * + * @param props.data The BookmarkTreeNode with the data for the bookmark + */ +function Bookmark(props: {data: BookmarkTreeNode}) { + let [favicon, setFavicon] = React.useState<string | null>(null); + let [iconMode, setIconMode] = React.useState<"large" | "small" | "letter">("letter"); + let [settings, setSettings] = React.useContext(Settings); + let [bgColor, setBgColor] = React.useState<[number, number, number] | null>(null) + // let [dropRight, setDropRight] = React.useState(false); + // let [dropLeft, setDropLeft] = React.useState(false); + // let [dropCenter, setDropCenter] = React.useState(false); + + useEffect(() => { + setBgColor([255, 0, 0]) + // faviconURL(props.data.url).then(o => o && setFavicon(o)) + faviconURL(props.data).then(r => { + if (r) { + setFavicon(r) + setIconMode("small"); + } + }) + }, []); + + // useEffect(() => { + // console.log("signal received", dropCenter) + // }, [dropCenter]); + + function handleImageLoad(e: SyntheticEvent<HTMLImageElement, Event>) { + if (e.currentTarget.naturalWidth >= 75 || favicon!.startsWith("data:image/svg+xml")) { + setIconMode("large") + } + } + + return( + <div className={"bookmark"}> + <a draggable={settings.editMode} href={props.data.url} + // onDragStart={e => { + // console.log("dragStart") + // e.dataTransfer.dropEffect = "move"; + // e.dataTransfer.setData("bm-id", props.data.id); + // }} + > + <div className={"icon-box " + (iconMode)} + style={bgColor ? {"--icon-bg": `rgba(${bgColor[0]}, ${bgColor[1]}, ${bgColor[2]}, 0.2)`} as React.CSSProperties : undefined}> + {favicon ? ( + <img alt="Bookmark icon" + draggable={false} + src={favicon} + onLoad={handleImageLoad} + /> + ) : ( + <span className={"letter"}>{new URL(props.data.url!).hostname.charAt(0)}</span> + )} + + </div> + <span>{props.data.title}</span> + </a> + {/*<div className={"drop-targets"}>*/} + {/* <div*/} + {/* className={"left"}*/} + {/* onDragEnter={_ => setDropLeft(true)}*/} + {/* onDragLeave={_ => setDropRight(false)}*/} + {/* onDrop={e => getBrowser().bookmarks.move(e.dataTransfer.getData("bm-id"), {parentId: props.data.parentId, index: props.data.index})}*/} + {/* style={dropLeft ? undefined : {visibility: "hidden"}}*/} + {/* // hidden={!dropLeft}*/} + {/* >*/} + {/* <div/>*/} + {/* </div>*/} + {/* <div*/} + {/* className={"right"}*/} + {/* onDragEnter={_ => setDropLeft(true)}*/} + {/* onDragLeave={_ => setDropRight(false)}*/} + {/* onDrop={e => getBrowser().bookmarks.move(e.dataTransfer.getData("bm-id"), {parentId: props.data.parentId, index: (props.data.index! + 1)})}*/} + {/* style={dropRight ? undefined : {visibility: "hidden"}}*/} + {/* // hidden={!dropRight}*/} + {/* >*/} + {/* <div/>*/} + {/* </div>*/} + {/* <div*/} + {/* className={"center"}*/} + {/* onDragOver={e => {*/} + {/* e.preventDefault()*/} + {/* // console.log("dropped")*/} + {/* }}*/} + {/* onDragEnter={e => {*/} + {/* e.preventDefault()*/} + {/* setDropCenter(true)*/} + {/* console.log("enter")*/} + {/* }}*/} + {/* onDragLeave={_ => {*/} + {/* setDropCenter(false)*/} + {/* console.log("exit")*/} + {/* }}*/} + {/* onDrop={e => {*/} + {/* e.preventDefault();*/} + {/* console.log("dropped")*/} + {/* }}*/} + {/* style={dropCenter ? undefined : {visibility: "hidden"}}*/} + {/* // hidden={!dropCenter}*/} + {/* >*/} + {/* <span>+</span>*/} + {/* </div>*/} + {/*</div>*/} + </div> + ); +} + +/** + * Gets the icon for a bookmark + * + * @param data The URL of the link + * @return The URL of the icon + */ +async function faviconURL(data: BookmarkTreeNode) { + let i = (await getBrowser().storage.local.get("icon-cache-"+data.id))["icon-cache-"+data.id]; + if (i) return i + + const url = new URL('https://www.google.com/s2/favicons'); + url.searchParams.set("sz", "256"); + url.searchParams.set("domain_url", data.url!); + let resp = await fetch(url) + let imgData = resp.ok ? await toDataURL(url.toString()) : null; + getBrowser().storage.local.set({["icon-cache-"+data.id]: imgData}); + return imgData; +} + +function toDataURL(url:string):string { + // @ts-ignore + return fetch(url) + .then(response => response.blob()) + .then(blob => new Promise((resolve, reject) => { + const reader = new FileReader() + reader.onloadend = () => resolve(reader.result) + reader.onerror = reject + reader.readAsDataURL(blob) + })) +} + +// function hashColor(url:string) { +// hashCode(String) +// } +// +// function hashCode(str: string) { +// let hash = 0; +// for (let i = 0, len = str.length; i < len; i++) { +// let chr = str.charCodeAt(i); +// hash = (hash << 5) - hash + chr; +// hash |= 0; // Convert to 32bit integer +// } +// return hash; +// } + +export default Bookmark;
\ No newline at end of file diff --git a/extension/src/components/Bookmark.tsx b/extension/src/components/Bookmark.tsx index 839a9f5..d1c1756 100644 --- a/extension/src/components/Bookmark.tsx +++ b/extension/src/components/Bookmark.tsx @@ -1,7 +1,9 @@ import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; -import GlobeIcon from "../assets/globe.svg" import React, {SyntheticEvent, useEffect} from "react"; import {getBrowser} from "../main.tsx"; +import {Settings} from "./Body.tsx"; +import ColorThief from 'colorthief' +import react from "@vitejs/plugin-react"; /** * A component for a single bookmark @@ -9,27 +11,51 @@ import {getBrowser} from "../main.tsx"; * @param props.data The BookmarkTreeNode with the data for the bookmark */ function Bookmark(props: {data: BookmarkTreeNode}) { - let [favicon, setFavicon] = React.useState(GlobeIcon); - let [isSmall, setSmall] = React.useState(true); + let [favicon, setFavicon] = React.useState<string | null>(null); + let [iconMode, setIconMode] = React.useState<"large" | "small" | "letter">("letter"); + let [settings, setSettings] = React.useContext(Settings); + let [bgColor, setBgColor] = React.useState<[number, number, number] | null>(null) + useEffect(() => { - // faviconURL(props.data.url).then(o => o && setFavicon(o)) faviconURL(props.data).then(r => { if (r) { setFavicon(r) + setIconMode("small"); } }) }, []); + function handleImageLoad(e: SyntheticEvent<HTMLImageElement, Event>) { + if (e.currentTarget.naturalWidth >= 75 || favicon!.startsWith("data:image/svg+xml")) { + setIconMode("large") + } else if(!bgColor) { + setBgColor(new ColorThief().getColor(e.currentTarget)) + } + } + return( - <a className="bookmark draggable" href={props.data.url}> - <div className={"icon-box" + (isSmall ? " small" : "")}> - <img alt="Bookmark icon" - src={favicon} - onLoad={(e) => setSmall(e.currentTarget.naturalWidth < 75 && !favicon.startsWith("data:image/svg+xml"))} - ></img> - </div> - <span>{props.data.title}</span> - </a> + <div className={"bookmark"}> + <a draggable={settings.editMode} href={props.data.url}> + <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 (!bgColor) { + setBgColor(hashStringToColor(url.hostname)); + } + 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> + </a> + </div> ); } @@ -42,12 +68,13 @@ function Bookmark(props: {data: BookmarkTreeNode}) { async function faviconURL(data: BookmarkTreeNode) { let i = (await getBrowser().storage.local.get("icon-cache-"+data.id))["icon-cache-"+data.id]; if (i) return i + if (i == null) return i; const url = new URL('https://www.google.com/s2/favicons'); url.searchParams.set("sz", "256"); url.searchParams.set("domain_url", data.url!); let resp = await fetch(url) - let imgData = resp.ok ? await toDataURL(url.toString()) : GlobeIcon; + let imgData = resp.ok ? await toDataURL(url.toString()) : null; getBrowser().storage.local.set({["icon-cache-"+data.id]: imgData}); return imgData; } @@ -64,4 +91,20 @@ function toDataURL(url:string):string { })) } +function djb2(str: string){ + var hash = 5381; + for (var i = 0; i < str.length; i++) { + hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */ + } + return hash; +} + +function hashStringToColor(str: string): [number, number, number] { + var hash = djb2(str); + var r = (hash & 0xFF0000) >> 16; + var g = (hash & 0x00FF00) >> 8; + var b = hash & 0x0000FF; + return [r, g, b]; +} + export default Bookmark;
\ No newline at end of file diff --git a/extension/src/components/FolderButton.tsx b/extension/src/components/FolderButton.tsx index 42e5d60..2b59d56 100644 --- a/extension/src/components/FolderButton.tsx +++ b/extension/src/components/FolderButton.tsx @@ -1,8 +1,9 @@ import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; import FolderBody from "./FolderBody.tsx"; -import folderIcon from "../assets/folder.svg" -import folderIconOpen from "../assets/folder_open.svg" +import FolderIcon from "../assets/folder.svg?react" +import FolderIconOpen from "../assets/folder_open.svg?react" import {useState} from "react"; +import bookmark from "./Bookmark.tsx"; /** * A component for the button used to open a bookmark folder. @@ -15,16 +16,18 @@ function FolderButton(props: {data: BookmarkTreeNode}) { return( <> - <a className="bookmark draggable" onClick={() => setFolderOpen(!folderOpen)}> - <div className="icon-box"> - <img alt="Folder icon" src={folderOpen ? folderIconOpen : folderIcon}/> - </div> - <span>{props.data.title}</span> - </a> + <div className={"bookmark"}> + <a onClick={() => setFolderOpen(!folderOpen)}> + <div className="icon-box"> + {folderOpen ? <FolderIconOpen/> : <FolderIcon/>} + </div> + <span>{props.data.title}</span> + </a> + </div> {folderOpen - && props.data.children - && props.data.children.length > 0 - && (<FolderBody data={props.data}/>)} + && props.data.children + && props.data.children.length > 0 + && (<FolderBody data={props.data}/>)} </> ); } diff --git a/extension/src/components/SettingsEditor.tsx b/extension/src/components/SettingsEditor.tsx index edd99f9..d11158e 100644 --- a/extension/src/components/SettingsEditor.tsx +++ b/extension/src/components/SettingsEditor.tsx @@ -1,8 +1,9 @@ import RadioButtonGroup from "./RadioButtonGroup.tsx"; import React, {useContext} from "react"; -import imageUrl from "../assets/close.svg" +import CloseIcon from "../assets/close.svg?react" import BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; import {Settings} from "./Body.tsx"; +import {getBrowser} from "../main.tsx"; /** * A component for the settings sidebar @@ -17,7 +18,7 @@ function SettingsEditor(props: {tree: BookmarkTreeNode[], isOpen: [boolean, Rea return ( <div id="settings-menu" className={open ? "open" : "closed"}> <button id="settings-close" onClick={_ => setOpen(false)}> - <img alt="close settings" src={imageUrl}/> + <CloseIcon/> </button> <h1>Settings</h1> @@ -28,7 +29,6 @@ function SettingsEditor(props: {tree: BookmarkTreeNode[], isOpen: [boolean, Rea }}> <option value={"from-bookmarks"}>From Bookmarks</option> <option value={"alphabetical"}>Alphabetical</option> - <option value={"frequency"}>Frequency</option> <option value={"recent"}>Recently used</option> </RadioButtonGroup> <br/> @@ -79,10 +79,9 @@ function SettingsEditor(props: {tree: BookmarkTreeNode[], isOpen: [boolean, Rea )} </select> - {/*<br/>*/} - {/*<span>sort: {settings.sort}</span>*/} - {/*<span>rootFolder: {settings.rootFolder}</span>*/} - {/*<span>bgmode: {settings.backgroundMode}</span>*/} + <h3>Icon Cache</h3> + <button onClick={_ => getBrowser().storage.local.clear()}>Clear Icon Cache</button> + </div> ) } diff --git a/extension/src/index.css b/extension/src/index.css index 6b3ba69..a85aeaf 100644 --- a/extension/src/index.css +++ b/extension/src/index.css @@ -79,11 +79,15 @@ body > .folderBody { /* Bookmark */ .bookmark { + padding: 10px; + position: relative; +} + +.bookmark > a { display: flex; flex-direction: column; width: 125px; padding: 10px; - margin: 10px; user-select: none; border-radius: 10px; } @@ -96,9 +100,21 @@ body > .folderBody { justify-content: center; } -.icon-box.small { +@property --icon-bg { + syntax: "<color>"; + inherits: false; + initial-value: #ffffff14; +} + +.icon-box.small, .icon-box.letter { border-radius: 10px; - background-color: #ffffff14; + background-color: var(--icon-bg); +} + +.icon-box > span { + font-size: xx-large; + text-transform: capitalize; + font-weight: bold; } .icon-box > img { @@ -106,12 +122,17 @@ body > .folderBody { border-radius: 10px; } +.icon-box > svg { + width: 100%; + height: 100%; +} + .icon-box.small > img { width: 50%; border-radius: 5px; } -.bookmark > span { +.bookmark > a > span { text-wrap: nowrap; text-overflow: ellipsis; overflow: hidden; @@ -119,7 +140,7 @@ body > .folderBody { font-size: 12px; } -.bookmark:hover { +.bookmark > a:hover { background-color: rgba(0, 0, 0, 0.3); } @@ -128,7 +149,7 @@ a { text-decoration: none; } -#settings-close, #settings-button { +#settings-close { border-style: none; background: none; color: white; @@ -140,8 +161,100 @@ a { z-index: 2; } -#settings-close:hover, #settings-button:hover { - background-color: rgba(0, 0, 0, 0.3); +#action-area { + position: absolute; + top: 0; + right: 0; + z-index: 2; + gap: 5px; + margin: 5px; + display: flex; + flex-direction: row; + + button { + border-style: none; + background: none; + color: white; + } + + > * { + padding: 5px; + display: flex; + justify-content: center; + align-items: center; + } + + button:hover { + background-color: rgba(0, 0, 0, 0.3); + } +} + +/* Drop targets */ +.drop-targets { + pointer-events: none; + position: absolute; + top: 0; + /* bottom: 0; */ + left: 0; + right: 0; + height: 100%; + width: 100%; +} + +/*.drop-targets > *:hover {*/ +/* background-color: red;*/ +/*}*/ + +.drop-targets > .left { + position: absolute; + left: -2px; + height: 100%; + width: 30px; + display: flex; + justify-content: flex-start; + align-items: center; + + > div { + background-color: aqua; + height: 50%; + width: 4px; + } +} + +.drop-targets > .right { + position: absolute; + right: -2px; + height: 100%; + width: 30px; + display: flex; + justify-content: flex-end; + align-items: center; + + > div { + background-color: aqua; + width: 4px; + height: 50%; + } +} + +.drop-targets > .center { + position: absolute; + top: 0; + bottom: 0; + left: 30px; + right: 30px; + display: flex; + justify-content: center; + align-items: center; + + > span { + color: aqua; + font-size: 100px; + /* background-color: aqua; */ + /* aspect-ratio: 1 / 1; */ + /* height: 100px; */ + font-family: monospace; + } } diff --git a/extension/src/vite-env.d.ts b/extension/src/vite-env.d.ts index 11f02fe..fa3e1b9 100644 --- a/extension/src/vite-env.d.ts +++ b/extension/src/vite-env.d.ts @@ -1 +1,2 @@ /// <reference types="vite/client" /> +/// <reference types="vite-plugin-svgr/client" />
\ No newline at end of file |