mirror of
https://github.com/zadam/trilium.git
synced 2026-05-07 01:06:00 +02:00
Merge remote-tracking branch 'origin/main' into standalone
This commit is contained in:
@@ -25,6 +25,6 @@
|
||||
"fs-extra": "11.3.4",
|
||||
"js-yaml": "4.1.1",
|
||||
"typedoc": "0.28.18",
|
||||
"typedoc-plugin-missing-exports": "4.1.2"
|
||||
"typedoc-plugin-missing-exports": "4.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,14 +34,14 @@
|
||||
"@triliumnext/highlightjs": "workspace:*",
|
||||
"@triliumnext/share-theme": "workspace:*",
|
||||
"@triliumnext/split.js": "workspace:*",
|
||||
"@univerjs/preset-sheets-conditional-formatting": "0.19.0",
|
||||
"@univerjs/preset-sheets-core": "0.19.0",
|
||||
"@univerjs/preset-sheets-data-validation": "0.19.0",
|
||||
"@univerjs/preset-sheets-filter": "0.19.0",
|
||||
"@univerjs/preset-sheets-find-replace": "0.19.0",
|
||||
"@univerjs/preset-sheets-note": "0.19.0",
|
||||
"@univerjs/preset-sheets-sort": "0.19.0",
|
||||
"@univerjs/presets": "0.19.0",
|
||||
"@univerjs/preset-sheets-conditional-formatting": "0.20.0",
|
||||
"@univerjs/preset-sheets-core": "0.20.0",
|
||||
"@univerjs/preset-sheets-data-validation": "0.20.0",
|
||||
"@univerjs/preset-sheets-filter": "0.20.0",
|
||||
"@univerjs/preset-sheets-find-replace": "0.20.0",
|
||||
"@univerjs/preset-sheets-note": "0.20.0",
|
||||
"@univerjs/preset-sheets-sort": "0.20.0",
|
||||
"@univerjs/presets": "0.20.0",
|
||||
"@zumer/snapdom": "2.7.0",
|
||||
"autocomplete.js": "0.38.1",
|
||||
"bootstrap": "5.3.8",
|
||||
@@ -65,7 +65,7 @@
|
||||
"mermaid": "11.14.0",
|
||||
"mind-elixir": "5.10.0",
|
||||
"panzoom": "9.4.4",
|
||||
"preact": "10.29.0",
|
||||
"preact": "10.29.1",
|
||||
"react-i18next": "17.0.2",
|
||||
"react-window": "2.2.7",
|
||||
"reveal.js": "6.0.0",
|
||||
|
||||
@@ -54,7 +54,7 @@ function initOnElectron() {
|
||||
const currentWindow = electronRemote.getCurrentWindow();
|
||||
const style = window.getComputedStyle(document.body);
|
||||
|
||||
initDarkOrLightMode(style);
|
||||
initDarkOrLightMode();
|
||||
initTransparencyEffects(style, currentWindow);
|
||||
initFullScreenDetection(currentWindow);
|
||||
|
||||
@@ -119,11 +119,11 @@ function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Elec
|
||||
*
|
||||
* @param style the root CSS element to read variables from.
|
||||
*/
|
||||
function initDarkOrLightMode(style: CSSStyleDeclaration) {
|
||||
function initDarkOrLightMode() {
|
||||
let themeSource: typeof nativeTheme.themeSource = "system";
|
||||
|
||||
const themeStyle = style.getPropertyValue("--theme-style");
|
||||
if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) {
|
||||
const themeStyle = window.glob.getThemeStyle();
|
||||
if (themeStyle !== "auto") {
|
||||
themeSource = themeStyle;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { getThemeStyle } from "./services/theme";
|
||||
|
||||
async function bootstrap() {
|
||||
showSplash();
|
||||
await setupGlob();
|
||||
@@ -39,6 +41,7 @@ async function setupGlob() {
|
||||
activeDialog: null,
|
||||
device: json.device || getDevice()
|
||||
};
|
||||
window.glob.getThemeStyle = getThemeStyle;
|
||||
}
|
||||
|
||||
function getDevice() {
|
||||
@@ -76,31 +79,65 @@ async function loadBootstrapCss() {
|
||||
}
|
||||
}
|
||||
|
||||
function loadStylesheets() {
|
||||
const { device, assetPath, themeCssUrl, themeUseNextAsBase } = window.glob;
|
||||
type StylesheetRef = {
|
||||
href: string;
|
||||
media?: string;
|
||||
};
|
||||
|
||||
const cssToLoad: string[] = [];
|
||||
if (device !== "print") {
|
||||
cssToLoad.push(`${assetPath}/stylesheets/ckeditor-theme.css`);
|
||||
cssToLoad.push(`api/fonts`);
|
||||
cssToLoad.push(`${assetPath}/stylesheets/theme-light.css`);
|
||||
if (themeCssUrl) {
|
||||
cssToLoad.push(themeCssUrl);
|
||||
}
|
||||
if (themeUseNextAsBase === "next") {
|
||||
cssToLoad.push(`${assetPath}/stylesheets/theme-next.css`);
|
||||
} else if (themeUseNextAsBase === "next-dark") {
|
||||
cssToLoad.push(`${assetPath}/stylesheets/theme-next-dark.css`);
|
||||
} else if (themeUseNextAsBase === "next-light") {
|
||||
cssToLoad.push(`${assetPath}/stylesheets/theme-next-light.css`);
|
||||
}
|
||||
cssToLoad.push(`${assetPath}/stylesheets/style.css`);
|
||||
function getConfiguredThemeStylesheets(stylesheetsPath: string, theme: string, customThemeCssUrl?: string) {
|
||||
if (theme === "auto") {
|
||||
return [{ href: `${stylesheetsPath}/theme-dark.css`, media: "(prefers-color-scheme: dark)" }];
|
||||
}
|
||||
|
||||
for (const href of cssToLoad) {
|
||||
if (theme === "dark") {
|
||||
return [{ href: `${stylesheetsPath}/theme-dark.css` }];
|
||||
}
|
||||
|
||||
if (theme === "next") {
|
||||
return [
|
||||
{ href: `${stylesheetsPath}/theme-next-light.css` },
|
||||
{ href: `${stylesheetsPath}/theme-next-dark.css`, media: "(prefers-color-scheme: dark)" }
|
||||
];
|
||||
}
|
||||
|
||||
if (theme === "next-light") {
|
||||
return [{ href: `${stylesheetsPath}/theme-next-light.css` }];
|
||||
}
|
||||
|
||||
if (theme === "next-dark") {
|
||||
return [{ href: `${stylesheetsPath}/theme-next-dark.css` }];
|
||||
}
|
||||
|
||||
if (theme !== "light" && customThemeCssUrl) {
|
||||
return [{ href: customThemeCssUrl }];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function loadStylesheets() {
|
||||
const { device, assetPath, theme, themeBase, customThemeCssUrl } = window.glob;
|
||||
const stylesheetsPath = `${assetPath}/stylesheets`;
|
||||
|
||||
const cssToLoad: StylesheetRef[] = [];
|
||||
if (device !== "print") {
|
||||
cssToLoad.push({ href: `${stylesheetsPath}/ckeditor-theme.css` });
|
||||
cssToLoad.push({ href: `api/fonts` });
|
||||
cssToLoad.push({ href: `${stylesheetsPath}/theme-light.css` });
|
||||
cssToLoad.push(...getConfiguredThemeStylesheets(stylesheetsPath, theme, customThemeCssUrl));
|
||||
if (themeBase) {
|
||||
cssToLoad.push(...getConfiguredThemeStylesheets(stylesheetsPath, themeBase));
|
||||
}
|
||||
cssToLoad.push({ href: `${stylesheetsPath}/style.css` });
|
||||
}
|
||||
|
||||
for (const { href, media } of cssToLoad) {
|
||||
const linkEl = document.createElement("link");
|
||||
linkEl.href = href;
|
||||
linkEl.rel = "stylesheet";
|
||||
if (media) {
|
||||
linkEl.media = media;
|
||||
}
|
||||
document.head.appendChild(linkEl);
|
||||
}
|
||||
}
|
||||
|
||||
35
apps/client/src/services/theme.ts
Normal file
35
apps/client/src/services/theme.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export function getThemeStyle(): "auto" | "light" | "dark" {
|
||||
const configuredTheme = window.glob?.theme;
|
||||
if (configuredTheme === "auto" || configuredTheme === "next") {
|
||||
return "auto";
|
||||
}
|
||||
|
||||
if (configuredTheme === "light" || configuredTheme === "dark") {
|
||||
return configuredTheme;
|
||||
}
|
||||
|
||||
if (configuredTheme === "next-light") {
|
||||
return "light";
|
||||
}
|
||||
|
||||
if (configuredTheme === "next-dark") {
|
||||
return "dark";
|
||||
}
|
||||
|
||||
const style = window.getComputedStyle(document.body);
|
||||
const themeStyle = style.getPropertyValue("--theme-style");
|
||||
if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) {
|
||||
return themeStyle as "light" | "dark";
|
||||
}
|
||||
|
||||
return "auto";
|
||||
}
|
||||
|
||||
export function getEffectiveThemeStyle(): "light" | "dark" {
|
||||
const themeStyle = getThemeStyle();
|
||||
if (themeStyle === "auto") {
|
||||
return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
||||
}
|
||||
|
||||
return themeStyle === "dark" ? "dark" : "light";
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/* Import the light color scheme.
|
||||
* This is the base color scheme, always active and overridden by the dark
|
||||
* color scheme stylesheet when necessary. */
|
||||
@import url(./theme-next-light.css);
|
||||
|
||||
/* Import the dark color scheme when the system preference is set to dark mode */
|
||||
@import url(./theme-next-dark.css) (prefers-color-scheme: dark);
|
||||
|
||||
:root {
|
||||
--theme-style-auto: true;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/* Import the light color scheme.
|
||||
* This is the base color scheme, always active and overridden by the dark
|
||||
* color scheme stylesheet when necessary. */
|
||||
@import url(./theme-light.css);
|
||||
|
||||
/* Import the dark color scheme when the system preference is set to dark mode */
|
||||
@import url(./theme-dark.css) (prefers-color-scheme: dark);
|
||||
|
||||
:root {
|
||||
--theme-style-auto: true;
|
||||
}
|
||||
1
apps/client/src/types-lib.d.ts
vendored
1
apps/client/src/types-lib.d.ts
vendored
@@ -66,6 +66,7 @@ declare module "preact" {
|
||||
interface ElectronWebViewElement extends JSX.HTMLAttributes<HTMLElement> {
|
||||
src: string;
|
||||
class: string;
|
||||
key?: string | number;
|
||||
}
|
||||
|
||||
interface IntrinsicElements {
|
||||
|
||||
1
apps/client/src/types.d.ts
vendored
1
apps/client/src/types.d.ts
vendored
@@ -23,6 +23,7 @@ interface CustomGlobals extends BootstrapDefinition {
|
||||
getReferenceLinkTitle: (href: string) => Promise<string>;
|
||||
getReferenceLinkTitleSync: (href: string) => string;
|
||||
getActiveContextNote: () => FNote | null;
|
||||
getThemeStyle: () => "auto" | "light" | "dark";
|
||||
ESLINT: Library;
|
||||
appContext: AppContext;
|
||||
froca: Froca;
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import { useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import "./NoteMap.css";
|
||||
import { getThemeStyle, MapType, NoteMapWidgetMode, rgb2hex } from "./utils";
|
||||
import { RefObject } from "preact";
|
||||
import FNote from "../../entities/fnote";
|
||||
import { useElementSize, useNoteLabel } from "../react/hooks";
|
||||
|
||||
import ForceGraph from "force-graph";
|
||||
import { RefObject } from "preact";
|
||||
import { useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
|
||||
import appContext from "../../components/app_context";
|
||||
import FNote from "../../entities/fnote";
|
||||
import link_context_menu from "../../menus/link_context_menu";
|
||||
import hoisted_note from "../../services/hoisted_note";
|
||||
import { t } from "../../services/i18n";
|
||||
import { getEffectiveThemeStyle } from "../../services/theme";
|
||||
import ActionButton from "../react/ActionButton";
|
||||
import { useElementSize, useNoteLabel } from "../react/hooks";
|
||||
import Slider from "../react/Slider";
|
||||
import { loadNotesAndRelations, NoteMapLinkObject, NoteMapNodeObject, NotesAndRelationsData } from "./data";
|
||||
import { CssData, setupRendering } from "./rendering";
|
||||
import ActionButton from "../react/ActionButton";
|
||||
import { t } from "../../services/i18n";
|
||||
import link_context_menu from "../../menus/link_context_menu";
|
||||
import appContext from "../../components/app_context";
|
||||
import Slider from "../react/Slider";
|
||||
import hoisted_note from "../../services/hoisted_note";
|
||||
import { MapType, NoteMapWidgetMode, rgb2hex } from "./utils";
|
||||
|
||||
interface NoteMapProps {
|
||||
note: FNote;
|
||||
@@ -40,9 +43,9 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) {
|
||||
return hoisted_note.getHoistedNoteId();
|
||||
} else if (mapRootIdLabel) {
|
||||
return mapRootIdLabel;
|
||||
} else {
|
||||
return appContext.tabManager.getActiveContext()?.parentNoteId ?? null;
|
||||
}
|
||||
return appContext.tabManager.getActiveContext()?.parentNoteId ?? null;
|
||||
|
||||
}, [ note ]);
|
||||
|
||||
// Build the note graph instance.
|
||||
@@ -67,7 +70,7 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) {
|
||||
noteIdToSizeMap: notesAndRelations.noteIdToSizeMap,
|
||||
cssData,
|
||||
notesAndRelations,
|
||||
themeStyle: getThemeStyle(),
|
||||
themeStyle: getEffectiveThemeStyle(),
|
||||
widgetMode,
|
||||
mapType
|
||||
});
|
||||
@@ -113,7 +116,7 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) {
|
||||
node.fx = undefined;
|
||||
node.fy = undefined;
|
||||
}
|
||||
})
|
||||
});
|
||||
}, [ fixNodes, mapType ]);
|
||||
|
||||
return (
|
||||
@@ -159,7 +162,7 @@ function MapTypeSwitcher({ icon, text, type, currentMapType, setMapType }: {
|
||||
onClick={() => setMapType(type)}
|
||||
frame
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getCssData(container: HTMLElement, styleResolver: HTMLElement): CssData {
|
||||
@@ -170,5 +173,5 @@ function getCssData(container: HTMLElement, styleResolver: HTMLElement): CssData
|
||||
fontFamily: containerStyle.fontFamily,
|
||||
textColor: rgb2hex(containerStyle.color),
|
||||
mutedTextColor: rgb2hex(styleResolverStyle.color)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +27,3 @@ export function generateColorFromString(str: string, themeStyle: "light" | "dark
|
||||
return color;
|
||||
}
|
||||
|
||||
export function getThemeStyle() {
|
||||
const documentStyle = window.getComputedStyle(document.documentElement);
|
||||
return documentStyle.getPropertyValue("--theme-style")?.trim() as "light" | "dark";
|
||||
}
|
||||
|
||||
@@ -1385,7 +1385,7 @@ export function useGetContextDataFrom<K extends keyof NoteContextDataMap>(
|
||||
}
|
||||
|
||||
export function useColorScheme() {
|
||||
const themeStyle = getThemeStyle();
|
||||
const themeStyle = window.glob.getThemeStyle();
|
||||
const defaultValue = themeStyle === "auto" ? (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) : themeStyle === "dark";
|
||||
const [ prefersDark, setPrefersDark ] = useState(defaultValue);
|
||||
|
||||
@@ -1400,12 +1400,3 @@ export function useColorScheme() {
|
||||
|
||||
return prefersDark ? "dark" : "light";
|
||||
}
|
||||
|
||||
function getThemeStyle() {
|
||||
const style = window.getComputedStyle(document.body);
|
||||
const themeStyle = style.getPropertyValue("--theme-style");
|
||||
if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) {
|
||||
return themeStyle as "light" | "dark";
|
||||
}
|
||||
return "auto";
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ function DesktopWebView({ src, ntxId }: { src: string, ntxId: string | null | un
|
||||
return <webview
|
||||
ref={webviewRef}
|
||||
src={src}
|
||||
key={src}
|
||||
class="note-detail-web-view-content"
|
||||
/>;
|
||||
}
|
||||
@@ -80,6 +81,7 @@ function BrowserWebView({ src, ntxId }: { src: string, ntxId: string | null | un
|
||||
return <iframe
|
||||
ref={iframeRef}
|
||||
src={src}
|
||||
key={src}
|
||||
class="note-detail-web-view-content"
|
||||
sandbox="allow-same-origin allow-scripts allow-popups" />;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,9 @@ const config: ForgeConfig = {
|
||||
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
|
||||
[FuseV1Options.EnableNodeCliInspectArguments]: false,
|
||||
[FuseV1Options.EnableCookieEncryption]: true,
|
||||
[FuseV1Options.OnlyLoadAppFromAsar]: true
|
||||
[FuseV1Options.OnlyLoadAppFromAsar]: true,
|
||||
[FuseV1Options.GrantFileProtocolExtraPrivileges]: false,
|
||||
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
"proxy-nginx-subdir": "docker run --name trilium-nginx-subdir --rm --network=host -v ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro nginx:latest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "3.0.64",
|
||||
"@ai-sdk/google": "3.0.55",
|
||||
"@ai-sdk/openai": "3.0.49",
|
||||
"@ai-sdk/anthropic": "3.0.66",
|
||||
"@ai-sdk/google": "3.0.58",
|
||||
"@ai-sdk/openai": "3.0.50",
|
||||
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||
"ai": "6.0.142",
|
||||
"ai": "6.0.146",
|
||||
"better-sqlite3": "12.8.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"i18next-fs-backend": "2.6.3",
|
||||
@@ -117,7 +117,7 @@
|
||||
"time2fa": "1.4.2",
|
||||
"tmp": "0.2.5",
|
||||
"turnish": "1.8.0",
|
||||
"vite": "8.0.3",
|
||||
"vite": "8.0.5",
|
||||
"xml2js": "0.6.2",
|
||||
"yauzl": "3.3.0"
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-light.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-next.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-next-light.css" media="(prefers-color-scheme: light)">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-next-dark.css" media="(prefers-color-scheme: dark)">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/style.css">
|
||||
<script src="<%= appPath %>/runtime.js" crossorigin type="module"></script>
|
||||
</head>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<title><%= t("set_password.title") %></title>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="<%= assetPath %>/images/app-icons/ios/apple-touch-icon.png">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-light.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-next.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-next-light.css" media="(prefers-color-scheme: light)">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-next-dark.css" media="(prefers-color-scheme: dark)">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/style.css">
|
||||
<script src="<%= appPath %>/runtime.js" crossorigin type="module"></script>
|
||||
<style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BootstrapDefinition } from "@triliumnext/commons";
|
||||
import { getSharedBootstrapItems, icon_packs as iconPackService, sql_init } from "@triliumnext/core";
|
||||
import { attributes, BNote, getSharedBootstrapItems, icon_packs as iconPackService, sql_init } from "@triliumnext/core";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
import packageJson from "../../package.json" with { type: "json" };
|
||||
@@ -43,7 +43,7 @@ export function bootstrap(req: Request, res: Response) {
|
||||
hasNativeTitleBar: false,
|
||||
hasBackgroundEffects: isElectron && (isWindows11 || isMac),
|
||||
isMainWindow: true,
|
||||
appCssNoteIds: [],
|
||||
appCssNoteIds: []
|
||||
} satisfies BootstrapDefinition);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,18 +10,18 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"i18next": "26.0.3",
|
||||
"preact": "10.29.0",
|
||||
"preact": "10.29.1",
|
||||
"preact-iso": "2.11.1",
|
||||
"preact-render-to-string": "6.6.7",
|
||||
"react-i18next": "17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "2.10.5",
|
||||
"eslint": "10.1.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint-config-preact": "2.0.0",
|
||||
"typescript": "6.0.2",
|
||||
"user-agent-data-types": "0.4.3",
|
||||
"vite": "8.0.3",
|
||||
"vite": "8.0.5",
|
||||
"vitest": "4.1.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* There are three themes embedded in the application:
|
||||
* `light`, located in `src\public\stylesheets\theme-light.css`
|
||||
* `dark`, located in `src\public\stylesheets\theme-dark.css`
|
||||
* `next`, located in `src\public\stylesheets\theme-next.css`.
|
||||
* `next`, composed from `src\public\stylesheets\theme-next-light.css` and `src\public\stylesheets\theme-next-dark.css`.
|
||||
* The default theme is set only once, when the database is created and is managed by `options_init#initNotSyncedOptions`.
|
||||
* In the original implementation: On Electron, the choice between `light` and `dark` is done based on the OS preference. Otherwise, the theme is always `dark`.
|
||||
* Now, we always choose `next` as the default theme.
|
||||
|
||||
@@ -12,10 +12,10 @@ Trilium Web Clipper officially supports the following web browsers:
|
||||
|
||||
## Obtaining the extension
|
||||
|
||||
> [!WARNING]
|
||||
> The extension is currently under development. A preview with unsigned extensions is available on [GitHub Actions](https://github.com/TriliumNext/Trilium/actions/runs/21318809414).
|
||||
>
|
||||
> We have already submitted the extension to both Chrome and Firefox web stores, but they are pending validation.
|
||||
The extension is available from the official browser web stores:
|
||||
|
||||
* **Firefox**: [Trilium Web Clipper on Firefox Add-ons](https://addons.mozilla.org/firefox/addon/trilium-notes-web-clipper/)
|
||||
* **Chrome**: [Trilium Web Clipper on Chrome Web Store](https://chromewebstore.google.com/detail/trilium-web-clipper/ofoiklieachadcaeffficgjaajojpkpi)
|
||||
|
||||
## Functionality
|
||||
|
||||
@@ -87,4 +87,4 @@ Development versions are version pre-release versions, generally meant for testi
|
||||
|
||||
## Credits
|
||||
|
||||
Some parts of the code are based on the [Joplin Notes browser extension](https://github.com/laurent22/joplin/tree/master/Clipper).
|
||||
Some parts of the code are based on the [Joplin Notes browser extension](https://github.com/laurent22/joplin/tree/master/Clipper).
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
"@triliumnext/server": "workspace:*",
|
||||
"@types/express": "5.0.6",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/node": "24.12.0",
|
||||
"@types/node": "24.12.2",
|
||||
"@vitest/browser-webdriverio": "4.1.2",
|
||||
"@vitest/coverage-v8": "4.1.2",
|
||||
"@vitest/ui": "4.1.2",
|
||||
@@ -62,7 +62,7 @@
|
||||
"cross-env": "10.1.0",
|
||||
"dpdm": "4.0.1",
|
||||
"esbuild": "0.28.0",
|
||||
"eslint": "10.1.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint-config-preact": "2.0.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-playwright": "2.10.1",
|
||||
@@ -79,7 +79,7 @@
|
||||
"typescript": "6.0.2",
|
||||
"typescript-eslint": "8.58.0",
|
||||
"upath": "2.0.1",
|
||||
"vite": "8.0.3",
|
||||
"vite": "8.0.5",
|
||||
"vite-plugin-dts": "4.5.4",
|
||||
"vitest": "4.1.2"
|
||||
},
|
||||
@@ -108,7 +108,7 @@
|
||||
"@lezer/highlight": "1.2.3",
|
||||
"@lezer/common": "1.5.1",
|
||||
"mermaid": "11.14.0",
|
||||
"preact": "10.29.0",
|
||||
"preact": "10.29.1",
|
||||
"roughjs": "4.6.6",
|
||||
"@types/express-serve-static-core": "5.1.1",
|
||||
"node-abi": "4.28.0",
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"@vitest/browser": "4.1.2",
|
||||
"@vitest/coverage-istanbul": "4.1.2",
|
||||
"ckeditor5": "48.0.0",
|
||||
"eslint": "10.1.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"stylelint": "17.6.0",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"@vitest/browser": "4.1.2",
|
||||
"@vitest/coverage-istanbul": "4.1.2",
|
||||
"ckeditor5": "48.0.0",
|
||||
"eslint": "10.1.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"stylelint": "17.6.0",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"@vitest/browser": "4.1.2",
|
||||
"@vitest/coverage-istanbul": "4.1.2",
|
||||
"ckeditor5": "48.0.0",
|
||||
"eslint": "10.1.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"stylelint": "17.6.0",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"@vitest/browser": "4.1.2",
|
||||
"@vitest/coverage-istanbul": "4.1.2",
|
||||
"ckeditor5": "48.0.0",
|
||||
"eslint": "10.1.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"stylelint": "17.6.0",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"@vitest/browser": "4.1.2",
|
||||
"@vitest/coverage-istanbul": "4.1.2",
|
||||
"ckeditor5": "48.0.0",
|
||||
"eslint": "10.1.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"stylelint": "17.6.0",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
|
||||
@@ -19,30 +19,35 @@
|
||||
"@codemirror/search": "6.6.0",
|
||||
"@codemirror/state": "6.6.0",
|
||||
"@codemirror/view": "6.41.0",
|
||||
"@fsegurai/codemirror-theme-abcdef": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-abyss": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-android-studio": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-andromeda": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-basic-dark": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-basic-light": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-cobalt2": "6.0.3",
|
||||
"@fsegurai/codemirror-theme-forest": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-github-dark": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-github-light": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-gruvbox-dark": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-gruvbox-light": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-material-dark": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-material-light": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-monokai": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-nord": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-palenight": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-solarized-dark": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-solarized-light": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-tokyo-night-day": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-tokyo-night-storm": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-volcano": "6.2.3",
|
||||
"@fsegurai/codemirror-theme-vscode-dark": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-vscode-light": "6.2.4",
|
||||
"@eslint/js": "10.0.1",
|
||||
"@fsegurai/codemirror-theme-abcdef": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-abyss": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-android-studio": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-andromeda": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-basic-dark": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-basic-light": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-cobalt2": "6.0.4",
|
||||
"@fsegurai/codemirror-theme-forest": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-github-dark": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-github-light": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-gruvbox-dark": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-gruvbox-light": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-high-contrast-dark": "6.0.2",
|
||||
"@fsegurai/codemirror-theme-high-contrast-light": "6.0.2",
|
||||
"@fsegurai/codemirror-theme-material-dark": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-material-light": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-material-ocean": "6.0.1",
|
||||
"@fsegurai/codemirror-theme-monokai": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-nord": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-palenight": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-solarized-dark": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-solarized-light": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-synthwave-84": "6.0.2",
|
||||
"@fsegurai/codemirror-theme-tokyo-night-day": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-tokyo-night-storm": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-volcano": "6.2.4",
|
||||
"@fsegurai/codemirror-theme-vscode-dark": "6.2.5",
|
||||
"@fsegurai/codemirror-theme-vscode-light": "6.2.5",
|
||||
"@replit/codemirror-indentation-markers": "6.5.3",
|
||||
"@replit/codemirror-lang-nix": "6.0.1",
|
||||
"@replit/codemirror-vim": "6.3.0",
|
||||
@@ -52,7 +57,6 @@
|
||||
"codemirror-lang-elixir": "4.0.1",
|
||||
"codemirror-lang-hcl": "0.1.0",
|
||||
"codemirror-lang-mermaid": "0.5.0",
|
||||
"@eslint/js": "10.0.1",
|
||||
"eslint-linter-browserify": "10.1.0",
|
||||
"globals": "17.4.0"
|
||||
}
|
||||
|
||||
@@ -77,6 +77,16 @@ const themes: ThemeDefinition[] = [
|
||||
name: "GitHub Light",
|
||||
load: async () => (await import("@fsegurai/codemirror-theme-github-light")).githubLight
|
||||
},
|
||||
{
|
||||
id: "high-contrast-dark",
|
||||
name: "High Contrast Dark",
|
||||
load: async () => (await import("@fsegurai/codemirror-theme-high-contrast-dark")).highContrastDark
|
||||
},
|
||||
{
|
||||
id: "high-contrast-light",
|
||||
name: "High Contrast Light",
|
||||
load: async () => (await import("@fsegurai/codemirror-theme-high-contrast-light")).highContrastLight
|
||||
},
|
||||
{
|
||||
id: "gruvbox-dark",
|
||||
name: "Gruvbox Dark",
|
||||
@@ -97,6 +107,11 @@ const themes: ThemeDefinition[] = [
|
||||
name: "Material Light",
|
||||
load: async () => (await import("@fsegurai/codemirror-theme-material-light")).materialLight
|
||||
},
|
||||
{
|
||||
id: "material-ocean",
|
||||
name: "Material Ocean",
|
||||
load: async () => (await import("@fsegurai/codemirror-theme-material-ocean")).materialOcean
|
||||
},
|
||||
{
|
||||
id: "monokai",
|
||||
name: "Monokai",
|
||||
@@ -122,6 +137,11 @@ const themes: ThemeDefinition[] = [
|
||||
name: "Solarized Light",
|
||||
load: async () => (await import("@fsegurai/codemirror-theme-solarized-light")).solarizedLight
|
||||
},
|
||||
{
|
||||
id: "synthwave-84",
|
||||
name: "Synthwave '84",
|
||||
load: async () => (await import("@fsegurai/codemirror-theme-synthwave-84")).synthwave84
|
||||
},
|
||||
{
|
||||
id: "tokyo-night-day",
|
||||
name: "Tokyo Night Day",
|
||||
|
||||
@@ -342,8 +342,9 @@ export type BootstrapDefinition = {
|
||||
dbInitialized: boolean;
|
||||
baseApiUrl: string;
|
||||
assetPath: string;
|
||||
themeCssUrl: string | false;
|
||||
themeUseNextAsBase?: "next" | "next-light" | "next-dark";
|
||||
theme: string;
|
||||
themeBase?: "next" | "next-light" | "next-dark";
|
||||
customThemeCssUrl?: string;
|
||||
iconPackCss: string;
|
||||
iconRegistry: IconRegistry;
|
||||
device: "mobile" | "desktop" | "print" | false;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@typescript-eslint/parser": "8.58.0",
|
||||
"dotenv": "17.4.0",
|
||||
"esbuild": "0.28.0",
|
||||
"eslint": "10.1.0",
|
||||
"eslint": "10.2.0",
|
||||
"highlight.js": "11.11.1",
|
||||
"typescript": "6.0.2"
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ const MIGRATIONS: (SqlMigration | JsMigration)[] = [
|
||||
version: 236,
|
||||
sql: /*sql*/`\
|
||||
ALTER TABLE blobs ADD COLUMN textRepresentation TEXT DEFAULT NULL;
|
||||
`
|
||||
`,
|
||||
ignoreErrors: true
|
||||
},
|
||||
// Add missing database indices for query performance
|
||||
{
|
||||
@@ -335,6 +336,8 @@ export default MIGRATIONS;
|
||||
|
||||
interface Migration {
|
||||
version: number;
|
||||
/** If true, errors during this migration are logged but do not halt the migration process. Useful for migrations that may have already been applied (e.g. adding a column that already exists). */
|
||||
ignoreErrors?: boolean;
|
||||
}
|
||||
|
||||
interface SqlMigration extends Migration {
|
||||
|
||||
@@ -28,9 +28,10 @@ export default function getSharedBootstrapItems(assetPath: string, dbInitialized
|
||||
if (!dbInitialized) {
|
||||
return {
|
||||
...commonItems,
|
||||
theme: "next",
|
||||
themeCssUrl: false as const,
|
||||
themeUseNextAsBase: "next" as const,
|
||||
appCssNoteIds: []
|
||||
appCssNoteIds: [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,6 +39,8 @@ export default function getSharedBootstrapItems(assetPath: string, dbInitialized
|
||||
const options = optionService.getOptionMap();
|
||||
const theme = options.theme;
|
||||
const themeNote = attributes.getNoteWithLabel("appTheme", theme);
|
||||
const themeUseNextAsBase = themeNote?.getAttributeValue("label", "appThemeBase") ?? undefined;
|
||||
|
||||
return {
|
||||
...commonItems,
|
||||
headingStyle: options.headingStyle as "plain" | "underline" | "markdown",
|
||||
@@ -45,6 +48,9 @@ export default function getSharedBootstrapItems(assetPath: string, dbInitialized
|
||||
maxEntityChangeIdAtLoad: sql.getValue<number>("SELECT COALESCE(MAX(id), 0) FROM entity_changes"),
|
||||
maxEntityChangeSyncIdAtLoad: sql.getValue<number>("SELECT COALESCE(MAX(id), 0) FROM entity_changes WHERE isSynced = 1"),
|
||||
isProtectedSessionAvailable: protected_session.isProtectedSessionAvailable(),
|
||||
theme,
|
||||
themeBase: themeUseNextAsBase as "next" | "next-light" | "next-dark" | undefined,
|
||||
customThemeCssUrl: getCustomThemeCssUrl(theme, themeNote),
|
||||
themeCssUrl: getThemeCssUrl(theme, commonItems.assetPath, themeNote) as string | false,
|
||||
themeUseNextAsBase: themeNote?.getAttributeValue("label", "appThemeBase") as "next" | "next-light" | "next-dark",
|
||||
appCssNoteIds: getAppCssNoteIds(),
|
||||
@@ -89,3 +95,15 @@ function getThemeCssUrl(theme: string, assetPath: string, themeNote: BNote | nul
|
||||
// baseline light theme
|
||||
return false;
|
||||
}
|
||||
|
||||
function getCustomThemeCssUrl(theme: string, themeNote: BNote | null) {
|
||||
if (["auto", "light", "dark", "next", "next-light", "next-dark"].includes(theme)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!process.env.TRILIUM_SAFE_MODE && themeNote) {
|
||||
return `api/notes/download/${themeNote.noteId}`;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ interface MigrationInfo {
|
||||
* If a function, then the migration is a JavaScript/TypeScript module that will be executed.
|
||||
*/
|
||||
migration: string | (() => void);
|
||||
ignoreErrors?: boolean;
|
||||
}
|
||||
|
||||
async function migrate() {
|
||||
@@ -57,8 +58,13 @@ async function migrate() {
|
||||
|
||||
log.info(`Migration to version ${mig.dbVersion} has been successful.`);
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
getPlatform().crash(t("migration.error_message", { version: mig.dbVersion, stack: e.stack }));
|
||||
if (mig.ignoreErrors) {
|
||||
log.info(`Migration to version ${mig.dbVersion} failed, but ignoreErrors is set. Continuing. Error: ${e.message}`);
|
||||
} else {
|
||||
console.error(e);
|
||||
getPlatform().crash(t("migration.error_message", { version: mig.dbVersion, stack: e.stack }));
|
||||
break; // crash() is sometimes async
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -79,14 +85,16 @@ async function prepareMigrations(currentDbVersion: number): Promise<MigrationInf
|
||||
if ("sql" in migration) {
|
||||
migrations.push({
|
||||
dbVersion,
|
||||
migration: migration.sql
|
||||
migration: migration.sql,
|
||||
ignoreErrors: migration.ignoreErrors
|
||||
});
|
||||
} else {
|
||||
// Due to ESM imports, the migration file needs to be imported asynchronously and thus cannot be loaded at migration time (since migration is not asynchronous).
|
||||
// As such we have to preload the ESM.
|
||||
migrations.push({
|
||||
dbVersion,
|
||||
migration: (await migration.module()).default
|
||||
migration: (await migration.module()).default,
|
||||
ignoreErrors: migration.ignoreErrors
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"happy-dom": "20.8.9",
|
||||
"turndown": "7.2.2",
|
||||
"turndown": "7.2.4",
|
||||
"vitest": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
2923
pnpm-lock.yaml
generated
2923
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user