aboutsummaryrefslogtreecommitdiff
path: root/extension/src
diff options
context:
space:
mode:
Diffstat (limited to 'extension/src')
-rw-r--r--extension/src/Settings.ts4
-rw-r--r--extension/src/assets/close.svg2
-rw-r--r--extension/src/assets/edit.svg1
-rw-r--r--extension/src/assets/folder.svg2
-rw-r--r--extension/src/assets/folder_open.svg2
-rw-r--r--extension/src/assets/globe.svg2
-rw-r--r--extension/src/assets/settings.svg2
-rw-r--r--extension/src/colortheif.d.ts15
-rw-r--r--extension/src/components/Body.tsx17
-rw-r--r--extension/src/components/Bookmark-backup.txt161
-rw-r--r--extension/src/components/Bookmark.tsx71
-rw-r--r--extension/src/components/FolderButton.tsx25
-rw-r--r--extension/src/components/SettingsEditor.tsx13
-rw-r--r--extension/src/index.css129
-rw-r--r--extension/src/vite-env.d.ts1
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