From 124fa2e6117e76a62afeeacf603b1028bf6cfd4b Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Sat, 21 Feb 2026 08:18:16 +0700 Subject: [PATCH 01/19] Update Settings - Security + Dangerzone by adding new buttons, stylization, and order --- package-lock.json | 4 +-- src-tauri/tauri.conf.json | 2 +- src/index.html | 59 ++++++++++++++++++++++----------------- src/js/misc.js | 2 +- src/js/settings.js | 3 +- src/main.js | 15 ++++++++++ src/styles.css | 2 +- 7 files changed, 55 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index dc4d6351..d67a88ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vector", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vector", - "version": "0.3.0", + "version": "0.3.1", "dependencies": { "@tauri-apps/plugin-clipboard-manager": "^2.3.2", "@tauri-apps/plugin-deep-link": "^2.4.6", diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index ee55b264..3f72dfdb 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -2,7 +2,7 @@ "$schema": "https://schema.tauri.app/config/2", "productName": "Vector", "mainBinaryName": "Vector", - "identifier": "io.vectorapp", + "identifier": "io.vectorapp.dev", "build": { "frontendDist": "../dist", "beforeDevCommand": "node scripts/build-frontend.mjs --dev", diff --git a/src/index.html b/src/index.html index 388c621b..607d575f 100644 --- a/src/index.html +++ b/src/index.html @@ -870,21 +870,6 @@

Privacy

- -
-
-

Security

- -
- -
- -
-

@@ -1002,7 +987,39 @@

What's New:

- + +
+
+

Security

+ +
+ +
+ +
+
+ + Change PIN +
+ +
+ +
+
+ + Export Account +
+ +
+
+ + @@ -1039,16 +1056,6 @@

Dangerzone

-
-
- - Export Account -
- -
-
diff --git a/src/js/misc.js b/src/js/misc.js index 1a7fae79..e8d7fea9 100644 --- a/src/js/misc.js +++ b/src/js/misc.js @@ -196,7 +196,7 @@ async function popupConfirm(strTitle, strSubtext, fNotice = false, strInputPlace domApp.classList.add('active'); // Adjust the 'Confirm' button if this is only a notice - domPopupConfirmBtn.innerText = fNotice ? 'Okay!' : 'Confirm'; + domPopupConfirmBtn.innerText = fNotice ? 'Okay' : 'Confirm'; domPopupCancelBtn.style.display = fNotice ? 'none' : ''; // If a string placeholder is specified, render it diff --git a/src/js/settings.js b/src/js/settings.js index 8b49047f..00368846 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -1584,7 +1584,8 @@ function updateChangeCredentialButton() { if (!btn) return; if (fEncryptionEnabled) { btn.style.display = ''; - btn.textContent = fSecurityType === 'password' ? 'Change Password' : 'Change PIN'; + btn.textContent = 'Change'; + domSettingsChangePinLabel.textContent = fSecurityType === 'password' ? 'Change Password' : 'Change PIN'; } else { btn.style.display = 'none'; } diff --git a/src/main.js b/src/main.js index 37055f5e..7ca36e74 100644 --- a/src/main.js +++ b/src/main.js @@ -162,6 +162,8 @@ const domSettingsChatBgInfo = document.getElementById('chat-bg-info'); const domSettingsNotifMuteInfo = document.getElementById('notif-mute-info'); const domSettingsDeepRescanInfo = document.getElementById('deep-rescan-info'); const domSettingsExportAccountInfo = document.getElementById('export-account-info'); +const domSettingsChangePinInfo = document.getElementById('change-pin-info'); +const domSettingsChangePinLabel = document.getElementById('change-pin-label'); const domSettingsLogoutInfo = document.getElementById('logout-info'); const domSettingsDonorsInfo = document.getElementById('donors-info'); const domDonorPivx = document.getElementById('donor-pivx'); @@ -11332,6 +11334,19 @@ domChatMessageInput.oninput = async () => { popupConfirm('Export Account', 'Export Account will display a backup of your encryption keys. Keep it safe to restore your account later.', true); }; + domSettingsChangePinInfo.onclick = (e) => { + e.preventDefault(); + e.stopPropagation(); + popupConfirm( + fSecurityType === 'password' ? 'Change Password' : 'Change PIN', + fSecurityType === 'password' + ? 'Your password encrypts all local data including messages, keys, and secrets stored on your device. Resetting it will re-encrypt everything with your new password.' + : 'Your PIN encrypts all local data including messages, keys, and secrets stored on your device. Resetting it will re-encrypt everything with your new PIN.', + true + ); + }; + + // Info button for Refresh KeyPackages const domRefreshKeypkgInfo = document.getElementById('refresh-keypkg-info'); if (domRefreshKeypkgInfo) { diff --git a/src/styles.css b/src/styles.css index 8c68d7c1..997c811b 100644 --- a/src/styles.css +++ b/src/styles.css @@ -4487,7 +4487,7 @@ select:disabled:hover { cursor: pointer; font-size: 15px; font-family: inherit; - font-weight: 500; + font-weight: 600; transition: all 0.2s; } From 50b674db1663ef2b12d6cb6b2be46b3f091e151d Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Sat, 21 Feb 2026 08:36:50 +0700 Subject: [PATCH 02/19] Add Gitcoin as a Donor & Contributor in Settings --- src/icons/gitcoin-white.svg | 1 + src/index.html | 5 ++++- src/main.js | 8 ++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/icons/gitcoin-white.svg diff --git a/src/icons/gitcoin-white.svg b/src/icons/gitcoin-white.svg new file mode 100644 index 00000000..f887dd53 --- /dev/null +++ b/src/icons/gitcoin-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/index.html b/src/index.html index 607d575f..13742281 100644 --- a/src/index.html +++ b/src/index.html @@ -1075,10 +1075,13 @@

Dangerzone

Donors & Contributors -
+
PIVX
+
+ Gitcoin +
diff --git a/src/main.js b/src/main.js index 7ca36e74..d789be4e 100644 --- a/src/main.js +++ b/src/main.js @@ -167,6 +167,7 @@ const domSettingsChangePinLabel = document.getElementById('change-pin-label'); const domSettingsLogoutInfo = document.getElementById('logout-info'); const domSettingsDonorsInfo = document.getElementById('donors-info'); const domDonorPivx = document.getElementById('donor-pivx'); +const domDonorGitcoin = document.getElementById('donor-gitcoin'); const domSettingsLogout = document.getElementById('logout-btn'); const domSettingsExport = document.getElementById('export-account-btn'); const domRestorePivxGroup = document.getElementById('restore-pivx-group'); @@ -11381,6 +11382,13 @@ domChatMessageInput.oninput = async () => { openUrl('https://pivx.org'); }; + // Gitcoin donor logo click - opens gitcoin.co + domDonorGitcoin.onclick = (e) => { + e.preventDefault(); + e.stopPropagation(); + openUrl('https://www.gitcoin.co'); + }; + // Restore PIVX Wallet button - restores hidden PIVX app if (domRestorePivxBtn) { domRestorePivxBtn.onclick = async () => { From 1409dfa31f46572c72a5fbf9f79fe3ca90b126f1 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Sat, 21 Feb 2026 09:04:52 +0700 Subject: [PATCH 03/19] Add Footer in Settings with Donate, GitBook, and Privacy Policy Links --- src/index.html | 13 ++++++++++++- src/main.js | 14 ++++++++++++++ src/styles.css | 11 +++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/index.html b/src/index.html index 13742281..a9d45d38 100644 --- a/src/index.html +++ b/src/index.html @@ -1071,7 +1071,7 @@

Dangerzone

-
+

Donors & Contributors

@@ -1084,6 +1084,17 @@

+
+ +

+
-
- -
-
+
- -
- -
diff --git a/src/styles.css b/src/styles.css index 09894b15..0d58745c 100644 --- a/src/styles.css +++ b/src/styles.css @@ -897,7 +897,7 @@ html, body { } .profile-option:hover { - background-color: #161616; + background-color: #171717; border-color: #959899; color: white; opacity: 1; @@ -3175,7 +3175,7 @@ audio { #settings { overflow-y: auto; height: 100%; - padding-bottom: 100px; + padding-bottom: 80px; overscroll-behavior: none; -webkit-overflow-scrolling: touch; touch-action: pan-y; @@ -3211,7 +3211,7 @@ select { } #whisper-model option { - background: #161616; + background: #171717; padding: 10px; } @@ -3863,6 +3863,12 @@ input[type="checkbox"]:checked + .neon-toggle:before { #theme-select { text-align: center; text-align-last: center; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23888'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 12px center; + background-size: 10px; + padding-right: 36px; } /* Remove default focus outline and apply custom styling */ @@ -3872,7 +3878,7 @@ input[type="checkbox"]:checked + .neon-toggle:before { /* Style options to match whisper model */ #theme-select option { - background: #161616; + background: #171717; text-align: center; padding: 10px; } @@ -3895,11 +3901,22 @@ select:focus::-ms-value { /* Sound Notification Selection container styles */ #notif-sound-select option { - background: #161616; + background: #171717; padding: 10px; text-align: center; } +/* Down Arrow added to Dropdown Button */ +#notif-sound-select { + text-align: center; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23888'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 12px center; + background-size: 10px; + padding-right: 36px; +} + /* Delete model button with trash bin icon */ .btn-delete-model { position: absolute; @@ -3983,7 +4000,7 @@ select:disabled:hover { margin-left: 10px; backdrop-filter: none; border-color: #ff2ea9; - background-color: #161616; + background-color: #171717; } .cancel-btn:disabled, @@ -4256,7 +4273,7 @@ select:disabled:hover { bottom: 0px; height: 65px; width: 100%; - background-color: #161616; + background-color: #171717; justify-content: space-evenly; } @@ -7982,7 +7999,7 @@ hr { align-items: center; gap: 14px; padding: 14px; - background-color: #161616; + background-color: #171717; border-radius: 12px; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; @@ -8384,7 +8401,7 @@ hr { } .publish-app-container { - background-color: #161616; + background-color: #171717; border-radius: 16px; width: 90%; max-width: 500px; From a549bc40b4e8af660b778b3b51d61855a4db3b9c Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 09:15:51 +0700 Subject: [PATCH 06/19] Fix Image Viewer Contrast for Light Backgrounds --- src/styles.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/styles.css b/src/styles.css index 0d58745c..22f95019 100644 --- a/src/styles.css +++ b/src/styles.css @@ -5906,7 +5906,7 @@ select:disabled:hover { right: 20px; width: 40px; height: 40px; - background-color: rgba(255, 255, 255, 0.1); + background-color: #17171770; border: none; border-radius: 50%; cursor: pointer; @@ -5918,7 +5918,7 @@ select:disabled:hover { } .image-viewer-close:hover { - background-color: rgba(255, 255, 255, 0.2); + background-color: #171717; } .image-viewer-close::before, From 29d77533421eec937db4f65bc47f2fbbf7184300 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 09:22:02 +0700 Subject: [PATCH 07/19] Fix Top Avatar Bar Contrast + Shadow --- src/styles.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/styles.css b/src/styles.css index 22f95019..feda50d8 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1246,7 +1246,7 @@ html, body { .chat-header { position: fixed; height: 60px; - background-color: rgba(22, 22, 22, 0.85); + background-color: rgba(22, 22, 22, 0.9); backdrop-filter: blur(10px); display: flex; align-items: center; @@ -3110,7 +3110,7 @@ audio { left: 0; right: 0; height: 40px; - background: linear-gradient(rgba(7, 7, 7, 0.85), #00000000 80%); + background: linear-gradient(#030303d9, #03030300 80%); pointer-events: none; } From 9d70b55e9ecd2b06050e1c9c49bd438757b9ea51 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 09:29:03 +0700 Subject: [PATCH 08/19] Update Vector's main color to be mid-green tone, not accent --- src/themes/vector/dark.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/themes/vector/dark.css b/src/themes/vector/dark.css index d26d8ccb..d4ba2850 100644 --- a/src/themes/vector/dark.css +++ b/src/themes/vector/dark.css @@ -3,7 +3,7 @@ --voice-highlight-bg: rgba(89, 252, 179, 0.3); --voice-highlight-text: #59fcb3; --voice-frequency-glow: rgba(89, 252, 179, 0.8); - --icon-color-primary: #59fcb3; + --icon-color-primary: #33DB98; --reply-highlight-border: #33DB98; --toast-border-color: #33DB98; } From b545937a31b5a0a91a8ca3112a797f4c81789943 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 09:55:31 +0700 Subject: [PATCH 09/19] Add Scroll Effect to nPub Display --- src/index.html | 4 +++- src/main.js | 4 ++-- src/styles.css | 18 ++++++++++++++---- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/index.html b/src/index.html index c97b971f..3ba5c0e9 100644 --- a/src/index.html +++ b/src/index.html @@ -583,7 +583,9 @@

nPub Key

- +
+ +
diff --git a/src/main.js b/src/main.js index 7d404c93..98aa3af4 100644 --- a/src/main.js +++ b/src/main.js @@ -6656,7 +6656,7 @@ function renderProfileTab(cProfile) { // npub display const profileNpub = document.getElementById('profile-npub'); if (profileNpub) { - profileNpub.textContent = cProfile.id; + profileNpub.textContent = cProfile.id + ' ' + cProfile.id; } // Description @@ -6669,7 +6669,7 @@ function renderProfileTab(cProfile) { // Add npub copy functionality document.getElementById('profile-npub-copy').onclick = (e) => { - const npub = document.getElementById('profile-npub')?.textContent; + const npub = document.getElementById('profile-npub')?.textContent?.split(' ')[0]; if (npub) { // Copy the full profile URL for easy sharing navigator.clipboard.writeText(npub).then(() => { diff --git a/src/styles.css b/src/styles.css index feda50d8..b63105f9 100644 --- a/src/styles.css +++ b/src/styles.css @@ -917,13 +917,23 @@ html, body { margin-right: auto; } +.npub-scroll-wrapper { + flex: 1; + overflow: hidden; + padding: 0 12px; +} + .profile-npub { font-size: 14px; opacity: 0.75; - word-break: break-all; - text-align: center; - flex: 1; - padding: 0 12px; + display: block; + white-space: nowrap; + animation: npub-scroll 12s linear infinite; +} + +@keyframes npub-scroll { + 0% { transform: translateX(0); } + 100% { transform: translateX(-50%); } } .profile-npub-copy { From b96ef7a82ed675af8386de9d3f6165f31375ff90 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 11:16:43 +0700 Subject: [PATCH 10/19] Fix nPub Display > Truncated and add My Profile Top Nav Bar for Profile --- src/index.html | 23 +++++++++------------ src/main.js | 11 ++++++++-- src/styles.css | 56 ++++++++++++++++++++++---------------------------- 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/index.html b/src/index.html index 3ba5c0e9..f9d215aa 100644 --- a/src/index.html +++ b/src/index.html @@ -577,21 +577,18 @@

- - -
-

nPub Key

-
-
-
+ + +
+

nPub Key

+
+
+
- -
- - +
diff --git a/src/main.js b/src/main.js index 98aa3af4..19855893 100644 --- a/src/main.js +++ b/src/main.js @@ -6656,7 +6656,9 @@ function renderProfileTab(cProfile) { // npub display const profileNpub = document.getElementById('profile-npub'); if (profileNpub) { - profileNpub.textContent = cProfile.id + ' ' + cProfile.id; + profileNpub.dataset.fullNpub = cProfile.id; + profileNpub.textContent = cProfile.id.slice(0, 25) + '...' + cProfile.id.slice(-8); + document.getElementById('profile-npub-label').textContent = cProfile.mine ? 'My nPub Key' : 'nPub Key'; } // Description @@ -6669,7 +6671,7 @@ function renderProfileTab(cProfile) { // Add npub copy functionality document.getElementById('profile-npub-copy').onclick = (e) => { - const npub = document.getElementById('profile-npub')?.textContent?.split(' ')[0]; + const npub = document.getElementById('profile-npub')?.dataset.fullNpub; if (npub) { // Copy the full profile URL for easy sharing navigator.clipboard.writeText(npub).then(() => { @@ -6709,6 +6711,9 @@ function renderProfileTab(cProfile) { // Display the Navbar domNavbar.style.display = ''; + document.getElementById('profile-header-avatar-container').style.display = 'none'; + document.getElementById('profile-name').textContent = 'My Profile'; + document.getElementById('profile-status').style.display = 'none'; // Configure other clickables domProfileName.onclick = askForUsername; @@ -6724,6 +6729,8 @@ function renderProfileTab(cProfile) { } else { // Show Contact Options domProfileOptions.style.display = ''; + document.getElementById('profile-header-avatar-container').style.display = ''; + document.getElementById('profile-status').style.display = ''; // Setup Mute option domProfileOptionMute.querySelector('span').classList.replace('icon-volume-' + (cProfile.muted ? 'max' : 'mute'), 'icon-volume-' + (cProfile.muted ? 'mute' : 'max')); diff --git a/src/styles.css b/src/styles.css index b63105f9..8b17e749 100644 --- a/src/styles.css +++ b/src/styles.css @@ -733,8 +733,8 @@ html, body { height: 175px; margin: -87px auto 10px; border-radius: 50%; - border: 8px solid #060606; - background-color: #060606; + border: 8px solid #030303; + background-color: #030303; } /* Avatar Image */ @@ -892,7 +892,7 @@ html, body { border-style: solid; border-width: 2px; color: #b2b2b2; - background-color: #060606; + background-color: #030303; cursor: pointer; } @@ -907,44 +907,38 @@ html, body { .profile-npub-container { display: flex; align-items: center; - justify-content: space-between; - margin: 20px 0; - padding: 12px 16px; - border-radius: 30px; - width: calc(100% - 32px); - max-width: 600px; - margin-left: auto; - margin-right: auto; -} - -.npub-scroll-wrapper { - flex: 1; - overflow: hidden; - padding: 0 12px; + width: 85%; + gap: 4px; + margin: 8px auto 20px auto; + padding: 4px 4px 4px 8px; } .profile-npub { + flex: 1; font-size: 14px; - opacity: 0.75; + opacity: 0.9; display: block; white-space: nowrap; - animation: npub-scroll 12s linear infinite; -} - -@keyframes npub-scroll { - 0% { transform: translateX(0); } - 100% { transform: translateX(-50%); } + text-align: center; } .profile-npub-copy { - width: 36px; - height: 36px; - background: none; + align-self: center; + flex-shrink: 0; + padding: 4px; + line-height: 1; + width: 28px; + height: 28px; display: flex; align-items: center; justify-content: center; - cursor: pointer; - flex-shrink: 0; + background: transparent; + border: none; +} + +.profile-npub-copy .icon-copy { + width: 20px; + height: 20px; } /* Icons */ @@ -1334,8 +1328,8 @@ html, body { margin-right: auto; margin-top: -1px; transition: opacity 0.25s cubic-bezier(0.22, 1, 0.36, 1), max-height 0.3s cubic-bezier(0.34, 1, 0.64, 1), margin-bottom 0.3s cubic-bezier(0.34, 1, 0.64, 1); - max-height: 30px; - overflow: hidden; + max-height: none; + overflow: visible; } .chat-contact-status.status-hidden { From b76e4fa336a514f545e0cdf7736ee1c084715270 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 11:57:16 +0700 Subject: [PATCH 11/19] Edit New Chat Buttons on All Themes --- src/styles.css | 18 +++++++++++++++--- src/themes/chatstr/dark.css | 4 +++- src/themes/gifverse/dark.css | 4 +++- src/themes/pivx/dark.css | 4 +++- src/themes/satoshi/dark.css | 4 +++- src/themes/vector/dark.css | 4 +++- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/styles.css b/src/styles.css index 8b17e749..5ace88c6 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1098,8 +1098,15 @@ html, body { display: flex; align-items: center; height: 40px; - background-color: transparent; - border-color: rgba(128, 128, 128, 0.2); + color: #fff; + background-color: #17171750; + border: 1px solid #80808033; +} + +.new-chat-btn:hover { + color: #fff; + background-color: #171717; + border-color: #B2B2B2; } .new-chat-btn .icon { @@ -1108,6 +1115,11 @@ html, body { width: 30px; height: 30px; margin: 0; + background: var(--primary-color); +} + +.new-chat-btn .icon:hover { + background: var(--accent-color); } #chat-list { @@ -4168,7 +4180,7 @@ select:disabled:hover { } #chat-new-btn .icon { - background-color: var(--icon-color-primary); + background-color: var(--primary-color); } .chat-new-help { diff --git a/src/themes/chatstr/dark.css b/src/themes/chatstr/dark.css index d03bda8b..184b844c 100644 --- a/src/themes/chatstr/dark.css +++ b/src/themes/chatstr/dark.css @@ -7,6 +7,8 @@ --voice-progress-secondary: rgba(177, 136, 226, 0.4); --reply-highlight-border: #CD3DD3; --toast-border-color: #b188e2; + --primary-color: #b188e2; + --accent-color: #CD3DD3; } .sync-line { @@ -118,7 +120,7 @@ button { } .new-chat-btn .icon { - background-color: #b188e2; + background-color: var(--primary-color); } .msg-preview-container { diff --git a/src/themes/gifverse/dark.css b/src/themes/gifverse/dark.css index 1857dbc6..8e1382f3 100644 --- a/src/themes/gifverse/dark.css +++ b/src/themes/gifverse/dark.css @@ -7,6 +7,8 @@ --voice-progress-secondary: #F7FFAE40; --reply-highlight-border: #FFAECE; --toast-border-color: #F7FFAE; + --primary-color: #F7FFAE; + --accent-color: #FFAECE; } .sync-line { @@ -118,7 +120,7 @@ button { } .new-chat-btn .icon { - background-color: #F7FFAE; + background-color: var(--primary-color); } .msg-preview-container { diff --git a/src/themes/pivx/dark.css b/src/themes/pivx/dark.css index a2f7c9f5..2c6827a8 100644 --- a/src/themes/pivx/dark.css +++ b/src/themes/pivx/dark.css @@ -8,6 +8,8 @@ --reply-highlight-border: #a128fd; --toast-border-color: #B359FC; --chat-bg-opacity: 0.04; + --primary-color: #B359FC; + --accent-color: #a128fd; } .sync-line { @@ -141,7 +143,7 @@ button { } .new-chat-btn .icon { - background-color: #B359FC; + background-color: var(--primary-color); } .msg-preview-container { diff --git a/src/themes/satoshi/dark.css b/src/themes/satoshi/dark.css index 43d5163e..56244f43 100644 --- a/src/themes/satoshi/dark.css +++ b/src/themes/satoshi/dark.css @@ -7,6 +7,8 @@ --voice-progress-secondary: #F7931A40; --reply-highlight-border: #F9AA4B; --toast-border-color: #F7931A; + --primary-color: #F7931A; + --accent-color: #F9AA4B; } .sync-line { @@ -118,7 +120,7 @@ button { } .new-chat-btn .icon { - background-color: #F9AA4B; + background-color: var(--primary-color); } .msg-preview-container { diff --git a/src/themes/vector/dark.css b/src/themes/vector/dark.css index d4ba2850..2375f327 100644 --- a/src/themes/vector/dark.css +++ b/src/themes/vector/dark.css @@ -6,6 +6,8 @@ --icon-color-primary: #33DB98; --reply-highlight-border: #33DB98; --toast-border-color: #33DB98; + --primary-color: #33DB98; + --accent-color: #59fcb3; } .sync-line { @@ -123,7 +125,7 @@ button { } .new-chat-btn .icon { - background-color: rgba(128, 255, 212, 0.75); + background-color: var(--primary-color); } .msg-preview-container { From c64201258b151c99a9f59bfd2cd4d7bc4754ce5e Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 13:42:30 +0700 Subject: [PATCH 12/19] Update Export Account Private Key Popup Design --- src/js/settings.js | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/js/settings.js b/src/js/settings.js index 00368846..01353e03 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -891,20 +891,33 @@ domSettingsExport.onclick = async (evt) => { const keys = await invoke('export_keys'); // Create the export content with security warnings - let exportContent = `

Account Export

-

SECURITY WARNING

-

These are your private keys. Anyone with access to them can access your account.

-

Store them securely and never share them with anyone.


`; + let exportContent = ` +
+

Security Warning. Do Not Lose.

+

These keys are your identity on Vector. There are no recovery options! If lost, your account cannot be restored. Never share them.

+ `; - // Add seed phrase first if available (prioritized for users) if (keys.seed_phrase) { - exportContent += `

Seed Phrase:

-

${keys.seed_phrase}


`; + exportContent += ` +
+

Seed Phrase

+
+

${keys.seed_phrase}

+ +
+
+ `; } - // Always add the private key (nsec) - exportContent += `

Private Key (nsec):

-

${keys.nsec}

`; + exportContent += ` +
+

Private Key (nsec)

+
+

${keys.nsec}

+
+

Do Not Store on Device. Backup Offline.

+
+ `; // Show the export information in a popup await popupConfirm('', exportContent, true, '', 'vector_warning.svg'); From f547f300008397498f6dc9ebebb7ee85de770b5b Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 14:06:55 +0700 Subject: [PATCH 13/19] Add Title to Export Account Popup --- src/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/settings.js b/src/js/settings.js index 01353e03..c41a4156 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -920,7 +920,7 @@ domSettingsExport.onclick = async (evt) => { `; // Show the export information in a popup - await popupConfirm('', exportContent, true, '', 'vector_warning.svg'); + await popupConfirm('Export Account', exportContent, true, '', 'vector_warning.svg'); } catch (error) { console.error('Export failed:', error); await popupConfirm('Export Failed', escapeHtml(error.toString()), true, '', 'vector_warning.svg'); From dcef54ab6cf2249b042aed7fe6fecd5a77e666d9 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 16:03:30 +0700 Subject: [PATCH 14/19] Removing Typing Indicator Gradient Dead Code and Update Name --- src/js/misc.js | 2 +- src/main.js | 30 +++++++++++++++--------------- src/styles.css | 9 +-------- src/themes/chatstr/dark.css | 8 +------- src/themes/gifverse/dark.css | 8 +------- src/themes/pivx/dark.css | 8 +------- src/themes/satoshi/dark.css | 8 +------- src/themes/vector/dark.css | 8 +------- 8 files changed, 22 insertions(+), 59 deletions(-) diff --git a/src/js/misc.js b/src/js/misc.js index e8d7fea9..43f9b1db 100644 --- a/src/js/misc.js +++ b/src/js/misc.js @@ -179,7 +179,7 @@ function createPlaceholderAvatar(isGroup = false, limitSizeTo = null) { * @param {Boolean} fNotice - If this is a Notice or an Interactive Dialog. * @param {String} strInputPlaceholder - If specified, renders a text input with a custom placeholder, and returns a string instead of a boolean. * @param {String} strIcon - If specified, an icon to be displayed above the popup. - * @param {String} strTitleClass - If specified, a CSS class to be added to the title element (e.g., 'text-gradient'). + * @param {String} strTitleClass - If specified, a CSS class to be added to the title element (e.g., 'typing-indicator-text'). * @return {Promise} - The Promise will resolve to 'true' if confirm button was clicked, otherwise 'false'. */ async function popupConfirm(strTitle, strSubtext, fNotice = false, strInputPlaceholder = '', strIcon = '', strTitleClass = '') { diff --git a/src/main.js b/src/main.js index 19855893..e9b4d76e 100644 --- a/src/main.js +++ b/src/main.js @@ -4223,7 +4223,7 @@ function updateChatHeaderSubtext(chat) { domChatContactStatus.classList.remove('status-hidden'); domChatContactStatus.style.display = ''; // Reset display in case it was hidden by else branch domChatContactStatus.textContent = newStatusText; - domChatContactStatus.classList.toggle('text-gradient', shouldAddGradient); + domChatContactStatus.classList.toggle('typing-indicator-text', shouldAddGradient); if (!shouldAddGradient) { twemojify(domChatContactStatus); } @@ -4238,7 +4238,7 @@ function updateChatHeaderSubtext(chat) { // Clear content after animation completes (300ms matches CSS transition) statusHideTimeout = setTimeout(() => { domChatContactStatus.textContent = ''; - domChatContactStatus.classList.remove('text-gradient'); + domChatContactStatus.classList.remove('typing-indicator-text'); statusHideTimeout = null; }, 300); } @@ -4633,7 +4633,7 @@ function renderChat(chat, primaryColor) { pChatPreview.classList.add('cutoff'); const preview = generateChatPreviewText(chat); - pChatPreview.classList.toggle('text-gradient', preview.isTyping); + pChatPreview.classList.toggle('typing-indicator-text', preview.isTyping); pChatPreview.textContent = preview.text; if (preview.needsTwemoji) twemojify(pChatPreview); @@ -4685,7 +4685,7 @@ function updateChatlistPreview(chatId) { if (pChatPreview) { const preview = generateChatPreviewText(cChat); - pChatPreview.classList.toggle('text-gradient', preview.isTyping); + pChatPreview.classList.toggle('typing-indicator-text', preview.isTyping); pChatPreview.textContent = preview.text; if (preview.needsTwemoji) twemojify(pChatPreview); } @@ -6315,7 +6315,7 @@ async function login(skipAnimations = false) { switch (type) { case 'start': domLoginEncryptTitle.textContent = message; - domLoginEncryptTitle.classList.add('text-gradient'); + domLoginEncryptTitle.classList.add('typing-indicator-text'); domLoginEncryptTitle.style.color = ''; break; @@ -6330,12 +6330,12 @@ async function login(skipAnimations = false) { case 'complete': domLoginEncryptTitle.textContent = message; - domLoginEncryptTitle.classList.remove('text-gradient'); + domLoginEncryptTitle.classList.remove('typing-indicator-text'); break; case 'error': domLoginEncryptTitle.textContent = message; - domLoginEncryptTitle.classList.remove('text-gradient'); + domLoginEncryptTitle.classList.remove('typing-indicator-text'); domLoginEncryptTitle.style.color = 'red'; break; } @@ -6949,7 +6949,7 @@ function openEncryptionFlow(fUnlock = false, securityType = 'pin') { document.querySelector('.login-encrypt-header').style.display = ''; document.querySelector('.login-lock-icon').style.display = 'none'; domLoginEncryptTitle.textContent = 'Setting up your account...'; - domLoginEncryptTitle.classList.add('startup-subtext-gradient'); + domLoginEncryptTitle.classList.add('startup-subtyping-indicator-text'); await invoke('skip_encryption'); login(); }; @@ -6993,10 +6993,10 @@ function openEncryptionFlow(fUnlock = false, securityType = 'pin') { function updateStatusMessage(message, isProcessing = false) { domLoginEncryptTitle.textContent = message; if (isProcessing) { - domLoginEncryptTitle.classList.add('startup-subtext-gradient'); + domLoginEncryptTitle.classList.add('startup-subtyping-indicator-text'); pinRow.style.display = 'none'; } else { - domLoginEncryptTitle.classList.remove('startup-subtext-gradient'); + domLoginEncryptTitle.classList.remove('startup-subtyping-indicator-text'); pinRow.style.display = ''; } domLoginEncryptPassword.style.display = 'none'; @@ -7120,10 +7120,10 @@ function openEncryptionFlow(fUnlock = false, securityType = 'pin') { function updateStatusMessage(message, isProcessing = false) { domLoginEncryptTitle.textContent = message; if (isProcessing) { - domLoginEncryptTitle.classList.add('startup-subtext-gradient'); + domLoginEncryptTitle.classList.add('startup-subtyping-indicator-text'); domLoginEncryptPassword.style.display = 'none'; } else { - domLoginEncryptTitle.classList.remove('startup-subtext-gradient'); + domLoginEncryptTitle.classList.remove('startup-subtyping-indicator-text'); domLoginEncryptPassword.style.display = ''; } domLoginEncryptPinRow.style.display = 'none'; @@ -7540,7 +7540,7 @@ async function updateChat(chat, arrMessages = [], profile = null, fClicked = fal domChatContact.onclick = null; domChatContact.classList.remove('btn'); domChatContactStatus.textContent = 'Encrypted Notes to Self'; - domChatContactStatus.classList.remove('text-gradient'); + domChatContactStatus.classList.remove('typing-indicator-text'); } else if (isGroup) { domChatContact.textContent = chat?.metadata?.custom_fields?.name || `Group ${strOpenChat.substring(0, 10)}...`; domChatContact.onclick = () => { @@ -7556,7 +7556,7 @@ async function updateChat(chat, arrMessages = [], profile = null, fClicked = fal domChatContact.onclick = null; domChatContact.classList.remove('btn'); domChatContactStatus.textContent = ''; - domChatContactStatus.classList.remove('text-gradient'); + domChatContactStatus.classList.remove('typing-indicator-text'); } domChatContact.classList.toggle('chat-contact', !domChatContactStatus.textContent); @@ -9483,7 +9483,7 @@ async function closeChat() { domChatContact.textContent = ''; domChatContactStatus.textContent = ''; domChatContactStatus.classList.add('status-hidden'); - domChatContactStatus.classList.remove('text-gradient'); + domChatContactStatus.classList.remove('typing-indicator-text'); domChatHeaderAvatarContainer.innerHTML = ''; // Reset procedural scroll state diff --git a/src/styles.css b/src/styles.css index 5ace88c6..0e71ca31 100644 --- a/src/styles.css +++ b/src/styles.css @@ -377,14 +377,7 @@ html, body { margin-top: auto; } -.text-gradient { - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - animation: BreathingGradient 6s cubic-bezier(.46,.03,.52,.96) infinite; -} - -.text-gradient-green { +.typing-indicator-text { background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; diff --git a/src/themes/chatstr/dark.css b/src/themes/chatstr/dark.css index 184b844c..72f5c57d 100644 --- a/src/themes/chatstr/dark.css +++ b/src/themes/chatstr/dark.css @@ -21,18 +21,12 @@ border-color: #b188e2; } -.text-gradient { +.typing-indicator-text { background: linear-gradient(to right, #f8f8f8 13.87%, #f8f8f8 60%); background-size: 200% 200%; background-clip: text; } -.text-gradient-green { - background: linear-gradient(to right, #59fcb3 13.87%, #2b976c 60%); - background-size: 200% 200%; - background-clip: text; -} - .back-btn { color: rgba(167, 137, 204, 1); } diff --git a/src/themes/gifverse/dark.css b/src/themes/gifverse/dark.css index 8e1382f3..f0ca73d3 100644 --- a/src/themes/gifverse/dark.css +++ b/src/themes/gifverse/dark.css @@ -21,18 +21,12 @@ border-color: #F7FFAE; } -.text-gradient { +.typing-indicator-text { background: linear-gradient(to right, #f8f8f8 13.87%, #f8f8f8 60%); background-size: 200% 200%; background-clip: text; } -.text-gradient-green { - background: linear-gradient(to right, #F7FFAE 13.87%, #F7FFAE 60%); - background-size: 200% 200%; - background-clip: text; -} - .back-btn { color: #F7FFAE; } diff --git a/src/themes/pivx/dark.css b/src/themes/pivx/dark.css index 2c6827a8..5b2c774a 100644 --- a/src/themes/pivx/dark.css +++ b/src/themes/pivx/dark.css @@ -22,18 +22,12 @@ border-color: #6202D4; } -.text-gradient { +.typing-indicator-text { background: linear-gradient(to right, #f8f8f8 13.87%, #6202D4 60%); background-size: 200% 200%; background-clip: text; } -.text-gradient-green { - background: linear-gradient(to right, #6202D4 13.87%, #1D003F 60%); - background-size: 200% 200%; - background-clip: text; -} - .back-btn { color: #B359FC; } diff --git a/src/themes/satoshi/dark.css b/src/themes/satoshi/dark.css index 56244f43..365eda74 100644 --- a/src/themes/satoshi/dark.css +++ b/src/themes/satoshi/dark.css @@ -21,18 +21,12 @@ border-color: #F7931A; } -.text-gradient { +.typing-indicator-text { background: linear-gradient(to right, #f8f8f8 13.87%, #F7931A 60%); background-size: 200% 200%; background-clip: text; } -.text-gradient-green { - background: linear-gradient(to right, #F7931A 13.87%, #B56C12 60%); - background-size: 200% 200%; - background-clip: text; -} - .back-btn { color: #F9AA4B; } diff --git a/src/themes/vector/dark.css b/src/themes/vector/dark.css index 2375f327..ce6175b6 100644 --- a/src/themes/vector/dark.css +++ b/src/themes/vector/dark.css @@ -20,18 +20,12 @@ border-color: #33DB98; } -.text-gradient { +.typing-indicator-text { background: linear-gradient(to right, #ffffff 13.87%, #808080 60%); background-size: 200% 200%; background-clip: text; } -.text-gradient-green { - background: linear-gradient(to right, #59fcb3 13.87%, #2b976c 80%); - background-size: 200% 200%; - background-clip: text; -} - .back-btn { color: rgb(191, 191, 191); } From fe54bb3116dd3055b5064a3ea77506eee8ca43d8 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 18:43:45 +0700 Subject: [PATCH 15/19] Patch Key PIN Code Decryption Gradient --- src/main.js | 10 +++++----- src/styles.css | 8 +++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main.js b/src/main.js index e9b4d76e..c40223e8 100644 --- a/src/main.js +++ b/src/main.js @@ -6949,7 +6949,7 @@ function openEncryptionFlow(fUnlock = false, securityType = 'pin') { document.querySelector('.login-encrypt-header').style.display = ''; document.querySelector('.login-lock-icon').style.display = 'none'; domLoginEncryptTitle.textContent = 'Setting up your account...'; - domLoginEncryptTitle.classList.add('startup-subtyping-indicator-text'); + domLoginEncryptTitle.classList.add('startup-subtext-gradient'); await invoke('skip_encryption'); login(); }; @@ -6993,10 +6993,10 @@ function openEncryptionFlow(fUnlock = false, securityType = 'pin') { function updateStatusMessage(message, isProcessing = false) { domLoginEncryptTitle.textContent = message; if (isProcessing) { - domLoginEncryptTitle.classList.add('startup-subtyping-indicator-text'); + domLoginEncryptTitle.classList.add('startup-subtext-gradient'); pinRow.style.display = 'none'; } else { - domLoginEncryptTitle.classList.remove('startup-subtyping-indicator-text'); + domLoginEncryptTitle.classList.remove('startup-subtext-gradient'); pinRow.style.display = ''; } domLoginEncryptPassword.style.display = 'none'; @@ -7120,10 +7120,10 @@ function openEncryptionFlow(fUnlock = false, securityType = 'pin') { function updateStatusMessage(message, isProcessing = false) { domLoginEncryptTitle.textContent = message; if (isProcessing) { - domLoginEncryptTitle.classList.add('startup-subtyping-indicator-text'); + domLoginEncryptTitle.classList.add('startup-subtext-gradient'); domLoginEncryptPassword.style.display = 'none'; } else { - domLoginEncryptTitle.classList.remove('startup-subtyping-indicator-text'); + domLoginEncryptTitle.classList.remove('startup-subtext-gradient'); domLoginEncryptPassword.style.display = ''; } domLoginEncryptPinRow.style.display = 'none'; diff --git a/src/styles.css b/src/styles.css index 0e71ca31..4d9be268 100644 --- a/src/styles.css +++ b/src/styles.css @@ -385,15 +385,13 @@ html, body { } .startup-subtext-gradient { - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - animation: BreathingGradient 6s cubic-bezier(.46,.03,.52,.96) infinite; - /* Always uses Vector theme (brand colour) */ background: linear-gradient(to right, #2b976c 13.87%, #59fcb3 60%); background-size: 200% 200%; background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: BreathingGradient 6s cubic-bezier(.46,.03,.52,.96) infinite; } @keyframes BreathingGradient { From f540d9c7f444b4b028355ce657ac536f75bc27d2 Mon Sep 17 00:00:00 2001 From: Yuurin Bee Date: Mon, 23 Feb 2026 18:56:39 +0700 Subject: [PATCH 16/19] Fix width on Sound Preview button --- src/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.html b/src/index.html index f9d215aa..9cd0a251 100644 --- a/src/index.html +++ b/src/index.html @@ -917,7 +917,7 @@

Notifications

- From 0f4362c62b875fef07ad4e7d1c82da47c4f26b63 Mon Sep 17 00:00:00 2001 From: JSKitty Date: Wed, 25 Feb 2026 15:25:29 +0000 Subject: [PATCH 17/19] fix: restore production app identifier (io.vectorapp) Co-Authored-By: Claude Opus 4.6 --- src-tauri/tauri.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 3f72dfdb..ee55b264 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -2,7 +2,7 @@ "$schema": "https://schema.tauri.app/config/2", "productName": "Vector", "mainBinaryName": "Vector", - "identifier": "io.vectorapp.dev", + "identifier": "io.vectorapp", "build": { "frontendDist": "../dist", "beforeDevCommand": "node scripts/build-frontend.mjs --dev", From eb067466bd19fc7b8ccaf6eb543580cb82be941c Mon Sep 17 00:00:00 2001 From: JSKitty Date: Wed, 25 Feb 2026 15:40:26 +0000 Subject: [PATCH 18/19] fix: harden export popup XSS, hide Change PIN when encryption disabled, center nPub truncation - Escape seed phrase and nsec via escapeHtml() before HTML interpolation to prevent XSS from malicious DB content; replace inline onclick with DOM-bound click handlers - Hide the entire Change PIN container (not just the button) when local encryption is disabled; start hidden via display:none to prevent flash - Add null guard for domSettingsChangePinInfo onclick binding - Center nPub truncation: 16 prefix + ... + 16 suffix (was 25+8) Co-Authored-By: Claude Opus 4.6 --- src/index.html | 2 +- src/js/settings.js | 25 +++++++++++++++++-------- src/main.js | 27 ++++++++++++++------------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/index.html b/src/index.html index 494ef11a..ac287b33 100644 --- a/src/index.html +++ b/src/index.html @@ -1029,7 +1029,7 @@

Security

-
+