@@ -30,7 +30,7 @@
{
const defaultTitle = t(actionsRef.defaultValue[index]?.defaultTitleKey)
return {
diff --git a/entrypoints/sidepanel/utils/chat/texts.ts b/entrypoints/sidepanel/utils/chat/texts.ts
index d403b01e..284a2a39 100644
--- a/entrypoints/sidepanel/utils/chat/texts.ts
+++ b/entrypoints/sidepanel/utils/chat/texts.ts
@@ -8,6 +8,6 @@ export const welcomeMessage = (t: ComposerTranslation) => {
return `
${makeParagraph(t('onboarding.welcome_msg.title'), { class: 'text-base font-normal' })}
-${makeContainer(t('onboarding.welcome_msg.body'), { class: 'text-xs text-[#596066]' })}
+${makeContainer(t('onboarding.welcome_msg.body'), { class: 'text-xs text-text-secondary' })}
`.trim()
}
diff --git a/entrypoints/sidepanel/utils/chat/tool-calls/index.ts b/entrypoints/sidepanel/utils/chat/tool-calls/index.ts
index f078768d..1d4ffc3c 100644
--- a/entrypoints/sidepanel/utils/chat/tool-calls/index.ts
+++ b/entrypoints/sidepanel/utils/chat/tool-calls/index.ts
@@ -62,8 +62,14 @@ export const executeSearchOnline: AgentToolCallExecute<'search_online'> = async
taskMsg.details = {
content: filteredLinks.map((link) => {
const faviconUrl = link.favicon?.startsWith('data:') ? link.favicon : undefined
- const faviconPart = faviconUrl ? makeRawHtmlTag('img', '', { src: faviconUrl, style: 'width: 16px; height: 16px;' }) : makeIcon('web', { color: '#596066' })
- const linkPart = makeRawHtmlTag('a', link.title || link.url, { href: link.url, target: '_blank', style: 'color: #596066; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;' })
+ const faviconPart = faviconUrl
+ ? makeRawHtmlTag('img', '', { src: faviconUrl, style: 'width: 16px; height: 16px;' })
+ : makeIcon('web', { color: 'var(--color-text-secondary, #596066)' })
+ const linkPart = makeRawHtmlTag('a', link.title || link.url, {
+ href: link.url,
+ target: '_blank',
+ style: 'color: var(--color-text-secondary, #596066); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;',
+ })
return makeRawHtmlTag('div', `${faviconPart} ${linkPart}`, { style: 'display: flex; align-items: center; gap: 8px;' })
}).join('\n'),
expanded: true,
diff --git a/entrypoints/sidepanel/utils/markdown/content.ts b/entrypoints/sidepanel/utils/markdown/content.ts
index 7bddba67..cb0f199c 100644
--- a/entrypoints/sidepanel/utils/markdown/content.ts
+++ b/entrypoints/sidepanel/utils/markdown/content.ts
@@ -2,13 +2,16 @@ import IconDownload from '@/assets/icons/md-download.svg?raw'
import IconEdit from '@/assets/icons/md-edit.svg?raw'
import IconFileSuccess from '@/assets/icons/md-file-success.svg?raw'
import IconFind from '@/assets/icons/md-find.svg?raw'
+import IconHighlightAction from '@/assets/icons/md-highlight-action.svg?raw'
import IconHighlightBoxed from '@/assets/icons/md-highlight-boxed.svg?raw'
import IconLink from '@/assets/icons/md-link.svg?raw'
import IconQuickModified from '@/assets/icons/md-quick-action-modified.svg?raw'
import IconSearch from '@/assets/icons/md-search.svg?raw'
+import IconSearchAction from '@/assets/icons/md-search-action.svg?raw'
import IconSearchBoxed from '@/assets/icons/md-search-boxed.svg?raw'
import IconSearchColored from '@/assets/icons/md-search-colored.svg?raw'
import IconStar from '@/assets/icons/md-star.svg?raw'
+import IconSummarizeAction from '@/assets/icons/md-summarize-action.svg?raw'
import IconSummarizeBoxed from '@/assets/icons/md-summarize-boxed.svg?raw'
import IconTick from '@/assets/icons/md-tick.svg?raw'
import IconTickColored from '@/assets/icons/md-tick-colored.svg?raw'
@@ -33,6 +36,9 @@ const iconMap = {
translationBoxed: IconTranslationBoxed,
writingBoxed: IconWritingBoxed,
highlightBoxed: IconHighlightBoxed,
+ summarizeAction: IconSummarizeAction,
+ highlightAction: IconHighlightAction,
+ searchAction: IconSearchAction,
edit: IconEdit,
quickActionModifiedBoxed: IconQuickModified,
searchBoxed: IconSearchBoxed,
diff --git a/entrypoints/sidepanel/utils/translator/utils/dom-utils.ts b/entrypoints/sidepanel/utils/translator/utils/dom-utils.ts
index fef1f7bb..8a3aa9cf 100644
--- a/entrypoints/sidepanel/utils/translator/utils/dom-utils.ts
+++ b/entrypoints/sidepanel/utils/translator/utils/dom-utils.ts
@@ -354,18 +354,24 @@ export function updateTranslationTextStyle(element: HTMLElement, style: Translat
break
}
case TranslationDisplayStyle.tintedHighlight: {
- element.style.color = isBGDark ? '#A8B4FF' : '#2724D8'
+ element.style.color = isBGDark
+ ? 'var(--color-translation-highlight-contrast, #A8B4FF)'
+ : 'var(--color-translation-highlight, #2724D8)'
break
}
case TranslationDisplayStyle.overlay: {
- element.style.backgroundColor = isBGDark ? 'rgba(255, 255, 255, 0.16)' : 'rgba(0,0,0,0.08)'
+ element.style.backgroundColor = isBGDark
+ ? 'var(--color-overlay-subtle-on-dark, rgba(255, 255, 255, 0.16))'
+ : 'var(--color-overlay-subtle-on-light, rgba(0, 0, 0, 0.08))'
element.style.borderRadius = '8px'
element.style.padding = '8px 12px'
break
}
case TranslationDisplayStyle.tintedOverlay: {
const innerElement = document.createElement('span')
- innerElement.style.backgroundColor = isBGDark ? 'rgba(200, 200, 200, 0.3)' : 'rgba(74, 101, 243, 0.1)'
+ innerElement.style.backgroundColor = isBGDark
+ ? 'var(--color-translation-overlay-dark, rgba(200, 200, 200, 0.3))'
+ : 'var(--color-translation-overlay-light, rgba(74, 101, 243, 0.1))'
innerElement.innerHTML = element.innerHTML
innerElement.classList.add(translationTargetInnerClass)
element.innerHTML = ''
@@ -373,11 +379,15 @@ export function updateTranslationTextStyle(element: HTMLElement, style: Translat
break
}
case TranslationDisplayStyle.wavyLine: {
- applyUnderlineStyle(element, 'wavy', isBGDark ? '#A8B4FF' : '#322EE5')
+ applyUnderlineStyle(element, 'wavy', isBGDark
+ ? 'var(--color-translation-highlight-contrast, #A8B4FF)'
+ : 'var(--color-translation-highlight, #322EE5)')
break
}
case TranslationDisplayStyle.dashedLine: {
- applyUnderlineStyle(element, 'dashed', isBGDark ? 'rgba(255, 255, 255, 0.56)' : 'rgba(0,0,0,0.32)')
+ applyUnderlineStyle(element, 'dashed', isBGDark
+ ? 'var(--color-translation-underline-dark, rgba(255, 255, 255, 0.56))'
+ : 'var(--color-translation-underline-light, rgba(0,0,0,0.32))')
break
}
case TranslationDisplayStyle.divider: {
@@ -386,7 +396,9 @@ export function updateTranslationTextStyle(element: HTMLElement, style: Translat
divider.classList.add(translationTargetDividerClass)
divider.style.width = '48px'
divider.style.marginTop = '8px'
- divider.style.borderBottom = isBGDark ? '1px dashed rgba(255, 255, 255, 0.56)' : '1px dashed rgba(0, 0, 0, 0.32)'
+ divider.style.borderBottom = isBGDark
+ ? '1px dashed var(--color-translation-underline-dark, rgba(255, 255, 255, 0.56))'
+ : '1px dashed var(--color-translation-underline-light, rgba(0, 0, 0, 0.32))'
element.before(divider)
break
diff --git a/locales/de.json b/locales/de.json
index c53a5321..4bed1a13 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -322,7 +322,10 @@
"interface": {
"title": "Schnittstelle",
"interface_language": "Schnittstellensprache",
- "interface_language_desc": "Wählen Sie die Anzeigesprache für die NativeMind-Benutzeroberfläche"
+ "theme": "Design",
+ "theme_light": "Hell",
+ "theme_dark": "Dunkel",
+ "theme_system": "System"
},
"header": {
"starts_on_github": "Sterne auf GitHub",
diff --git a/locales/en.json b/locales/en.json
index 1e51300b..bb7f63b7 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -189,7 +189,10 @@
"interface": {
"title": "Interface",
"interface_language": "Interface Language",
- "interface_language_desc": "Choose the display language for NativeMind interface"
+ "theme": "Theme",
+ "theme_light": "Light",
+ "theme_dark": "Dark",
+ "theme_system": "System"
},
"header": {
"starts_on_github": "Stars on GitHub",
diff --git a/locales/es.json b/locales/es.json
index 7419190f..407df534 100644
--- a/locales/es.json
+++ b/locales/es.json
@@ -347,7 +347,10 @@
"interface": {
"title": "Interfaz",
"interface_language": "Idioma de la Interfaz",
- "interface_language_desc": "Elige el idioma de visualización para la interfaz de NativeMind"
+ "theme": "Tema",
+ "theme_light": "Claro",
+ "theme_dark": "Oscuro",
+ "theme_system": "Sistema"
},
"header": {
"starts_on_github": "Estrellas en GitHub",
diff --git a/locales/fr.json b/locales/fr.json
index e7163807..c4af18c9 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -322,7 +322,10 @@
"interface": {
"title": "Interface",
"interface_language": "Langue d'interface",
- "interface_language_desc": "Choisissez la langue d'affichage pour l'interface NativeMind"
+ "theme": "Thème",
+ "theme_light": "Clair",
+ "theme_dark": "Sombre",
+ "theme_system": "Système"
},
"header": {
"starts_on_github": "Étoiles sur GitHub",
diff --git a/locales/id.json b/locales/id.json
index 4b93d891..62f80ebd 100644
--- a/locales/id.json
+++ b/locales/id.json
@@ -322,7 +322,10 @@
"interface": {
"title": "Antarmuka",
"interface_language": "Bahasa Antarmuka",
- "interface_language_desc": "Pilih bahasa tampilan untuk antarmuka NativeMind"
+ "theme": "Tema",
+ "theme_light": "Terang",
+ "theme_dark": "Gelap",
+ "theme_system": "Sistem"
},
"header": {
"starts_on_github": "Bintang di GitHub",
diff --git a/locales/ja.json b/locales/ja.json
index afb94cc2..62204399 100644
--- a/locales/ja.json
+++ b/locales/ja.json
@@ -322,7 +322,10 @@
"interface": {
"title": "インターフェース",
"interface_language": "インターフェース言語",
- "interface_language_desc": "NativeMindインターフェースの表示言語を選択してください"
+ "theme": "テーマ",
+ "theme_light": "ライト",
+ "theme_dark": "ダーク",
+ "theme_system": "システム"
},
"header": {
"starts_on_github": "GitHubでスター",
diff --git a/locales/ko.json b/locales/ko.json
index 3e24ac01..f540d346 100644
--- a/locales/ko.json
+++ b/locales/ko.json
@@ -322,7 +322,10 @@
"interface": {
"title": "인터페이스",
"interface_language": "인터페이스 언어",
- "interface_language_desc": "NativeMind 인터페이스의 표시 언어를 선택하세요"
+ "theme": "테마",
+ "theme_light": "라이트",
+ "theme_dark": "다크",
+ "theme_system": "시스템"
},
"header": {
"starts_on_github": "GitHub에서 별점 주기",
diff --git a/locales/pt.json b/locales/pt.json
index cd988996..80f399ca 100644
--- a/locales/pt.json
+++ b/locales/pt.json
@@ -322,7 +322,10 @@
"interface": {
"title": "Interface",
"interface_language": "Idioma da Interface",
- "interface_language_desc": "Escolha o idioma de exibição para a interface do NativeMind"
+ "theme": "Tema",
+ "theme_light": "Claro",
+ "theme_dark": "Escuro",
+ "theme_system": "Sistema"
},
"header": {
"starts_on_github": "Estrelas no GitHub",
diff --git a/locales/ru.json b/locales/ru.json
index 67230d33..f227ef08 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -322,7 +322,10 @@
"interface": {
"title": "Интерфейс",
"interface_language": "Язык интерфейса",
- "interface_language_desc": "Выберите язык отображения для интерфейса NativeMind"
+ "theme": "Тема",
+ "theme_light": "Светлая",
+ "theme_dark": "Темная",
+ "theme_system": "Системная"
},
"header": {
"starts_on_github": "Звезды на GitHub",
diff --git a/locales/th.json b/locales/th.json
index e9973bdc..b14dc42d 100644
--- a/locales/th.json
+++ b/locales/th.json
@@ -322,7 +322,10 @@
"interface": {
"title": "อินเทอร์เฟซ",
"interface_language": "ภาษาของอินเทอร์เฟซ",
- "interface_language_desc": "เลือกภาษาที่แสดงสำหรับส่วนติดต่อผู้ใช้ NativeMind"
+ "theme": "ธีม",
+ "theme_light": "สว่าง",
+ "theme_dark": "มืด",
+ "theme_system": "ระบบ"
},
"header": {
"starts_on_github": "ให้ดาวบน GitHub",
diff --git a/locales/vi.json b/locales/vi.json
index e058eeea..8961408d 100644
--- a/locales/vi.json
+++ b/locales/vi.json
@@ -322,7 +322,10 @@
"interface": {
"title": "Giao diện",
"interface_language": "Ngôn ngữ giao diện",
- "interface_language_desc": "Chọn ngôn ngữ hiển thị cho giao diện NativeMind"
+ "theme": "Giao diện",
+ "theme_light": "Sáng",
+ "theme_dark": "Tối",
+ "theme_system": "Hệ thống"
},
"header": {
"starts_on_github": "Sao trên GitHub",
diff --git a/locales/zh-CN.json b/locales/zh-CN.json
index c0debea8..b7c68d34 100644
--- a/locales/zh-CN.json
+++ b/locales/zh-CN.json
@@ -179,7 +179,10 @@
"interface": {
"title": "界面",
"interface_language": "界面语言",
- "interface_language_desc": "选择 NativeMind 界面的显示语言"
+ "theme": "主题",
+ "theme_light": "浅色",
+ "theme_dark": "深色",
+ "theme_system": "系统"
},
"header": {
"starts_on_github": "Stars on GitHub",
diff --git a/locales/zh-TW.json b/locales/zh-TW.json
index 1cd62325..8ceb6575 100644
--- a/locales/zh-TW.json
+++ b/locales/zh-TW.json
@@ -322,7 +322,10 @@
"interface": {
"title": "介面",
"interface_language": "介面語言",
- "interface_language_desc": "選擇 NativeMind 介面的顯示語言"
+ "theme": "主題",
+ "theme_light": "淺色",
+ "theme_dark": "深色",
+ "theme_system": "系統"
},
"header": {
"starts_on_github": "Stars on GitHub",
diff --git a/package.json b/package.json
index 66746dfd..70961f55 100644
--- a/package.json
+++ b/package.json
@@ -26,8 +26,8 @@
],
"type": "module",
"scripts": {
- "build:beta": "NODE_ENV=beta wxt build -c wxt.config.beta.ts",
- "build:beta:firefox": "NODE_ENV=beta wxt build -c wxt.config.beta.ts -b firefox --mv3",
+ "build:beta": "cross-env NODE_ENV=beta wxt build -c wxt.config.beta.ts",
+ "build:beta:firefox": "cross-env NODE_ENV=beta wxt build -c wxt.config.beta.ts -b firefox --mv3",
"build:prod": "wxt build",
"build:prod:firefox": "wxt build -b firefox --mv3",
"build:analyze": "wxt build --analyze",
@@ -38,16 +38,16 @@
"compile": "vue-tsc --noEmit",
"test:e2e": "PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS=1 playwright test --config=playwright.config.ts",
"test:unit": "vitest run",
- "dev": "NODE_ENV=development wxt",
- "dev:edge": "NODE_ENV=development wxt -b edge",
- "dev:firefox": "NODE_ENV=development wxt -b firefox --mv3",
+ "dev": "cross-env NODE_ENV=development wxt",
+ "dev:edge": "cross-env NODE_ENV=development wxt -b edge",
+ "dev:firefox": "cross-env NODE_ENV=development wxt -b firefox --mv3",
"postinstall": "wxt prepare",
"release:beta": "release-it --preRelease=beta --config .release-it.beta.json",
"release:prod": "release-it",
"release:patch": "release-it patch",
- "zip:beta": "NODE_ENV=beta wxt zip -c wxt.config.beta.ts",
- "zip:beta:edge": "NODE_ENV=beta wxt zip -c wxt.config.beta.ts -b edge",
- "zip:beta:firefox": "NODE_ENV=beta wxt zip -c wxt.config.beta.ts -b firefox --mv3",
+ "zip:beta": "cross-env NODE_ENV=beta wxt zip -c wxt.config.beta.ts",
+ "zip:beta:edge": "cross-env NODE_ENV=beta wxt zip -c wxt.config.beta.ts -b edge",
+ "zip:beta:firefox": "cross-env NODE_ENV=beta wxt zip -c wxt.config.beta.ts -b firefox --mv3",
"zip:prod": "wxt zip",
"zip:prod:firefox": "wxt zip -b firefox --mv3",
"prepare": "husky"
@@ -146,6 +146,7 @@
"@vue/test-utils": "^2.4.6",
"@webgpu/types": "^0.1.60",
"@wxt-dev/module-vue": "^1.0.2",
+ "cross-env": "^10.0.0",
"defu": "^6.1.4",
"eslint": "^9.26.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0eb4fd92..cdcd534e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -282,6 +282,9 @@ importers:
'@wxt-dev/module-vue':
specifier: ^1.0.2
version: 1.0.2(vite@6.3.5(@types/node@24.0.4)(jiti@2.4.2)(lightningcss@1.30.1)(sass-embedded@1.87.0)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))(wxt@0.20.6(@types/node@24.0.4)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@4.40.1)(sass-embedded@1.87.0)(yaml@2.7.1))
+ cross-env:
+ specifier: ^10.0.0
+ version: 10.0.0
defu:
specifier: ^6.1.4
version: 6.1.4
@@ -560,6 +563,9 @@ packages:
'@emnapi/runtime@1.4.3':
resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==}
+ '@epic-web/invariant@1.0.0':
+ resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==}
+
'@esbuild/aix-ppc64@0.25.4':
resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
engines: {node: '>=18'}
@@ -2473,6 +2479,11 @@ packages:
create-require@1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
+ cross-env@10.0.0:
+ resolution: {integrity: sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q==}
+ engines: {node: '>=20'}
+ hasBin: true
+
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -6236,6 +6247,8 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@epic-web/invariant@1.0.0': {}
+
'@esbuild/aix-ppc64@0.25.4':
optional: true
@@ -8278,6 +8291,11 @@ snapshots:
create-require@1.1.1: {}
+ cross-env@10.0.0:
+ dependencies:
+ '@epic-web/invariant': 1.0.0
+ cross-spawn: 7.0.6
+
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
diff --git a/styles/style.css b/styles/style.css
index bdeffc77..70ec0393 100644
--- a/styles/style.css
+++ b/styles/style.css
@@ -71,26 +71,208 @@
--font-inter: "Inter", ui-sans-serif, system-ui, sans-serif;
- /* Colors only used in UI component should not be used in business component */
+ /* Light mode colors */
--color-text-primary: #1f2326;
--color-text-secondary: #596066;
- --color-text-tertiary: #747a80;
+ --color-text-tertiary: #71717a;
--color-text-placeholder: #aeb5bd;
--color-text-disabled: #aeb5bd;
--color-text-quaternary: #9ea3a8;
+ --color-text-critical: #BF2A2A;
+ --color-text-caution: #fda58f;
+
+ --color-text-link: #0d80f2;
+ --color-text-link-hover: #0b6bbf;
+
+ --color-text-accent-green: #03943d;
+ --color-text-accent-blue: #0082FB;
+
+ --color-icon-quick-action: #596066;
+
+ --color-bg-app: #f5f6fb;
+ --color-bg-primary: #ffffff;
+ --color-bg-secondary: #e9e9ec;
--color-bg-component: hsla(0, 0%, 98%, 1);
- --color-icon-link: #0f62fe;
- --color-danger: #bf2a2a;
+ --color-bg-tertiary: #fafafa;
+ --color-bg-tag: #f4f4f5;
+ --color-bg-selection: #dfe1e5;
+ --color-bg-hover: #eaecef;
+ --color-bg-divider: #747a80;
+
+ --color-bg-info-subtle: #e5f3ff;
+ --color-bg-overlay-contrast: #27272a;
+ --color-bg-neutral-subtle: #f2f2f2;
+
+ /* Specific colors */
+ --color-bg-clickable: #ffffff;
+ --color-bg-quick-action: #f5f6f7;
+ --color-bg-chat-input: #ffffff;
+
+ --color-bg-accent-green: #dcffea;
+
+ --color-foreground-base: #18181b;
+
+ --color-border: #e5e7eb;
+ --color-border-light: #0000001a;
+ --color-border-strong: #e4e4e7;
+ --color-border-selection: #24b96080;
+ --color-border-accent: #24b960;
+ --color-border-critical: #e11d48;
+ --color-border-critical-soft: #e11d4826;
+ --color-border-disabled: #a0a0a0;
+ --color-border-hairline: #0000000d;
+ --color-border-overlay: #18181b3d;
+ --color-border-quick-action: #0000001f;
+ --color-border-chat-input: #e4e4e7;
+ --color-divider: #0000001a;
+
+ --color-surface-disabled: #cfd4d9;
+
+ --color-overlay-scrim: #0000008b;
+ --color-overlay-muted: #00000017;
+ --color-overlay-subtle-on-light: rgba(0, 0, 0, 0.08);
+ --color-overlay-subtle-on-dark: rgba(255, 255, 255, 0.16);
+
+ --color-shadow-soft: #0000000a;
+ --color-shadow-medium: #00000014;
+ --color-shadow-strong: #0000001f;
+ --color-shadow-contrast: #00000066;
+ --color-shadow-inset-highlight: #ffffff33;
+ --color-shadow-ambient: rgba(0, 0, 0, 0.2);
+
+ --color-accent-primary: #24b960;
+ --color-accent-primary-hover: #089641;
+ --color-accent-primary-shadow: #0e6b33;
+ --color-accent-primary-disabled: #8a8a8a;
+
--color-success: #60c959;
+ --color-warning: #f7c103;
+ --color-danger: #bf2a2a;
--color-quaternary: #bdc2c7;
- --color-bg-hover: #eaecef;
+ --color-gradient-onboarding-start: #d5f4e1;
+ --color-gradient-onboarding-end: #ffffff;
- --color-foreground-base: #18181b;
+ --color-translation-highlight: #2724d8;
+ --color-translation-highlight-contrast: #a8b4ff;
+ --color-translation-underline-light: rgba(0, 0, 0, 0.32);
+ --color-translation-underline-dark: rgba(255, 255, 255, 0.56);
+ --color-translation-overlay-light: rgba(74, 101, 243, 0.1);
+ --color-translation-overlay-dark: rgba(200, 200, 200, 0.3);
+
+ --color-scroll-thumb: #e4e4e7;
+ --color-mask-disabled: #ffffffaf;
+ --color-arrival-shadow: #92929225;
+ --color-loading-track: #222;
+
+ --shadow-01: 0px 8px 16px 0px var(--color-shadow-medium),
+ 0px 4px 8px 0px var(--color-shadow-medium),
+ 0px 0px 0px 1px var(--color-shadow-medium);
+ --shadow-02: 0px 0px 0px 1px var(--color-shadow-medium),
+ 0px 1px 2px 0px var(--color-shadow-strong);
+}
+
+/* Dark mode colors */
+[data-nm-theme="dark"] {
+ --color-text-primary: #f8f9fa;
+ --color-text-secondary: #eaecef;
+ --color-text-tertiary: #8b949e;
+ --color-text-placeholder: #6e7681;
+ --color-text-disabled: #6e7681;
+ --color-text-quaternary: #7d8590;
+ --color-text-success: #24b960;
+ --color-text-critical: #BF2A2A;
+ --color-text-caution: #fda58f;
+
+ --color-text-link: #58a6ff;
+ --color-text-link-hover: #78a6ff;
+
+ --color-text-accent-green: #56d364;
+ --color-text-accent-blue: #1565c0;
+
+ --color-icon-quick-action: #878c92;
+
+ --color-bg-app: #121212;
+ --color-bg-primary: #101010;
+ --color-bg-secondary: #212124;
+ --color-bg-component: #212124;
+ --color-bg-tertiary: #212124;
+ --color-bg-tag: #3f3f46;
+ --color-bg-selection: #212124;
+ --color-bg-hover: #2a2a2a;
+ --color-bg-divider: #878c92;
+
+ --color-bg-info-subtle: #033867;
+ --color-bg-overlay-contrast: #1f2326;
+ --color-bg-neutral-subtle: #1f2326;
+
+ /* Specific colors */
+ --color-bg-clickable: #212124;
+ --color-bg-quick-action: #212124;
+ --color-bg-chat-input: #212124;
+
+ --color-bg-accent-green: #1b3c2a;
+
+ --color-foreground-base: #f0f6fc;
+
+ --color-border: #2a2a2a;
+ --color-border-light: #212124;
+ --color-border-strong: #2a2a2a;
+ --color-border-selection: #24b96080;
+ --color-border-accent: #24b960;
+ --color-border-critical: #f85149;
+ --color-border-critical-soft: #f8514926;
+ --color-border-disabled: #3c434d;
+ --color-border-hairline: #262a31;
+ --color-border-overlay: #f8f9fa33;
+ --color-border-quick-action: #ffffff1f;
+ --color-border-chat-input: #2A2A2A;
+ --color-divider: #212124;
+
+ --color-surface-disabled: #2f363d;
+
+ --color-overlay-scrim: #000000bf;
+ --color-overlay-muted: rgba(255, 255, 255, 0.08);
+ --color-overlay-subtle-on-light: rgba(0, 0, 0, 0.24);
+ --color-overlay-subtle-on-dark: rgba(255, 255, 255, 0.16);
+
+ --color-shadow-soft: #0000001f;
+ --color-shadow-medium: #ffffff14;
+ --color-shadow-strong: #0000001f;
+ --color-shadow-contrast: #0000008a;
+ --color-shadow-inset-highlight: #ffffff1a;
+ --color-shadow-ambient: rgba(0, 0, 0, 0.4);
+
+ --color-accent-primary: #20a655;
+ --color-accent-primary-hover: #089641;
+ --color-accent-primary-shadow: #0e6b33;
+ --color-accent-primary-disabled: #3c434d;
+
+ --color-success: #56d364;
+ --color-warning: #ffb900;
+ --color-danger: #bf2a2a;
+ --color-quaternary: #30363d;
+
+ --color-gradient-onboarding-start: #1b3125;
+ --color-gradient-onboarding-end: #161b22;
+
+ --color-translation-highlight: #a8b4ff;
+ --color-translation-highlight-contrast: #2724d8;
+ --color-translation-underline-light: rgba(255, 255, 255, 0.56);
+ --color-translation-underline-dark: rgba(0, 0, 0, 0.32);
+ --color-translation-overlay-light: rgba(200, 200, 200, 0.3);
+ --color-translation-overlay-dark: rgba(74, 101, 243, 0.1);
+
+ --color-scroll-thumb: #30363d;
+ --color-mask-disabled: rgba(13, 17, 23, 0.7);
+ --color-arrival-shadow: rgba(0, 0, 0, 0.32);
+ --color-loading-track: #30363d;
- --shadow-01: 0px 8px 16px 0px #00000014, 0px 4px 8px 0px #00000014,
- 0px 0px 0px 1px #00000014;
- --shadow-02: 0px 0px 0px 1px #00000014, 0px 1px 2px 0px #0000001f;
+ --shadow-01: 0px 8px 16px 0px var(--color-shadow-medium),
+ 0px 4px 8px 0px var(--color-shadow-medium),
+ 0px 0px 0px 1px var(--color-shadow-medium);
+ --shadow-02: 0px 0px 0px 1px var(--color-shadow-medium),
+ 0px 1px 2px 0px var(--color-shadow-strong);
}
.nativemind-style-boundary .scrollbar-hide {
diff --git a/types/theme/index.ts b/types/theme/index.ts
new file mode 100644
index 00000000..a7335240
--- /dev/null
+++ b/types/theme/index.ts
@@ -0,0 +1,2 @@
+export type ThemeModeType = 'light' | 'dark' | 'system'
+export type ThemeType = 'light' | 'dark'
diff --git a/utils/icon.ts b/utils/icon.ts
index 07e175fc..4b84e6c4 100644
--- a/utils/icon.ts
+++ b/utils/icon.ts
@@ -2,13 +2,16 @@ import IconDownload from '@/assets/icons/md-download.svg?raw'
import IconEdit from '@/assets/icons/md-edit.svg?raw'
import IconFileSuccess from '@/assets/icons/md-file-success.svg?raw'
import IconFind from '@/assets/icons/md-find.svg?raw'
+import IconHighlightAction from '@/assets/icons/md-highlight-action.svg?raw'
import IconHighlightBoxed from '@/assets/icons/md-highlight-boxed.svg?raw'
import IconLink from '@/assets/icons/md-link.svg?raw'
import IconQuickModified from '@/assets/icons/md-quick-action-modified.svg?raw'
import IconSearch from '@/assets/icons/md-search.svg?raw'
+import IconSearchAction from '@/assets/icons/md-search-action.svg?raw'
import IconSearchBoxed from '@/assets/icons/md-search-boxed.svg?raw'
import IconSearchColored from '@/assets/icons/md-search-colored.svg?raw'
import IconStar from '@/assets/icons/md-star.svg?raw'
+import IconSummarizeAction from '@/assets/icons/md-summarize-action.svg?raw'
import IconSummarizeBoxed from '@/assets/icons/md-summarize-boxed.svg?raw'
import IconTick from '@/assets/icons/md-tick.svg?raw'
import IconTickColored from '@/assets/icons/md-tick-colored.svg?raw'
@@ -39,6 +42,9 @@ export const iconMap = {
translationBoxed: IconTranslationBoxed,
writingBoxed: IconWritingBoxed,
highlightBoxed: IconHighlightBoxed,
+ summarizeAction: IconSummarizeAction,
+ highlightAction: IconHighlightAction,
+ searchAction: IconSearchAction,
edit: IconEdit,
quickActionModifiedBoxed: IconQuickModified,
searchBoxed: IconSearchBoxed,
diff --git a/utils/theme/index.ts b/utils/theme/index.ts
new file mode 100644
index 00000000..a9bb6f72
--- /dev/null
+++ b/utils/theme/index.ts
@@ -0,0 +1,8 @@
+import { ThemeType } from '@/types/theme'
+
+export const getDocumentTheme = (): ThemeType => {
+ if (typeof document !== 'undefined' && document.documentElement.classList.contains('dark')) {
+ return 'dark'
+ }
+ return 'light'
+}
diff --git a/utils/user-config/index.ts b/utils/user-config/index.ts
index 7d5dddfc..cc5fcb2f 100644
--- a/utils/user-config/index.ts
+++ b/utils/user-config/index.ts
@@ -1,6 +1,7 @@
import { computed } from 'vue'
import { browser } from 'wxt/browser'
+import { ThemeModeType } from '@/types/theme'
import { c2bRpc } from '@/utils/rpc'
import { SupportedLocaleCode } from '../i18n/constants'
@@ -166,6 +167,9 @@ export async function _getUserConfig() {
},
},
ui: {
+ theme: {
+ mode: await new Config('ui.theme.mode').default('system' as ThemeModeType).build(),
+ },
pinSidebar: await new Config('ui.pinSidebar').default(false).build(),
onboarding: {
version: await new Config('ui.onboarding.version').default(0).build(),