Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/extension/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dockmark/extension",
"version": "1.5.4",
"version": "1.5.5",
"private": true,
"type": "module",
"scripts": {
Expand Down
7 changes: 6 additions & 1 deletion apps/extension/public/newtab-library-cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
}

const previousSessions = asArray(snapshot.sessions);
const [bookmarkPayload, categoryPayload, workspacePayload, enginePayload, settingsPayload] = await Promise.all([
const [bookmarkPayload, categoryPayload, workspacePayload, enginePayload, settingsPayload, appearancePayload] = await Promise.all([
requestJson("/api/bookmarks"),
requestJson("/api/categories"),
requestJson("/api/workspaces"),
requestJson("/api/search-engines"),
requestJson("/api/settings/browser"),
requestJson("/api/settings/appearance").catch(() => null),
]);

let sessions = previousSessions;
Expand All @@ -32,6 +33,9 @@
: {};

settings = normalizeSettings(settingsPayload?.settings);
const appearancePreference = window.dockmarkAppearance?.apply(
appearancePayload?.settings?.preference ?? snapshot.appearancePreference ?? "system",
) ?? "system";
snapshot = {
version: CACHE_VERSION,
origin,
Expand All @@ -46,6 +50,7 @@
searchEngines: asArray(enginePayload?.engines),
smartCollections: asArray(settingsPayload?.smartCollections),
inboxBookmarkIds: asArray(settingsPayload?.inboxBookmarkIds).filter((id) => typeof id === "string" && id.trim()),
appearancePreference,
};

await chrome.storage.local.set({
Expand Down
38 changes: 38 additions & 0 deletions apps/extension/public/newtab-theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
(() => {
const STORAGE_KEY = "dockmarkAppearanceV1";

function normalize(value) {
return value === "light" || value === "dark" || value === "system" ? value : "system";
}

function resolved(preference) {
if (preference === "system") {
return matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";
}
return preference;
}

function apply(preference, persist = true) {
const normalized = normalize(preference);
const theme = resolved(normalized);
document.documentElement.dataset.appearance = normalized;
document.documentElement.dataset.theme = theme;
document.documentElement.style.colorScheme = theme;
const meta = document.querySelector('meta[name="theme-color"]');
if (meta) meta.setAttribute("content", theme === "light" ? "#f4f7f5" : "#0a0f0c");
if (persist) localStorage.setItem(STORAGE_KEY, normalized);
return normalized;
}

function current() {
return normalize(localStorage.getItem(STORAGE_KEY));
}

apply(current(), false);
const media = matchMedia("(prefers-color-scheme: light)");
media.addEventListener("change", () => {
if (current() === "system") apply("system", false);
});

window.dockmarkAppearance = { apply, current };
})();
54 changes: 53 additions & 1 deletion apps/extension/public/newtab.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
:root {
color-scheme: dark;
color-scheme: light dark;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--dm-bg: #0a0f0c;
--dm-surface: #0f1512;
Expand Down Expand Up @@ -119,3 +119,55 @@ button:focus-visible, input:focus-visible, a:focus-visible { outline: 2px solid
.footer { align-items: flex-start; flex-direction: column; }
.footer-actions { justify-content: flex-start; flex-wrap: wrap; }
}


html[data-theme="light"] {
--dm-bg: #f4f7f5;
--dm-surface: #edf2ef;
--dm-surface-raised: #ffffff;
--dm-surface-hover: #e7efea;
--dm-surface-selected: #dceae1;
--dm-input-bg: #ffffff;
--dm-border: #d1ddd6;
--dm-border-strong: #b7c9bf;
--dm-text: #173126;
--dm-text-soft: #4e665b;
--dm-text-muted: #73867c;
--dm-placeholder: #91a097;
--dm-accent: #4f8063;
--dm-accent-strong: #315f47;
--dm-focus-ring: rgba(79, 128, 99, .14);
}

html[data-theme="light"] body {
background:
radial-gradient(circle at 18% 0%, rgba(81, 132, 101, .11), transparent 34rem),
radial-gradient(circle at 85% 12%, rgba(86, 115, 98, .05), transparent 26rem),
var(--dm-bg);
}
html[data-theme="light"] .state-chip,
html[data-theme="light"] .icon-button,
html[data-theme="light"] .ghost-button,
html[data-theme="light"] .command-input,
html[data-theme="light"] .panel,
html[data-theme="light"] .setup-card {
border-color: var(--dm-border);
background: rgba(255,255,255,.86);
color: var(--dm-text-soft);
}
html[data-theme="light"] .command-input { box-shadow: 0 18px 60px rgba(40,67,54,.08); color: var(--dm-text); }
html[data-theme="light"] .command-results { border-color: var(--dm-border-strong); background: rgba(255,255,255,.985); box-shadow: 0 26px 80px rgba(40,67,54,.14); }
html[data-theme="light"] .result-row { border-color: var(--dm-border); }
html[data-theme="light"] .bookmark-card,
html[data-theme="light"] .workspace-card { border-color: var(--dm-border); background: #fff; color: var(--dm-text-soft); }
html[data-theme="light"] .bookmark-card:hover,
html[data-theme="light"] .workspace-card:hover,
html[data-theme="light"] .result-row:hover,
html[data-theme="light"] .result-row.active,
html[data-theme="light"] .icon-button:hover,
html[data-theme="light"] .ghost-button:hover { border-color: #a8c7b5; background: var(--dm-surface-selected); color: var(--dm-text); }
html[data-theme="light"] .state-chip.online { border-color: #a8cbb5; color: #315f47; background: #eef8f1; }
html[data-theme="light"] .state-chip.offline,
html[data-theme="light"] .offline-banner { border-color: #dfc995; color: #7a6328; background: #fff8e9; }
html[data-theme="light"] .footer,
html[data-theme="light"] .footer-button { color: var(--dm-text-muted); }
3 changes: 2 additions & 1 deletion apps/extension/public/newtab.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="dark" />
<meta name="color-scheme" content="light dark" />
<meta name="theme-color" content="#0a0f0c" />
<title>Dockmark New Tab</title>
<link rel="icon" href="newtab-icon.svg" type="image/svg+xml" />
<script src="newtab-theme.js"></script>
<link rel="stylesheet" href="newtab.css" />
</head>
<body>
Expand Down
9 changes: 8 additions & 1 deletion apps/extension/public/newtab.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function emptySnapshot() {
categories: [],
workspaces: [],
searchEngines: [],
appearancePreference: "system",
};
}

Expand Down Expand Up @@ -284,15 +285,19 @@ async function refreshCloud({ quiet = false } = {}) {
throw new Error("Dockmark site access is not granted. Open the extension popup and reconnect this origin.");
}

const [bookmarkPayload, categoryPayload, workspacePayload, enginePayload, settingsPayload] = await Promise.all([
const [bookmarkPayload, categoryPayload, workspacePayload, enginePayload, settingsPayload, appearancePayload] = await Promise.all([
requestJson("/api/bookmarks"),
requestJson("/api/categories"),
requestJson("/api/workspaces"),
requestJson("/api/search-engines"),
requestJson("/api/settings/browser"),
requestJson("/api/settings/appearance").catch(() => null),
]);

settings = normalizeSettings(settingsPayload.settings);
const appearancePreference = window.dockmarkAppearance?.apply(
appearancePayload?.settings?.preference ?? snapshot.appearancePreference ?? "system",
) ?? "system";
snapshot = {
version: CACHE_VERSION,
origin,
Expand All @@ -301,6 +306,7 @@ async function refreshCloud({ quiet = false } = {}) {
categories: asArray(categoryPayload.categories),
workspaces: asArray(workspacePayload.workspaces),
searchEngines: asArray(enginePayload.engines),
appearancePreference,
};
await chrome.storage.local.set({
[CACHE_KEY]: snapshot,
Expand Down Expand Up @@ -568,6 +574,7 @@ async function bootstrap() {
origin = validOrigin(stored[SERVER_KEY]);
settings = normalizeSettings(stored[SETTINGS_KEY]);
if (cacheIsUsable(stored[CACHE_KEY], origin)) snapshot = stored[CACHE_KEY];
if (snapshot.appearancePreference) window.dockmarkAppearance?.apply(snapshot.appearancePreference);

await loadOpenTabs();
renderSnapshot();
Expand Down
2 changes: 1 addition & 1 deletion apps/extension/wxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default defineConfig({
modules: ["@wxt-dev/module-react"],
manifest: ({ browser }) => ({
name: "Dockmark",
version: "1.5.4",
version: "1.5.5",
description: "Browser bridge for Dockmark tabs, reviewed Capture Inbox, sessions, Smart Collection-aware local-first search, reviewed bookmark sync, local health checks and device pairing.",
icons: {
16: "icons/dockmark-16.png",
Expand Down
90 changes: 68 additions & 22 deletions apps/web/src/BookmarkManager.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useMemo, useState } from "react";
import type { Bookmark, Category } from "@dockmark/core";
import { AiOrganizationSettings } from "./AiOrganizationSettings";
import { BookmarkMaintenance } from "./BookmarkMaintenance";
import { BookmarkManager as ExistingBookmarkManager } from "./BookmarkManagerLegacy";
import { ChangeJournal } from "./ChangeJournal";
import { LibraryBulkMaintenance } from "./LibraryBulkMaintenance";
Expand All @@ -13,7 +15,17 @@ interface Props {
onChanged: () => Promise<void>;
}

type LibraryView = "library" | "organize" | "health" | "history";

const views: Array<{ id: LibraryView; label: string; detail: string }> = [
{ id: "library", label: "Library", detail: "Create, edit, categorize and reorder bookmarks." },
{ id: "organize", label: "Organize", detail: "Bulk moves, tags and AI-assisted organization." },
{ id: "health", label: "Health", detail: "Metadata, health checks, cleanup and archive review." },
{ id: "history", label: "History", detail: "Review recent library changes." },
];

export function BookmarkManager({ bookmarks, categories, bookmarkTags, loading, onChanged }: Props) {
const [view, setView] = useState<LibraryView>("library");
const [journalRevision, setJournalRevision] = useState(0);
const categoryNameById = useMemo(
() => new Map(categories.map((category) => [category.id, category.name])),
Expand All @@ -26,27 +38,61 @@ export function BookmarkManager({ bookmarks, categories, bookmarkTags, loading,
}

return (
<>
<LibraryBulkOrganizer
bookmarks={bookmarks}
categories={categories}
bookmarkTags={bookmarkTags}
onChanged={onBulkChanged}
/>
<LibraryBulkMaintenance
bookmarks={bookmarks}
bookmarkTags={bookmarkTags}
categoryNameById={categoryNameById}
onChanged={onBulkChanged}
/>
<ChangeJournal revision={String(journalRevision)} />
<ExistingBookmarkManager
bookmarks={bookmarks}
categories={categories}
bookmarkTags={bookmarkTags}
loading={loading}
onChanged={onChanged}
/>
</>
<section className="bookmark-management-hub">
<nav className="section-tabs" aria-label="Bookmark management sections">
{views.map((item) => (
<button
key={item.id}
className={view === item.id ? "active" : ""}
type="button"
aria-current={view === item.id ? "page" : undefined}
onClick={() => setView(item.id)}
>
<strong>{item.label}</strong>
<span>{item.detail}</span>
</button>
))}
</nav>

{view === "library" && (
<ExistingBookmarkManager
bookmarks={bookmarks}
categories={categories}
bookmarkTags={bookmarkTags}
loading={loading}
onChanged={onChanged}
/>
)}

{view === "organize" && (
<div className="bookmark-section-stack">
<LibraryBulkOrganizer
bookmarks={bookmarks}
categories={categories}
bookmarkTags={bookmarkTags}
onChanged={onBulkChanged}
/>
<AiOrganizationSettings
bookmarks={bookmarks}
categories={categories}
onChanged={onBulkChanged}
/>
</div>
)}

{view === "health" && (
<div className="bookmark-section-stack">
<LibraryBulkMaintenance
bookmarks={bookmarks}
bookmarkTags={bookmarkTags}
categoryNameById={categoryNameById}
onChanged={onBulkChanged}
/>
<BookmarkMaintenance bookmarks={bookmarks} onChanged={onBulkChanged} />
</div>
)}

{view === "history" && <ChangeJournal revision={String(journalRevision)} />}
</section>
);
}
Loading
Loading