mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 10:15:27 -04:00
Polish email send and card toggles
This commit is contained in:
@@ -2824,8 +2824,9 @@ import * as Modals from './modalManager.js';
|
|||||||
onAction: () => { canceled = true; },
|
onAction: () => { canceled = true; },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
detachedEmailDoc = _detachActiveEmailForBackground(sendDocId);
|
await _sleep(1000);
|
||||||
await _sleep(1200);
|
if (!canceled) detachedEmailDoc = _detachActiveEmailForBackground(sendDocId);
|
||||||
|
await _sleep(200);
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
_restoreDetachedEmailDoc(detachedEmailDoc);
|
_restoreDetachedEmailDoc(detachedEmailDoc);
|
||||||
detachedEmailDoc = null;
|
detachedEmailDoc = null;
|
||||||
@@ -2837,6 +2838,7 @@ import * as Modals from './modalManager.js';
|
|||||||
if (uiModule) {
|
if (uiModule) {
|
||||||
uiModule.showToast('Message sent', {
|
uiModule.showToast('Message sent', {
|
||||||
duration: 2200,
|
duration: 2200,
|
||||||
|
leadingIcon: 'check',
|
||||||
action: 'Undo',
|
action: 'Undo',
|
||||||
actionHint: 'undo send',
|
actionHint: 'undo send',
|
||||||
onAction: () => { undone = true; },
|
onAction: () => { undone = true; },
|
||||||
@@ -2868,6 +2870,7 @@ import * as Modals from './modalManager.js';
|
|||||||
if (uiModule) {
|
if (uiModule) {
|
||||||
uiModule.showToast('Message sent', {
|
uiModule.showToast('Message sent', {
|
||||||
duration: 7000,
|
duration: 7000,
|
||||||
|
leadingIcon: 'check',
|
||||||
action: 'View Message',
|
action: 'View Message',
|
||||||
onAction: () => {
|
onAction: () => {
|
||||||
import('./emailLibrary.js').then(mod => {
|
import('./emailLibrary.js').then(mod => {
|
||||||
|
|||||||
+38
-1
@@ -8,11 +8,41 @@ import themeModule from './theme.js';
|
|||||||
|
|
||||||
let toastEl = null;
|
let toastEl = null;
|
||||||
let autoScrollEnabled = true;
|
let autoScrollEnabled = true;
|
||||||
|
let hoveredToggleCard = null;
|
||||||
|
|
||||||
// Smooth scroll state
|
// Smooth scroll state
|
||||||
let _scrollRafId = null;
|
let _scrollRafId = null;
|
||||||
let _scrollBox = null;
|
let _scrollBox = null;
|
||||||
|
|
||||||
|
function _isTextEditingTarget(target) {
|
||||||
|
const el = target && target.nodeType === 1 ? target : target?.parentElement;
|
||||||
|
return !!(el && el.closest('input, textarea, select, [contenteditable="true"], [contenteditable=""]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function _initHoverCardSpaceToggle() {
|
||||||
|
if (document._odysseusHoverCardSpaceToggle) return;
|
||||||
|
document._odysseusHoverCardSpaceToggle = true;
|
||||||
|
document.addEventListener('pointerover', (e) => {
|
||||||
|
const card = e.target?.closest?.('#email-lib-modal .doclib-card, #doclib-modal .doclib-card, .email-reader-tab-modal .doclib-card, .email-window-modal .doclib-card');
|
||||||
|
if (card) hoveredToggleCard = card;
|
||||||
|
}, true);
|
||||||
|
document.addEventListener('pointerout', (e) => {
|
||||||
|
if (!hoveredToggleCard) return;
|
||||||
|
const next = e.relatedTarget;
|
||||||
|
if (!next || !hoveredToggleCard.contains(next)) hoveredToggleCard = null;
|
||||||
|
}, true);
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.code !== 'Space' || e.repeat || !hoveredToggleCard || !document.contains(hoveredToggleCard)) return;
|
||||||
|
if (_isTextEditingTarget(e.target)) return;
|
||||||
|
const blocked = e.target?.closest?.('button, a, input, textarea, select, [contenteditable="true"], [contenteditable=""], .recipient-chip, .doclib-card-dropdown, .email-card-dropdown');
|
||||||
|
if (blocked) return;
|
||||||
|
e.preventDefault();
|
||||||
|
hoveredToggleCard.click();
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_initHoverCardSpaceToggle();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy text to clipboard
|
* Copy text to clipboard
|
||||||
*/
|
*/
|
||||||
@@ -104,18 +134,25 @@ export function showToast(msg, durationOrOpts) {
|
|||||||
toastEl.textContent = '';
|
toastEl.textContent = '';
|
||||||
toastEl.classList.remove('error');
|
toastEl.classList.remove('error');
|
||||||
|
|
||||||
let duration = 1200, actionLabel = null, onAction = null, actionHint = null, actionIcon = null;
|
let duration = 1200, actionLabel = null, onAction = null, actionHint = null, actionIcon = null, leadingIcon = null;
|
||||||
if (typeof durationOrOpts === 'object' && durationOrOpts) {
|
if (typeof durationOrOpts === 'object' && durationOrOpts) {
|
||||||
duration = durationOrOpts.duration || 5000;
|
duration = durationOrOpts.duration || 5000;
|
||||||
actionLabel = durationOrOpts.action;
|
actionLabel = durationOrOpts.action;
|
||||||
onAction = durationOrOpts.onAction;
|
onAction = durationOrOpts.onAction;
|
||||||
actionHint = durationOrOpts.actionHint || null;
|
actionHint = durationOrOpts.actionHint || null;
|
||||||
actionIcon = durationOrOpts.actionIcon || null;
|
actionIcon = durationOrOpts.actionIcon || null;
|
||||||
|
leadingIcon = durationOrOpts.leadingIcon || null;
|
||||||
} else if (typeof durationOrOpts === 'number') {
|
} else if (typeof durationOrOpts === 'number') {
|
||||||
duration = durationOrOpts;
|
duration = durationOrOpts;
|
||||||
}
|
}
|
||||||
|
|
||||||
const textSpan = document.createElement('span');
|
const textSpan = document.createElement('span');
|
||||||
|
if (leadingIcon === 'check') {
|
||||||
|
const icon = document.createElement('span');
|
||||||
|
icon.className = 'toast-checkmark';
|
||||||
|
icon.innerHTML = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg>';
|
||||||
|
toastEl.appendChild(icon);
|
||||||
|
}
|
||||||
textSpan.textContent = msg;
|
textSpan.textContent = msg;
|
||||||
toastEl.appendChild(textSpan);
|
toastEl.appendChild(textSpan);
|
||||||
|
|
||||||
|
|||||||
@@ -3534,6 +3534,32 @@ body.bg-pattern-sparkles {
|
|||||||
max-width: min(360px, calc(100vw - 32px));
|
max-width: min(360px, calc(100vw - 32px));
|
||||||
}
|
}
|
||||||
.toast.show { opacity:1; transform: translateX(0); }
|
.toast.show { opacity:1; transform: translateX(0); }
|
||||||
|
.toast .toast-checkmark {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 7px;
|
||||||
|
color: var(--green, #50fa7b);
|
||||||
|
vertical-align: -3px;
|
||||||
|
transform: scale(0.65);
|
||||||
|
opacity: 0;
|
||||||
|
animation: toastCheckPop 360ms cubic-bezier(0.2, 0.9, 0.25, 1.25) forwards;
|
||||||
|
}
|
||||||
|
.toast .toast-checkmark svg polyline {
|
||||||
|
stroke-dasharray: 24;
|
||||||
|
stroke-dashoffset: 24;
|
||||||
|
animation: toastCheckDraw 420ms ease-out 120ms forwards;
|
||||||
|
}
|
||||||
|
@keyframes toastCheckPop {
|
||||||
|
0% { opacity: 0; transform: scale(0.65); }
|
||||||
|
65% { opacity: 1; transform: scale(1.16); }
|
||||||
|
100% { opacity: 1; transform: scale(1); }
|
||||||
|
}
|
||||||
|
@keyframes toastCheckDraw {
|
||||||
|
to { stroke-dashoffset: 0; }
|
||||||
|
}
|
||||||
.toast.exiting {
|
.toast.exiting {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-120%);
|
transform: translateX(-120%);
|
||||||
@@ -10654,6 +10680,8 @@ textarea.memory-add-input {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
max-width: 70vw;
|
max-width: 70vw;
|
||||||
|
container-type: inline-size;
|
||||||
|
container-name: docpane;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
@@ -14210,6 +14238,30 @@ body.left-dock-active {
|
|||||||
#doclib-modal.doclib-fullscreen .doclib-modal-content {
|
#doclib-modal.doclib-fullscreen .doclib-modal-content {
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
}
|
}
|
||||||
|
.modal.modal-right-docked .email-reader-header,
|
||||||
|
.modal.modal-left-docked .email-reader-header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.modal.modal-right-docked .email-reader-actions,
|
||||||
|
.modal.modal-left-docked .email-reader-actions {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
.modal.modal-right-docked .email-reader-meta-row,
|
||||||
|
.modal.modal-left-docked .email-reader-meta-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 2px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
.modal.modal-right-docked .email-reader-meta-row strong,
|
||||||
|
.modal.modal-left-docked .email-reader-meta-row strong {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.modal.modal-right-docked .recipient-chip,
|
||||||
|
.modal.modal-left-docked .recipient-chip {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
.archive-list {
|
.archive-list {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
border-top: 1px solid var(--border);
|
border-top: 1px solid var(--border);
|
||||||
@@ -26101,6 +26153,27 @@ button .spinner-whirlpool {
|
|||||||
border-color: var(--accent-primary, var(--red));
|
border-color: var(--accent-primary, var(--red));
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
}
|
}
|
||||||
|
@container docpane (max-width: 460px) {
|
||||||
|
.email-reader-header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.email-reader-actions {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
.email-reader-meta-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 2px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
.email-reader-meta-row strong {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.recipient-chip {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
.email-reader-actions {
|
.email-reader-actions {
|
||||||
display: flex; gap: 4px; flex-wrap: nowrap; align-items: center;
|
display: flex; gap: 4px; flex-wrap: nowrap; align-items: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -27564,6 +27637,21 @@ body.doc-find-active mark.doc-find-mark.current {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.email-field input:focus { border-color: var(--accent, #4a9eff); }
|
.email-field input:focus { border-color: var(--accent, #4a9eff); }
|
||||||
|
@container docpane (max-width: 460px) {
|
||||||
|
.doc-email-header .email-field {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 3px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.doc-email-header .email-field label {
|
||||||
|
min-width: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.doc-email-header .email-field input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Cc toggle and attach button are absolute so they don't steal width from the To input */
|
/* Cc toggle and attach button are absolute so they don't steal width from the To input */
|
||||||
.email-field .email-cc-toggle {
|
.email-field .email-cc-toggle {
|
||||||
position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
|
position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
|
||||||
|
|||||||
Reference in New Issue
Block a user