@zaclinley/dsh-mailharbor 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +18 -18
- package/README.zh.md +18 -18
- package/lib/client.js +414 -164
- package/lib/client.js.map +3 -3
- package/lib/index.js +248 -1
- package/lib/index.js.map +4 -4
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -35,7 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// src/client/styles.css
|
|
38
|
-
var styles_default = "/* MailHarbor panel + settings.\n Tokens come from the DSH shell (dark by default); fallbacks match the\n default dark theme so the panel also renders in a bare host page.\n Component rules are all scoped under `.mailharbor` and the generic element\n reset lives in `:where()` so it cannot outrank a component class. */\n\n.mailharbor {\n --m-bg: var(--dsw-alias-bg-base, #151517);\n --m-bg-1: var(--dsw-alias-bg-layer-1, #232324);\n --m-bg-2: var(--dsw-alias-bg-layer-2, #2c2c2e);\n --m-bg-3: var(--dsw-alias-bg-layer-3, #353638);\n --m-line: var(--dsw-alias-border-l2, #ffffff1f);\n --m-line-soft: var(--dsw-alias-border-l1, #ffffff0f);\n --m-line-strong: var(--dsw-alias-border-l3, #ffffff29);\n --m-text: var(--dsw-alias-label-primary, #f9fafb);\n --m-text-2: var(--dsw-alias-label-secondary, #cfd3d6);\n --m-text-3: var(--dsw-alias-label-tertiary, #adb2b8);\n --m-caption: var(--dsw-alias-label-caption, #81858c);\n --m-accent: #5686fe;\n --m-accent-soft: rgba(86, 134, 254, 0.14);\n --m-primary-bg: var(--dsw-alias-brand-primary, #f9fafb);\n --m-primary-fg: var(--dsw-alias-label-primary-foreground, #0f1115);\n --m-hover: var(--dsw-alias-interactive-bg-hover, #ffffff14);\n --m-danger: #f25a5a;\n --m-ok: #3fbf7f;\n --m-warn: var(--dsw-alias-state-warn-label, #dd8629);\n --m-radius: 8px;\n --m-shadow: 0 18px 60px rgba(0, 0, 0, 0.5);\n\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--m-bg);\n color: var(--m-text);\n font-size: 13px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\n\n.mailharbor *,\n.mailharbor *::before,\n.mailharbor *::after {\n box-sizing: border-box;\n}\n\n/* ---------- base controls ---------- */\n\n.mailharbor :where(button) {\n font: inherit;\n color: inherit;\n background: transparent;\n border: 0;\n margin: 0;\n cursor: pointer;\n}\n\n.mailharbor button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 30px;\n padding: 0 12px;\n border-radius: var(--m-radius);\n border: 1px solid transparent;\n color: var(--m-text-2);\n font-size: 12.5px;\n font-weight: 500;\n white-space: nowrap;\n transition:\n background 120ms ease,\n color 120ms ease,\n border-color 120ms ease;\n}\n\n.mailharbor button:hover:not(:disabled) {\n background: var(--m-hover);\n color: var(--m-text);\n}\n\n.mailharbor button:disabled {\n opacity: 0.45;\n cursor: default;\n}\n\n.mailharbor button.primary {\n background: var(--m-primary-bg);\n color: var(--m-primary-fg);\n border-color: transparent;\n}\n\n.mailharbor button.primary:hover:not(:disabled) {\n background: var(--m-primary-bg);\n filter: brightness(0.94);\n color: var(--m-primary-fg);\n}\n\n.mailharbor button.ghost {\n border-color: var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor button.ghost:hover:not(:disabled) {\n border-color: var(--m-line-strong);\n color: var(--m-text);\n}\n\n.mailharbor button.subtle {\n color: var(--m-text-3);\n padding: 0 8px;\n}\n\n.mailharbor button.icon {\n width: 30px;\n padding: 0;\n}\n\n.mailharbor button.danger {\n color: var(--m-danger);\n}\n\n.mailharbor input,\n.mailharbor select,\n.mailharbor textarea {\n font: inherit;\n color: var(--m-text);\n background: var(--m-bg-1);\n border: 1px solid var(--m-line);\n border-radius: var(--m-radius);\n padding: 0 10px;\n height: 32px;\n min-width: 0;\n}\n\n.mailharbor textarea {\n height: auto;\n padding: 8px 10px;\n resize: vertical;\n line-height: 1.6;\n}\n\n.mailharbor select {\n padding-right: 26px;\n appearance: none;\n background-image:\n linear-gradient(45deg, transparent 50%, var(--m-text-3) 50%),\n linear-gradient(135deg, var(--m-text-3) 50%, transparent 50%);\n background-position:\n calc(100% - 15px) 14px,\n calc(100% - 10px) 14px;\n background-size:\n 5px 5px,\n 5px 5px;\n background-repeat: no-repeat;\n}\n\n.mailharbor ::placeholder {\n color: var(--m-caption);\n}\n\n.mailharbor input:focus-visible,\n.mailharbor select:focus-visible,\n.mailharbor textarea:focus-visible,\n.mailharbor button:focus-visible,\n.mailharbor [contenteditable='true']:focus-visible {\n outline: 2px solid rgba(86, 134, 254, 0.55);\n outline-offset: -1px;\n}\n\n.mailharbor .spacer {\n flex: 1;\n}\n\n.mailharbor .muted {\n color: var(--m-text-3);\n}\n\n.mailharbor .small {\n font-size: 12px;\n}\n\n.mailharbor .badge {\n display: inline-flex;\n align-items: center;\n height: 18px;\n padding: 0 6px;\n border-radius: 999px;\n font-size: 10.5px;\n font-weight: 500;\n background: var(--m-bg-3);\n color: var(--m-text-2);\n}\n\n.mailharbor .badge.ok {\n background: rgba(63, 191, 127, 0.16);\n color: var(--m-ok);\n}\n\n.mailharbor .badge.warn {\n background: rgba(221, 134, 41, 0.16);\n color: var(--m-warn);\n}\n\n.mailharbor .error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.1);\n border-bottom: 1px solid rgba(242, 90, 90, 0.2);\n font-size: 12.5px;\n}\n\n/* ---------- shell ---------- */\n\n.mailharbor-topbar {\n display: flex;\n align-items: center;\n gap: 10px;\n height: 52px;\n padding: 0 14px;\n border-bottom: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n flex: none;\n}\n\n.mailharbor-account {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n max-width: 220px;\n padding: 4px 8px 4px 4px;\n border-radius: 999px;\n border: 1px solid transparent;\n cursor: default;\n}\n\n.mailharbor-account:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-account .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.mailharbor-account select {\n height: 26px;\n background: transparent;\n border-color: transparent;\n font-weight: 500;\n}\n\n.mailharbor-body {\n display: flex;\n flex: 1;\n min-height: 0;\n position: relative;\n}\n\n.mailharbor button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-list {\n display: flex;\n flex-direction: column;\n width: 360px;\n flex: none;\n border-right: 1px solid var(--m-line-soft);\n min-height: 0;\n}\n\n.mailharbor-reader {\n flex: 1;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n@media (max-width: 1000px) {\n .mailharbor-list {\n width: 300px;\n }\n}\n\n.mailharbor-narrow .mailharbor-body[data-mode='reader'] .mailharbor-list {\n display: none;\n}\n\n.mailharbor-narrow .mailharbor-body[data-mode='list'] .mailharbor-reader {\n display: none;\n}\n\n/* ---------- segmented control ---------- */\n\n.mailharbor-segment {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n border-radius: 9px;\n background: var(--m-bg-2);\n}\n\n.mailharbor-segment button {\n height: 26px;\n padding: 0 12px;\n border-radius: 7px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor-segment button:hover:not(.active) {\n color: var(--m-text-2);\n background: transparent;\n}\n\n.mailharbor-segment button.active {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n/* ---------- list ---------- */\n\n.mailharbor-filters {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-filters select {\n width: 128px;\n flex: none;\n font-size: 12px;\n}\n\n.mailharbor-filters input[type='search'] {\n flex: 1;\n height: 30px;\n font-size: 12.5px;\n}\n\n.mailharbor-rows {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n.mailharbor-row {\n display: flex;\n flex-direction: column;\n gap: 3px;\n width: 100%;\n padding: 10px 14px;\n border: 0;\n border-bottom: 1px solid var(--m-line-soft);\n border-left: 2px solid transparent;\n border-radius: 0;\n background: transparent;\n color: inherit;\n text-align: left;\n cursor: pointer;\n user-select: none;\n}\n\n.mailharbor-row:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-row.selected {\n background: var(--m-accent-soft);\n border-left-color: var(--m-accent);\n}\n\n.mailharbor-row .line-1,\n.mailharbor-row .line-2 {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n width: 100%;\n}\n\n.mailharbor-row .from {\n font-weight: 600;\n font-size: 12.5px;\n color: var(--m-text-2);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-row .date {\n margin-left: auto;\n color: var(--m-caption);\n font-size: 11px;\n flex: none;\n}\n\n.mailharbor-row .subject {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n.mailharbor-row .snippet {\n color: var(--m-caption);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n width: 100%;\n}\n\n.mailharbor-row.unread .from,\n.mailharbor-row.unread .subject {\n color: var(--m-text);\n}\n\n.mailharbor-row .dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--m-accent);\n flex: none;\n}\n\n.mailharbor-row .paperclip {\n color: var(--m-caption);\n flex: none;\n display: inline-flex;\n}\n\n.mailharbor-list-foot {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-top: 1px solid var(--m-line-soft);\n color: var(--m-text-3);\n font-size: 11.5px;\n flex: none;\n}\n\n.mailharbor-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 48px 24px;\n color: var(--m-text-3);\n text-align: center;\n}\n\n.mailharbor-empty svg {\n opacity: 0.5;\n}\n\n.mailharbor-empty .title {\n color: var(--m-text-2);\n font-size: 13px;\n font-weight: 500;\n}\n\n/* ---------- reader ---------- */\n\n.mailharbor-reader-head {\n padding: 16px 20px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.mailharbor-reader-title {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n\n.mailharbor-reader-title h2 {\n margin: 0;\n font-size: 17px;\n line-height: 1.35;\n font-weight: 600;\n letter-spacing: -0.01em;\n word-break: break-word;\n}\n\n.mailharbor-reader-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 10px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor-reader-meta .who {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n color: var(--m-text-2);\n}\n\n.mailharbor-reader-meta .who strong {\n color: var(--m-text);\n font-weight: 600;\n}\n\n.mailharbor-reader-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.mailharbor-reader-body {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n padding: 14px 18px 18px;\n background: var(--m-bg-2);\n}\n\n.mailharbor-reader-body iframe {\n flex: 1;\n width: 100%;\n border: 0;\n border-radius: 10px;\n background: #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n}\n\n.mailharbor-reader-body pre {\n flex: 1;\n overflow: auto;\n margin: 0;\n padding: 20px 22px;\n white-space: pre-wrap;\n word-break: break-word;\n background: #fff;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n color: #171a21;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12.5px;\n line-height: 1.7;\n}\n\n.mailharbor-attachments {\n padding: 10px 18px;\n border-top: 1px solid var(--m-line-soft);\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n flex: none;\n background: var(--m-bg);\n}\n\n.mailharbor-attachment {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 30px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: var(--m-radius);\n font-size: 12px;\n text-decoration: none;\n color: var(--m-text-2);\n max-width: 260px;\n background: var(--m-bg-1);\n}\n\n.mailharbor-attachment:hover {\n border-color: var(--m-line-strong);\n color: var(--m-text);\n}\n\n.mailharbor-attachment .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---------- AI rail ---------- */\n\n.mailharbor-ai {\n display: flex;\n flex-direction: column;\n width: 340px;\n flex: none;\n min-height: 0;\n border-left: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-ai-head {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 46px;\n padding: 0 8px 0 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-head strong {\n font-size: 13px;\n font-weight: 600;\n}\n\n.mailharbor-ai-confirm {\n display: inline-flex;\n gap: 2px;\n}\n\n.mailharbor-ai-context {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 9px 14px 10px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-context strong {\n font-size: 12.5px;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-ai-warn {\n padding: 8px 14px;\n color: var(--m-warn);\n background: rgba(221, 134, 41, 0.1);\n font-size: 12px;\n flex: none;\n}\n\n.mailharbor-ai-quick {\n display: flex;\n gap: 6px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-quick button {\n flex: 1;\n padding: 0 6px;\n}\n\n.mailharbor-ai-list {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n}\n\n.mailharbor-ai-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 30px 12px;\n text-align: center;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-empty .title {\n color: var(--m-text-2);\n font-weight: 500;\n font-size: 12.5px;\n}\n\n.mailharbor-ai-card {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n overflow: hidden;\n}\n\n.mailharbor-ai-card.generating {\n opacity: 0.7;\n}\n\n.mailharbor-ai-card-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 7px 8px 7px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-card-head > span:first-child {\n color: var(--m-text-2);\n font-weight: 600;\n}\n\n.mailharbor-ai-summary {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 10px 12px;\n}\n\n.mailharbor-ai-summary section h4 {\n margin: 0 0 3px;\n font-size: 11px;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mailharbor-ai-summary section p {\n margin: 0;\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-text {\n padding: 10px 12px;\n max-height: 320px;\n overflow: auto;\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-card-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n padding: 6px 8px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-ai-card-actions button {\n height: 26px;\n padding: 0 8px;\n font-size: 11.5px;\n}\n\n.mailharbor-ai-ask {\n display: flex;\n gap: 6px;\n padding: 10px 12px;\n border-top: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-ask input {\n flex: 1;\n height: 32px;\n}\n\n.mailharbor-ai-error {\n color: var(--m-danger);\n font-size: 12px;\n padding: 0 2px;\n}\n\n@media (max-width: 1280px) {\n .mailharbor-ai {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(420px, 94%);\n z-index: 6;\n border-left: 1px solid var(--m-line);\n box-shadow: -12px 0 40px rgba(0, 0, 0, 0.45);\n }\n}\n\n/* ---------- AI summary ---------- */\n\n.mailharbor-divider {\n width: 1px;\n height: 18px;\n margin: 0 4px;\n background: var(--m-line);\n}\n\n.mailharbor-summary {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.mailharbor-summary section h4 {\n margin: 0 0 6px;\n font-size: 11.5px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-summary section p {\n margin: 0;\n white-space: pre-wrap;\n line-height: 1.75;\n color: var(--m-text);\n}\n\n/* ---------- modal / forms ---------- */\n\n.mailharbor-portal {\n position: fixed;\n inset: 0;\n z-index: 80;\n height: auto;\n background: transparent;\n pointer-events: none;\n}\n\n.mailharbor-portal .mailharbor-modal-mask {\n pointer-events: auto;\n}\n\n.mailharbor-modal-mask {\n position: fixed;\n inset: 0;\n z-index: 60;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(2px);\n}\n\n.mailharbor-modal {\n display: flex;\n flex-direction: column;\n width: min(720px, 100%);\n max-height: 86vh;\n overflow: hidden;\n border: 1px solid var(--m-line);\n border-radius: 14px;\n background: var(--m-bg-1);\n color: var(--m-text);\n box-shadow: var(--m-shadow);\n}\n\n.mailharbor-modal > header {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 52px;\n padding: 0 14px 0 18px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 14px;\n font-weight: 600;\n}\n\n.mailharbor-modal .content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 18px;\n overflow: auto;\n}\n\n.mailharbor-modal > footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 18px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.mailharbor-field > input,\n.mailharbor-field > select,\n.mailharbor-field > textarea,\n.mailharbor-card > textarea {\n width: 100%;\n min-width: 0;\n}\n\n.mailharbor-field > label {\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-grid {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 10px;\n min-width: 0;\n}\n\n.mailharbor-grid.three {\n grid-template-columns: minmax(0, 2fr) minmax(72px, 90px) auto;\n align-items: end;\n min-width: 0;\n}\n\n.mailharbor-toggle {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n color: var(--m-text-2);\n font-size: 12.5px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.mailharbor-toggle input[type='checkbox'] {\n width: 14px;\n height: 14px;\n accent-color: var(--m-accent);\n}\n\n/* ---------- composer ---------- */\n\n.mailharbor-toolbar {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-wrap: wrap;\n padding: 6px;\n border: 1px solid var(--m-line-soft);\n border-bottom: 0;\n border-radius: 10px 10px 0 0;\n background: var(--m-bg-2);\n}\n\n.mailharbor-toolbar button {\n height: 26px;\n padding: 0 9px;\n border-radius: 6px;\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-toolbar button:hover {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n.mailharbor-editor {\n min-height: 240px;\n max-height: 44vh;\n overflow: auto;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 0 0 10px 10px;\n background: #fff;\n color: #171a21;\n outline: none;\n font-size: 13.5px;\n line-height: 1.7;\n}\n\n.mailharbor-editor:empty::before {\n content: attr(data-placeholder);\n color: #9aa0ab;\n}\n\n/* ---------- inline confirm ---------- */\n\n.mailharbor-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--m-line);\n background: var(--m-bg-2);\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n/* ---------- selection / extraction ---------- */\n\n.mailharbor-selectbar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n margin: 0 12px 8px;\n border: 1px solid var(--m-accent-soft);\n border-radius: 9px;\n background: var(--m-accent-soft);\n}\n\n.mailharbor-selectbar select {\n height: 28px;\n max-width: 200px;\n}\n\n.mailharbor-row.selectable input[type='checkbox'] {\n width: 15px;\n height: 15px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 9px 10px;\n border: 1px solid var(--m-line-soft);\n border-radius: 9px;\n background: var(--m-bg-1);\n cursor: pointer;\n}\n\n.mailharbor-extract-row input {\n margin-top: 2px;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row > span {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n gap: 6px 12px;\n margin: 0;\n font-size: 12.5px;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n/* ---------- tasks panel ---------- */\n\n.mailharbor .chip {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n.tasks-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 18px;\n padding: 18px 20px 48px;\n width: 100%;\n max-width: 940px;\n margin: 0 auto;\n}\n\n.tasks-overview {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));\n gap: 12px;\n}\n\n.tasks-progress,\n.tasks-project {\n display: flex;\n flex-direction: column;\n gap: 7px;\n padding: 12px 14px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n}\n\n.tasks-progress-head,\n.tasks-project-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n}\n\n.tasks-project-head .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12.5px;\n font-weight: 500;\n}\n\n.tasks-bar {\n height: 6px;\n border-radius: 999px;\n background: var(--m-bg-3);\n overflow: hidden;\n}\n\n.tasks-bar span {\n display: block;\n height: 100%;\n border-radius: 999px;\n background: var(--m-accent);\n transition: width 200ms ease;\n}\n\n.tasks-bar.small {\n height: 4px;\n}\n\n.tasks-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.tasks-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.tasks-row {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.tasks-row input[type='checkbox'] {\n width: 16px;\n height: 16px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.tasks-row .tasks-title {\n flex: 1;\n min-width: 0;\n height: auto;\n padding: 0;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n text-align: left;\n border: 0;\n background: transparent;\n}\n\n.tasks-row .tasks-title:hover {\n background: transparent;\n}\n\n.tasks-row .tasks-title > span:first-child {\n font-size: 13px;\n color: var(--m-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n}\n\n.tasks-row.done .tasks-title > span:first-child {\n color: var(--m-text-3);\n text-decoration: line-through;\n}\n\n.tasks-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-meta .due.overdue {\n color: var(--m-danger);\n}\n\n.tasks-list-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* ---------- markdown ---------- */\n\n.mailharbor-markdown {\n display: flex;\n flex-direction: column;\n gap: 8px;\n font-size: 12.5px;\n line-height: 1.68;\n overflow-wrap: anywhere;\n}\n\n.mailharbor-markdown > *:first-child {\n margin-top: 0;\n}\n\n.mailharbor-markdown > *:last-child {\n margin-bottom: 0;\n}\n\n.mailharbor-markdown p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.mailharbor-markdown h1,\n.mailharbor-markdown h2,\n.mailharbor-markdown h3,\n.mailharbor-markdown h4,\n.mailharbor-markdown h5,\n.mailharbor-markdown h6 {\n margin: 4px 0 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.mailharbor-markdown ul,\n.mailharbor-markdown ol {\n margin: 0;\n padding-left: 20px;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.mailharbor-markdown li::marker {\n color: var(--m-text-3);\n}\n\n.mailharbor-markdown a {\n color: var(--m-accent);\n text-decoration: none;\n}\n\n.mailharbor-markdown a:hover {\n text-decoration: underline;\n}\n\n.mailharbor-markdown code {\n padding: 1px 4px;\n border-radius: 4px;\n background: var(--m-bg-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11.5px;\n}\n\n.mailharbor-markdown pre {\n margin: 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n overflow: auto;\n}\n\n.mailharbor-markdown pre code {\n padding: 0;\n background: transparent;\n}\n\n.mailharbor-markdown blockquote {\n margin: 0;\n padding-left: 10px;\n border-left: 2px solid var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor-markdown hr {\n width: 100%;\n margin: 4px 0;\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n}\n\n/* ---------- composer AI ---------- */\n\n.mailharbor-toolbar button.ai {\n color: var(--m-accent);\n}\n\n.mailharbor-compose-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n flex-wrap: wrap;\n}\n\n.mailharbor-versions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n padding-top: 8px;\n}\n\n.mailharbor-versions .chip {\n height: 22px;\n padding: 0 8px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 11px;\n}\n\n.mailharbor-versions .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n/* ---------- settings ---------- */\n\n.mailharbor.mailharbor-settings-page {\n height: auto;\n min-height: 100%;\n overflow: visible;\n}\n\n.mailharbor-settings {\n flex: 0 0 auto;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding: 18px 20px 48px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n overflow-x: hidden;\n}\n\n.mailharbor-settings > * {\n min-width: 0;\n}\n\n.mailharbor-settings h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n.mailharbor-settings h3 {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n overflow: hidden;\n}\n\n.mailharbor-account-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.mailharbor-account-row .meta {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.mailharbor-account-row .meta strong {\n font-weight: 600;\n}\n\n.mailharbor-account-row .meta span {\n color: var(--m-text-3);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor .avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n border-radius: 50%;\n background: var(--m-accent-soft);\n color: var(--m-accent);\n font-weight: 600;\n}\n\n.mailharbor-log {\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n color: var(--m-text-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.6;\n max-height: 220px;\n overflow: auto;\n white-space: pre-wrap;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: minmax(120px, 170px) 1fr;\n gap: 6px 14px;\n font-size: 12px;\n margin: 0;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n color: var(--m-text-2);\n word-break: break-all;\n}\n\n.mailharbor hr {\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n margin: 2px 0;\n}\n\n/* ---------- mailbox sidebar ---------- */\n\n.mailharbor-side {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 214px;\n flex: none;\n padding: 10px 8px;\n overflow: auto;\n border-right: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-side-section {\n padding: 12px 8px 4px;\n font-size: 10.5px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 32px;\n padding: 0 8px;\n border-radius: 8px;\n color: var(--m-text-2);\n font-size: 12.5px;\n text-align: left;\n flex: none;\n}\n\n.mailharbor-side-item:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-side-item.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-side-item .name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-side-item .sub {\n display: block;\n font-size: 10.5px;\n color: var(--m-text-3);\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor-side-item .count {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item svg {\n flex: none;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item.active svg {\n color: var(--m-accent);\n}\n\n@media (max-width: 900px) {\n .mailharbor-side {\n display: none;\n }\n}\n\n/* ---------- task board ---------- */\n\n.tasks-board-wrap {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 16px 18px 40px;\n}\n\n.tasks-summary {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.tasks-summary-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 7px;\n}\n\n.tasks-summary-labels {\n display: flex;\n align-items: baseline;\n gap: 10px;\n}\n\n.tasks-stats {\n display: flex;\n gap: 18px;\n}\n\n.tasks-stat {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 42px;\n}\n\n.tasks-stat strong {\n font-size: 16px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.tasks-stat span {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-stat.danger strong {\n color: var(--m-danger);\n}\n\n.tasks-toolbar {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.tasks-board {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 14px;\n align-items: start;\n}\n\n.task-column {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 140px;\n padding: 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.task-column-head {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 2px 4px 6px;\n}\n\n.task-column-head strong {\n font-size: 12.5px;\n font-weight: 600;\n}\n\n.task-column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-dot {\n width: 7px;\n height: 7px;\n border-radius: 999px;\n background: var(--m-text-3);\n}\n\n.task-dot.NEEDS-ACTION {\n background: #8a8f98;\n}\n\n.task-dot.IN-PROCESS {\n background: var(--m-accent);\n}\n\n.task-dot.COMPLETED {\n background: var(--m-ok);\n}\n\n.task-column-body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 60px;\n}\n\n.task-column-empty {\n padding: 18px 8px;\n text-align: center;\n color: var(--m-text-3);\n font-size: 11.5px;\n border: 1px dashed var(--m-line-soft);\n border-radius: 9px;\n}\n\n.task-card {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 11px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg);\n cursor: grab;\n transition:\n border-color 120ms ease,\n box-shadow 120ms ease;\n}\n\n.task-card:hover {\n border-color: var(--m-line);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);\n}\n\n.task-card.dragging {\n opacity: 0.5;\n}\n\n.task-card-top {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n}\n\n.task-card-title {\n flex: 1;\n min-width: 0;\n font-size: 12.5px;\n line-height: 1.45;\n color: var(--m-text);\n overflow-wrap: anywhere;\n}\n\n.task-priority {\n width: 3px;\n height: 14px;\n margin-top: 2px;\n border-radius: 999px;\n background: transparent;\n flex: none;\n}\n\n.task-priority.p5 {\n background: #d9a441;\n}\n\n.task-priority.p9 {\n background: var(--m-danger);\n}\n\n.task-card-delete {\n width: 18px;\n height: 18px;\n flex: none;\n border-radius: 5px;\n color: var(--m-text-3);\n opacity: 0;\n}\n\n.task-card:hover .task-card-delete {\n opacity: 1;\n}\n\n.task-card-notes {\n margin: 0;\n font-size: 11.5px;\n line-height: 1.55;\n color: var(--m-text-3);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.task-card-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 10.5px;\n color: var(--m-text-3);\n}\n\n.task-due,\n.task-owner,\n.task-project,\n.task-priority-label {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 6px;\n border-radius: 5px;\n background: var(--m-bg-2);\n}\n\n.task-due.overdue {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-project {\n color: var(--m-accent);\n background: var(--m-accent-soft);\n}\n\n.task-source {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 22px;\n padding: 0 6px;\n border-radius: 5px;\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-source:hover {\n background: var(--m-hover);\n color: var(--m-text-2);\n}\n\n/* ---------- task editor ---------- */\n\n.mailharbor-tasks .mailharbor-modal {\n max-width: 760px;\n}\n\n.task-editor {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 230px;\n gap: 18px;\n}\n\n.task-editor-main {\n display: flex;\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n}\n\n.task-editor-title input {\n width: 100%;\n height: 38px;\n font-size: 15px;\n font-weight: 500;\n}\n\n.task-editor-section {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.task-editor-section label,\n.task-editor-field label {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.task-editor-section textarea {\n width: 100%;\n resize: vertical;\n}\n\n.task-editor-side {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-editor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.task-editor-field input,\n.task-editor-field select {\n width: 100%;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 26px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.task-priority-picker button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.task-editor-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n}\n";
|
|
38
|
+
var styles_default = "/* MailHarbor panel + settings.\n Tokens come from the DSH shell (dark by default); fallbacks match the\n default dark theme so the panel also renders in a bare host page.\n Component rules are all scoped under `.mailharbor` and the generic element\n reset lives in `:where()` so it cannot outrank a component class. */\n\n.mailharbor {\n --m-bg: var(--dsw-alias-bg-base, #151517);\n --m-bg-1: var(--dsw-alias-bg-layer-1, #232324);\n --m-bg-2: var(--dsw-alias-bg-layer-2, #2c2c2e);\n --m-bg-3: var(--dsw-alias-bg-layer-3, #353638);\n --m-line: var(--dsw-alias-border-l2, #ffffff1f);\n --m-line-soft: var(--dsw-alias-border-l1, #ffffff0f);\n --m-line-strong: var(--dsw-alias-border-l3, #ffffff29);\n --m-text: var(--dsw-alias-label-primary, #f9fafb);\n --m-text-2: var(--dsw-alias-label-secondary, #cfd3d6);\n --m-text-3: var(--dsw-alias-label-tertiary, #adb2b8);\n --m-caption: var(--dsw-alias-label-caption, #81858c);\n --m-accent: #5686fe;\n --m-accent-soft: rgba(86, 134, 254, 0.14);\n --m-primary-bg: var(--dsw-alias-brand-primary, #f9fafb);\n --m-primary-fg: var(--dsw-alias-label-primary-foreground, #0f1115);\n --m-hover: var(--dsw-alias-interactive-bg-hover, #ffffff14);\n --m-danger: #f25a5a;\n --m-ok: #3fbf7f;\n --m-warn: var(--dsw-alias-state-warn-label, #dd8629);\n --m-radius: 8px;\n --m-shadow: 0 18px 60px rgba(0, 0, 0, 0.5);\n\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--m-bg);\n color: var(--m-text);\n font-size: 13px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\n\n.mailharbor *,\n.mailharbor *::before,\n.mailharbor *::after {\n box-sizing: border-box;\n}\n\n/* ---------- base controls ---------- */\n\n.mailharbor :where(button) {\n font: inherit;\n color: inherit;\n background: transparent;\n border: 0;\n margin: 0;\n cursor: pointer;\n}\n\n.mailharbor button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 30px;\n padding: 0 12px;\n border-radius: var(--m-radius);\n border: 1px solid transparent;\n color: var(--m-text-2);\n font-size: 12.5px;\n font-weight: 500;\n white-space: nowrap;\n transition:\n background 120ms ease,\n color 120ms ease,\n border-color 120ms ease;\n}\n\n.mailharbor button:hover:not(:disabled) {\n background: var(--m-hover);\n color: var(--m-text);\n}\n\n.mailharbor button:disabled {\n opacity: 0.45;\n cursor: default;\n}\n\n.mailharbor button.primary {\n background: var(--m-primary-bg);\n color: var(--m-primary-fg);\n border-color: transparent;\n}\n\n.mailharbor button.primary:hover:not(:disabled) {\n background: var(--m-primary-bg);\n filter: brightness(0.94);\n color: var(--m-primary-fg);\n}\n\n.mailharbor button.ghost {\n border-color: var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor button.ghost:hover:not(:disabled) {\n border-color: var(--m-line-strong);\n color: var(--m-text);\n}\n\n.mailharbor button.subtle {\n color: var(--m-text-3);\n padding: 0 8px;\n}\n\n.mailharbor button.icon {\n width: 30px;\n padding: 0;\n}\n\n.mailharbor button.danger {\n color: var(--m-danger);\n}\n\n.mailharbor input,\n.mailharbor select,\n.mailharbor textarea {\n font: inherit;\n color: var(--m-text);\n background: var(--m-bg-1);\n border: 1px solid var(--m-line);\n border-radius: var(--m-radius);\n padding: 0 10px;\n height: 32px;\n min-width: 0;\n}\n\n.mailharbor textarea {\n height: auto;\n padding: 8px 10px;\n resize: vertical;\n line-height: 1.6;\n}\n\n.mailharbor select {\n padding-right: 26px;\n appearance: none;\n background-image:\n linear-gradient(45deg, transparent 50%, var(--m-text-3) 50%),\n linear-gradient(135deg, var(--m-text-3) 50%, transparent 50%);\n background-position:\n calc(100% - 15px) 14px,\n calc(100% - 10px) 14px;\n background-size:\n 5px 5px,\n 5px 5px;\n background-repeat: no-repeat;\n}\n\n.mailharbor ::placeholder {\n color: var(--m-caption);\n}\n\n.mailharbor input:focus-visible,\n.mailharbor select:focus-visible,\n.mailharbor textarea:focus-visible,\n.mailharbor button:focus-visible,\n.mailharbor [contenteditable='true']:focus-visible {\n outline: 2px solid rgba(86, 134, 254, 0.55);\n outline-offset: -1px;\n}\n\n.mailharbor .spacer {\n flex: 1;\n}\n\n.mailharbor .muted {\n color: var(--m-text-3);\n}\n\n.mailharbor .small {\n font-size: 12px;\n}\n\n.mailharbor .badge {\n display: inline-flex;\n align-items: center;\n height: 18px;\n padding: 0 6px;\n border-radius: 999px;\n font-size: 10.5px;\n font-weight: 500;\n background: var(--m-bg-3);\n color: var(--m-text-2);\n}\n\n.mailharbor .badge.ok {\n background: rgba(63, 191, 127, 0.16);\n color: var(--m-ok);\n}\n\n.mailharbor .badge.warn {\n background: rgba(221, 134, 41, 0.16);\n color: var(--m-warn);\n}\n\n.mailharbor .error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.1);\n border-bottom: 1px solid rgba(242, 90, 90, 0.2);\n font-size: 12.5px;\n}\n\n/* ---------- shell ---------- */\n\n.mailharbor-topbar {\n display: flex;\n align-items: center;\n gap: 10px;\n height: 52px;\n padding: 0 14px;\n border-bottom: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n flex: none;\n}\n\n.mailharbor-account {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n max-width: 220px;\n padding: 4px 8px 4px 4px;\n border-radius: 999px;\n border: 1px solid transparent;\n cursor: default;\n}\n\n.mailharbor-account:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-account .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.mailharbor-account select {\n height: 26px;\n background: transparent;\n border-color: transparent;\n font-weight: 500;\n}\n\n.mailharbor-body {\n display: flex;\n flex: 1;\n min-height: 0;\n position: relative;\n}\n\n.mailharbor button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-list {\n display: flex;\n flex-direction: column;\n width: 360px;\n flex: none;\n border-right: 1px solid var(--m-line-soft);\n min-height: 0;\n}\n\n.mailharbor-reader {\n flex: 1;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n@media (max-width: 1000px) {\n .mailharbor-list {\n width: 300px;\n }\n}\n\n.mailharbor-narrow .mailharbor-body[data-mode='reader'] .mailharbor-list {\n display: none;\n}\n\n.mailharbor-narrow .mailharbor-body[data-mode='list'] .mailharbor-reader {\n display: none;\n}\n\n/* ---------- segmented control ---------- */\n\n.mailharbor-segment {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n border-radius: 9px;\n background: var(--m-bg-2);\n}\n\n.mailharbor-segment button {\n height: 26px;\n padding: 0 12px;\n border-radius: 7px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor-segment button:hover:not(.active) {\n color: var(--m-text-2);\n background: transparent;\n}\n\n.mailharbor-segment button.active {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n/* ---------- list ---------- */\n\n.mailharbor-filters {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-filters select {\n width: 128px;\n flex: none;\n font-size: 12px;\n}\n\n.mailharbor-filters input[type='search'] {\n flex: 1;\n height: 30px;\n font-size: 12.5px;\n}\n\n.mailharbor-rows {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n.mailharbor-row {\n display: flex;\n flex-direction: column;\n gap: 3px;\n width: 100%;\n padding: 10px 14px;\n border: 0;\n border-bottom: 1px solid var(--m-line-soft);\n border-left: 2px solid transparent;\n border-radius: 0;\n background: transparent;\n color: inherit;\n text-align: left;\n cursor: pointer;\n user-select: none;\n}\n\n.mailharbor-row:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-row.selected {\n background: var(--m-accent-soft);\n border-left-color: var(--m-accent);\n}\n\n.mailharbor-row .line-1,\n.mailharbor-row .line-2 {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n width: 100%;\n}\n\n.mailharbor-row .from {\n font-weight: 600;\n font-size: 12.5px;\n color: var(--m-text-2);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-row .date {\n margin-left: auto;\n color: var(--m-caption);\n font-size: 11px;\n flex: none;\n}\n\n.mailharbor-row .subject {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n.mailharbor-row .snippet {\n color: var(--m-caption);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n width: 100%;\n}\n\n.mailharbor-row.unread .from,\n.mailharbor-row.unread .subject {\n color: var(--m-text);\n}\n\n.mailharbor-row .dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--m-accent);\n flex: none;\n}\n\n.mailharbor-row .paperclip {\n color: var(--m-caption);\n flex: none;\n display: inline-flex;\n}\n\n.mailharbor-list-foot {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-top: 1px solid var(--m-line-soft);\n color: var(--m-text-3);\n font-size: 11.5px;\n flex: none;\n}\n\n.mailharbor-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 48px 24px;\n color: var(--m-text-3);\n text-align: center;\n}\n\n.mailharbor-empty svg {\n opacity: 0.5;\n}\n\n.mailharbor-empty .title {\n color: var(--m-text-2);\n font-size: 13px;\n font-weight: 500;\n}\n\n/* ---------- reader ---------- */\n\n.mailharbor-reader-head {\n padding: 16px 20px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.mailharbor-reader-title {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n\n.mailharbor-reader-title h2 {\n margin: 0;\n font-size: 17px;\n line-height: 1.35;\n font-weight: 600;\n letter-spacing: -0.01em;\n word-break: break-word;\n}\n\n.mailharbor-reader-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 10px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor-reader-meta .who {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n color: var(--m-text-2);\n}\n\n.mailharbor-reader-meta .who strong {\n color: var(--m-text);\n font-weight: 600;\n}\n\n.mailharbor-reader-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.mailharbor-reader-body {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n padding: 14px 18px 18px;\n background: var(--m-bg-2);\n}\n\n.mailharbor-reader-body iframe {\n flex: 1;\n width: 100%;\n border: 0;\n border-radius: 10px;\n background: #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n}\n\n.mailharbor-reader-body pre {\n flex: 1;\n overflow: auto;\n margin: 0;\n padding: 20px 22px;\n white-space: pre-wrap;\n word-break: break-word;\n background: #fff;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n color: #171a21;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12.5px;\n line-height: 1.7;\n}\n\n.mailharbor-attachments {\n padding: 10px 18px;\n border-top: 1px solid var(--m-line-soft);\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n flex: none;\n background: var(--m-bg);\n}\n\n.mailharbor-attachment {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 30px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: var(--m-radius);\n font-size: 12px;\n text-decoration: none;\n color: var(--m-text-2);\n max-width: 260px;\n background: var(--m-bg-1);\n}\n\n.mailharbor-attachment:hover {\n border-color: var(--m-line-strong);\n color: var(--m-text);\n}\n\n.mailharbor-attachment .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---------- AI rail ---------- */\n\n.mailharbor-ai {\n display: flex;\n flex-direction: column;\n width: 340px;\n flex: none;\n min-height: 0;\n border-left: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-ai-head {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 46px;\n padding: 0 8px 0 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-head strong {\n font-size: 13px;\n font-weight: 600;\n}\n\n.mailharbor-ai-confirm {\n display: inline-flex;\n gap: 2px;\n}\n\n.mailharbor-ai-context {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 9px 14px 10px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-context strong {\n font-size: 12.5px;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-ai-warn {\n padding: 8px 14px;\n color: var(--m-warn);\n background: rgba(221, 134, 41, 0.1);\n font-size: 12px;\n flex: none;\n}\n\n.mailharbor-ai-quick {\n display: flex;\n gap: 6px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-quick button {\n flex: 1;\n padding: 0 6px;\n}\n\n.mailharbor-ai-list {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n}\n\n.mailharbor-ai-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 30px 12px;\n text-align: center;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-empty .title {\n color: var(--m-text-2);\n font-weight: 500;\n font-size: 12.5px;\n}\n\n.mailharbor-ai-card {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n overflow: hidden;\n}\n\n.mailharbor-ai-card.generating {\n opacity: 0.7;\n}\n\n.mailharbor-ai-card-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 7px 8px 7px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-card-head > span:first-child {\n color: var(--m-text-2);\n font-weight: 600;\n}\n\n.mailharbor-ai-summary {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 10px 12px;\n}\n\n.mailharbor-ai-summary section h4 {\n margin: 0 0 3px;\n font-size: 11px;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mailharbor-ai-summary section p {\n margin: 0;\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-text {\n padding: 10px 12px;\n max-height: 320px;\n overflow: auto;\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-card-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n padding: 6px 8px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-ai-card-actions button {\n height: 26px;\n padding: 0 8px;\n font-size: 11.5px;\n}\n\n.mailharbor-ai-ask {\n display: flex;\n gap: 6px;\n padding: 10px 12px;\n border-top: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-ask input {\n flex: 1;\n height: 32px;\n}\n\n.mailharbor-ai-error {\n color: var(--m-danger);\n font-size: 12px;\n padding: 0 2px;\n}\n\n@media (max-width: 1280px) {\n .mailharbor-ai {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(420px, 94%);\n z-index: 6;\n border-left: 1px solid var(--m-line);\n box-shadow: -12px 0 40px rgba(0, 0, 0, 0.45);\n }\n}\n\n/* ---------- AI summary ---------- */\n\n.mailharbor-divider {\n width: 1px;\n height: 18px;\n margin: 0 4px;\n background: var(--m-line);\n}\n\n.mailharbor-summary {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.mailharbor-summary section h4 {\n margin: 0 0 6px;\n font-size: 11.5px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-summary section p {\n margin: 0;\n white-space: pre-wrap;\n line-height: 1.75;\n color: var(--m-text);\n}\n\n/* ---------- modal / forms ---------- */\n\n.mailharbor-portal {\n position: fixed;\n inset: 0;\n z-index: 80;\n height: auto;\n background: transparent;\n pointer-events: none;\n}\n\n.mailharbor-portal .mailharbor-modal-mask {\n pointer-events: auto;\n}\n\n.mailharbor-modal-mask {\n position: fixed;\n inset: 0;\n z-index: 60;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(2px);\n}\n\n.mailharbor-modal {\n display: flex;\n flex-direction: column;\n width: min(720px, 100%);\n max-height: 86vh;\n overflow: hidden;\n border: 1px solid var(--m-line);\n border-radius: 14px;\n background: var(--m-bg-1);\n color: var(--m-text);\n box-shadow: var(--m-shadow);\n}\n\n.mailharbor-modal > header {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 52px;\n padding: 0 14px 0 18px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 14px;\n font-weight: 600;\n}\n\n.mailharbor-modal .content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 18px;\n overflow: auto;\n}\n\n.mailharbor-modal > footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 18px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.mailharbor-field > input,\n.mailharbor-field > select,\n.mailharbor-field > textarea,\n.mailharbor-card > textarea {\n width: 100%;\n min-width: 0;\n}\n\n.mailharbor-field > label {\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-grid {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 10px;\n min-width: 0;\n}\n\n.mailharbor-grid.three {\n grid-template-columns: minmax(0, 2fr) minmax(72px, 90px) auto;\n align-items: end;\n min-width: 0;\n}\n\n.mailharbor-toggle {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n color: var(--m-text-2);\n font-size: 12.5px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.mailharbor-toggle input[type='checkbox'] {\n width: 14px;\n height: 14px;\n accent-color: var(--m-accent);\n}\n\n/* ---------- composer ---------- */\n\n.mailharbor-toolbar {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-wrap: wrap;\n padding: 6px;\n border: 1px solid var(--m-line-soft);\n border-bottom: 0;\n border-radius: 10px 10px 0 0;\n background: var(--m-bg-2);\n}\n\n.mailharbor-toolbar button {\n height: 26px;\n padding: 0 9px;\n border-radius: 6px;\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-toolbar button:hover {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n.mailharbor-editor {\n min-height: 240px;\n max-height: 44vh;\n overflow: auto;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 0 0 10px 10px;\n background: #fff;\n color: #171a21;\n outline: none;\n font-size: 13.5px;\n line-height: 1.7;\n}\n\n.mailharbor-editor:empty::before {\n content: attr(data-placeholder);\n color: #9aa0ab;\n}\n\n/* ---------- inline confirm ---------- */\n\n.mailharbor-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--m-line);\n background: var(--m-bg-2);\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n/* ---------- selection / extraction ---------- */\n\n.mailharbor-selectbar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n margin: 0 12px 8px;\n border: 1px solid var(--m-accent-soft);\n border-radius: 9px;\n background: var(--m-accent-soft);\n}\n\n.mailharbor-selectbar select {\n height: 28px;\n max-width: 200px;\n}\n\n.mailharbor-row.selectable input[type='checkbox'] {\n width: 15px;\n height: 15px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 9px 10px;\n border: 1px solid var(--m-line-soft);\n border-radius: 9px;\n background: var(--m-bg-1);\n cursor: pointer;\n}\n\n.mailharbor-extract-row input {\n margin-top: 2px;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row > span {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n gap: 6px 12px;\n margin: 0;\n font-size: 12.5px;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n/* ---------- tasks panel ---------- */\n\n.mailharbor .chip {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n.tasks-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 18px;\n padding: 18px 20px 48px;\n width: 100%;\n max-width: 940px;\n margin: 0 auto;\n}\n\n.tasks-overview {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));\n gap: 12px;\n}\n\n.tasks-progress,\n.tasks-project {\n display: flex;\n flex-direction: column;\n gap: 7px;\n padding: 12px 14px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n}\n\n.tasks-progress-head,\n.tasks-project-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n}\n\n.tasks-project-head .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12.5px;\n font-weight: 500;\n}\n\n.tasks-bar {\n height: 6px;\n border-radius: 999px;\n background: var(--m-bg-3);\n overflow: hidden;\n}\n\n.tasks-bar span {\n display: block;\n height: 100%;\n border-radius: 999px;\n background: var(--m-accent);\n transition: width 200ms ease;\n}\n\n.tasks-bar.small {\n height: 4px;\n}\n\n.tasks-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.tasks-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.tasks-row {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.tasks-row input[type='checkbox'] {\n width: 16px;\n height: 16px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.tasks-row .tasks-title {\n flex: 1;\n min-width: 0;\n height: auto;\n padding: 0;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n text-align: left;\n border: 0;\n background: transparent;\n}\n\n.tasks-row .tasks-title:hover {\n background: transparent;\n}\n\n.tasks-row .tasks-title > span:first-child {\n font-size: 13px;\n color: var(--m-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n}\n\n.tasks-row.done .tasks-title > span:first-child {\n color: var(--m-text-3);\n text-decoration: line-through;\n}\n\n.tasks-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-meta .due.overdue {\n color: var(--m-danger);\n}\n\n.tasks-list-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* ---------- markdown ---------- */\n\n.mailharbor-markdown {\n display: flex;\n flex-direction: column;\n gap: 8px;\n font-size: 12.5px;\n line-height: 1.68;\n overflow-wrap: anywhere;\n}\n\n.mailharbor-markdown > *:first-child {\n margin-top: 0;\n}\n\n.mailharbor-markdown > *:last-child {\n margin-bottom: 0;\n}\n\n.mailharbor-markdown p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.mailharbor-markdown h1,\n.mailharbor-markdown h2,\n.mailharbor-markdown h3,\n.mailharbor-markdown h4,\n.mailharbor-markdown h5,\n.mailharbor-markdown h6 {\n margin: 4px 0 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.mailharbor-markdown ul,\n.mailharbor-markdown ol {\n margin: 0;\n padding-left: 20px;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.mailharbor-markdown li::marker {\n color: var(--m-text-3);\n}\n\n.mailharbor-markdown a {\n color: var(--m-accent);\n text-decoration: none;\n}\n\n.mailharbor-markdown a:hover {\n text-decoration: underline;\n}\n\n.mailharbor-markdown code {\n padding: 1px 4px;\n border-radius: 4px;\n background: var(--m-bg-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11.5px;\n}\n\n.mailharbor-markdown pre {\n margin: 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n overflow: auto;\n}\n\n.mailharbor-markdown pre code {\n padding: 0;\n background: transparent;\n}\n\n.mailharbor-markdown blockquote {\n margin: 0;\n padding-left: 10px;\n border-left: 2px solid var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor-markdown hr {\n width: 100%;\n margin: 4px 0;\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n}\n\n/* ---------- composer AI ---------- */\n\n.mailharbor-toolbar button.ai {\n color: var(--m-accent);\n}\n\n.mailharbor-compose-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n flex-wrap: wrap;\n}\n\n.mailharbor-versions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n padding-top: 8px;\n}\n\n.mailharbor-versions .chip {\n height: 22px;\n padding: 0 8px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 11px;\n}\n\n.mailharbor-versions .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n/* ---------- settings ---------- */\n\n.mailharbor.mailharbor-settings-page {\n height: auto;\n min-height: 100%;\n overflow: visible;\n}\n\n.mailharbor-settings {\n flex: 0 0 auto;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding: 18px 20px 48px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n overflow-x: hidden;\n}\n\n.mailharbor-settings > * {\n min-width: 0;\n}\n\n.mailharbor-settings h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n.mailharbor-settings h3 {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n overflow: hidden;\n}\n\n.mailharbor-account-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.mailharbor-account-row .meta {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.mailharbor-account-row .meta strong {\n font-weight: 600;\n}\n\n.mailharbor-account-row .meta span {\n color: var(--m-text-3);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor .avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n border-radius: 50%;\n background: var(--m-accent-soft);\n color: var(--m-accent);\n font-weight: 600;\n}\n\n.mailharbor-log {\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n color: var(--m-text-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.6;\n max-height: 220px;\n overflow: auto;\n white-space: pre-wrap;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: minmax(120px, 170px) 1fr;\n gap: 6px 14px;\n font-size: 12px;\n margin: 0;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n color: var(--m-text-2);\n word-break: break-all;\n}\n\n.mailharbor hr {\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n margin: 2px 0;\n}\n\n/* ---------- conversation rows ---------- */\n\n.mailharbor-thread {\n display: flex;\n flex-direction: column;\n}\n\n.mailharbor-row.compact {\n padding-top: 6px;\n padding-bottom: 6px;\n padding-left: 34px;\n background: var(--m-bg);\n}\n\n.mailharbor-row.compact .line-1 {\n opacity: 0.85;\n}\n\n.mailharbor-row.compact .snippet {\n -webkit-line-clamp: 1;\n}\n\n.mailharbor .to-label {\n font-size: 10.5px;\n color: var(--m-text-3);\n flex: none;\n}\n\n.mailharbor .thread-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-2);\n font-size: 10.5px;\n flex: none;\n}\n\n.mailharbor .thread-count:hover {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-account {\n height: auto;\n padding: 3px 8px 3px 3px;\n border-radius: 8px;\n gap: 8px;\n}\n\n.mailharbor-account:hover {\n background: var(--m-hover);\n}\n\n/* ---------- mailbox sidebar ---------- */\n\n.mailharbor-side {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 214px;\n flex: none;\n padding: 10px 8px;\n overflow: auto;\n border-right: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-side-section {\n padding: 12px 8px 4px;\n font-size: 10.5px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 32px;\n padding: 0 8px;\n border-radius: 8px;\n color: var(--m-text-2);\n font-size: 12.5px;\n text-align: left;\n flex: none;\n}\n\n.mailharbor-side-item:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-side-item.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-side-item .name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-side-item .sub {\n display: block;\n font-size: 10.5px;\n color: var(--m-text-3);\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor-side-item .count {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item svg {\n flex: none;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item.active svg {\n color: var(--m-accent);\n}\n\n@media (max-width: 900px) {\n .mailharbor-side {\n display: none;\n }\n}\n\n/* ---------- task board ---------- */\n\n.tasks-board-wrap {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 16px 18px 40px;\n}\n\n.tasks-summary {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.tasks-summary-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 7px;\n}\n\n.tasks-summary-labels {\n display: flex;\n align-items: baseline;\n gap: 10px;\n}\n\n.tasks-stats {\n display: flex;\n gap: 18px;\n}\n\n.tasks-stat {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 42px;\n}\n\n.tasks-stat strong {\n font-size: 16px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.tasks-stat span {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-stat.danger strong {\n color: var(--m-danger);\n}\n\n.tasks-toolbar {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.tasks-board {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 14px;\n align-items: start;\n}\n\n.task-column {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 140px;\n padding: 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.task-column-head {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 2px 4px 6px;\n}\n\n.task-column-head strong {\n font-size: 12.5px;\n font-weight: 600;\n}\n\n.task-column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-dot {\n width: 7px;\n height: 7px;\n border-radius: 999px;\n background: var(--m-text-3);\n}\n\n.task-dot.NEEDS-ACTION {\n background: #8a8f98;\n}\n\n.task-dot.IN-PROCESS {\n background: var(--m-accent);\n}\n\n.task-dot.COMPLETED {\n background: var(--m-ok);\n}\n\n.task-dot.CANCELLED {\n background: var(--m-danger);\n opacity: 0.7;\n}\n\n.task-column-body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 60px;\n}\n\n.task-column-empty {\n padding: 18px 8px;\n text-align: center;\n color: var(--m-text-3);\n font-size: 11.5px;\n border: 1px dashed var(--m-line-soft);\n border-radius: 9px;\n}\n\n.task-card {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 11px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg);\n cursor: grab;\n transition:\n border-color 120ms ease,\n box-shadow 120ms ease;\n}\n\n.task-card:hover {\n border-color: var(--m-line);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);\n}\n\n.task-card.dragging {\n opacity: 0.5;\n}\n\n.task-card-top {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n}\n\n.task-card-title {\n flex: 1;\n min-width: 0;\n font-size: 12.5px;\n line-height: 1.45;\n color: var(--m-text);\n overflow-wrap: anywhere;\n}\n\n.task-priority {\n width: 3px;\n height: 14px;\n margin-top: 2px;\n border-radius: 999px;\n background: transparent;\n flex: none;\n}\n\n.task-priority.p5 {\n background: #d9a441;\n}\n\n.task-priority.p9 {\n background: var(--m-danger);\n}\n\n.task-card-delete {\n width: 18px;\n height: 18px;\n flex: none;\n border-radius: 5px;\n color: var(--m-text-3);\n opacity: 0;\n}\n\n.task-card:hover .task-card-delete {\n opacity: 1;\n}\n\n.task-card-notes {\n margin: 0;\n font-size: 11.5px;\n line-height: 1.55;\n color: var(--m-text-3);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.task-card-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 10.5px;\n color: var(--m-text-3);\n}\n\n.task-due,\n.task-owner,\n.task-project,\n.task-priority-label {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 6px;\n border-radius: 5px;\n background: var(--m-bg-2);\n}\n\n.task-due.overdue {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-project {\n color: var(--m-accent);\n background: var(--m-accent-soft);\n}\n\n.task-source {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 22px;\n padding: 0 6px;\n border-radius: 5px;\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-source:hover {\n background: var(--m-hover);\n color: var(--m-text-2);\n}\n\n@media (max-width: 1180px) {\n .tasks-board {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n\n@media (max-width: 720px) {\n .tasks-board {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* ---------- AI search ---------- */\n\n.mailharbor-ai-search {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 12px 8px;\n padding: 7px 10px;\n border-radius: 8px;\n background: var(--m-accent-soft);\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-ai-search.searching {\n background: var(--m-bg-2);\n color: var(--m-text-3);\n}\n\n/* ---------- task editor ---------- */\n\n.mailharbor-tasks .mailharbor-modal {\n max-width: 760px;\n}\n\n.task-editor {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 230px;\n gap: 18px;\n}\n\n.task-editor-main {\n display: flex;\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n}\n\n.task-editor-title input {\n width: 100%;\n height: 38px;\n font-size: 15px;\n font-weight: 500;\n}\n\n.task-editor-section {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.task-editor-section label,\n.task-editor-field label {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.task-editor-section textarea {\n width: 100%;\n resize: vertical;\n}\n\n.task-editor-side {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-editor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.task-editor-field input,\n.task-editor-field select {\n width: 100%;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 26px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.task-priority-picker button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.task-editor-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n}\n";
|
|
39
39
|
|
|
40
40
|
// src/client/icon.tsx
|
|
41
41
|
var import_react = require("react");
|
|
@@ -126,6 +126,10 @@ var api = {
|
|
|
126
126
|
check: (id) => request(`accounts/${encodeURIComponent(id)}/check`, { method: "POST" }),
|
|
127
127
|
aiStatus: (accountId) => request(`ai/status${query({ accountId: accountId ?? null })}`),
|
|
128
128
|
aiModels: () => request("ai/models"),
|
|
129
|
+
aiSearch: (payload) => request("ai/search", {
|
|
130
|
+
method: "POST",
|
|
131
|
+
body: JSON.stringify(payload)
|
|
132
|
+
}),
|
|
129
133
|
aiThread: (accountId, key) => request(`ai/thread${query({ accountId: accountId ?? null, key })}`),
|
|
130
134
|
aiAddCard: (payload) => request("ai/cards", {
|
|
131
135
|
method: "POST",
|
|
@@ -182,6 +186,7 @@ var api = {
|
|
|
182
186
|
}),
|
|
183
187
|
syncTasks: (accountId) => request("tasks/sync", { method: "POST", body: JSON.stringify({ accountId }) }),
|
|
184
188
|
projects: () => request("projects"),
|
|
189
|
+
pickDirectory: () => request("projects/pick-directory", { method: "POST" }),
|
|
185
190
|
projectFor: (accountId, key) => request(`projects/for${query({ accountId: accountId ?? null, key })}`),
|
|
186
191
|
createProject: (payload) => request("projects", {
|
|
187
192
|
method: "POST",
|
|
@@ -496,6 +501,12 @@ var PATHS = {
|
|
|
496
501
|
(0, import_react3.createElement)("path", { d: "M10 11v6M14 11v6" })
|
|
497
502
|
),
|
|
498
503
|
send: (0, import_react3.createElement)("path", { d: "m4 4 17 8-17 8 3.6-8z M7.6 12H21" }),
|
|
504
|
+
list: (0, import_react3.createElement)(
|
|
505
|
+
"g",
|
|
506
|
+
null,
|
|
507
|
+
(0, import_react3.createElement)("path", { d: "M8 6h12M8 12h12M8 18h12" }),
|
|
508
|
+
(0, import_react3.createElement)("path", { d: "M4 6h.01M4 12h.01M4 18h.01" })
|
|
509
|
+
),
|
|
499
510
|
folder: (0, import_react3.createElement)("path", {
|
|
500
511
|
d: "M3.5 6.5A1.5 1.5 0 0 1 5 5h4l2 2.5h8A1.5 1.5 0 0 1 20.5 9v8.5A1.5 1.5 0 0 1 19 19H5a1.5 1.5 0 0 1-1.5-1.5z"
|
|
501
512
|
}),
|
|
@@ -1102,10 +1113,28 @@ ${card.output}`
|
|
|
1102
1113
|
"div",
|
|
1103
1114
|
{ className: "mailharbor-field" },
|
|
1104
1115
|
(0, import_react5.createElement)("label", null, "\u9879\u76EE\u76EE\u5F55\uFF08\u9ED8\u8BA4\u53EF\u5728\u8BBE\u7F6E\u91CC\u6539\uFF09"),
|
|
1105
|
-
(0, import_react5.createElement)(
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1116
|
+
(0, import_react5.createElement)(
|
|
1117
|
+
"div",
|
|
1118
|
+
{ style: { display: "flex", gap: "6px" } },
|
|
1119
|
+
(0, import_react5.createElement)("input", {
|
|
1120
|
+
value: projectRoot,
|
|
1121
|
+
onChange: (event) => setProjectRoot(event.target.value)
|
|
1122
|
+
}),
|
|
1123
|
+
(0, import_react5.createElement)(
|
|
1124
|
+
"button",
|
|
1125
|
+
{
|
|
1126
|
+
className: "ghost",
|
|
1127
|
+
title: "\u4ECE\u6587\u4EF6\u7BA1\u7406\u5668\u9009\u62E9",
|
|
1128
|
+
onClick: () => {
|
|
1129
|
+
void api.pickDirectory().then((result) => {
|
|
1130
|
+
if (result.path !== null) setProjectRoot(result.path);
|
|
1131
|
+
}).catch((caught) => setProjectWarnings([errorText(caught)]));
|
|
1132
|
+
}
|
|
1133
|
+
},
|
|
1134
|
+
(0, import_react5.createElement)(Icon, { name: "folder", size: 13 }),
|
|
1135
|
+
"\u6D4F\u89C8\u2026"
|
|
1136
|
+
)
|
|
1137
|
+
)
|
|
1109
1138
|
),
|
|
1110
1139
|
(0, import_react5.createElement)(
|
|
1111
1140
|
"p",
|
|
@@ -1905,6 +1934,7 @@ function Reader({
|
|
|
1905
1934
|
onReply,
|
|
1906
1935
|
onAiAction,
|
|
1907
1936
|
onExtractTasks,
|
|
1937
|
+
onAddToProject,
|
|
1908
1938
|
onClose
|
|
1909
1939
|
}) {
|
|
1910
1940
|
const [plain, setPlain] = (0, import_react8.useState)(false);
|
|
@@ -2013,6 +2043,12 @@ function Reader({
|
|
|
2013
2043
|
(0, import_react8.createElement)(Icon, { name: "checklist", size: 14 }),
|
|
2014
2044
|
"\u63D0\u53D6\u4EFB\u52A1"
|
|
2015
2045
|
),
|
|
2046
|
+
(0, import_react8.createElement)(
|
|
2047
|
+
"button",
|
|
2048
|
+
{ className: "ghost", onClick: onAddToProject },
|
|
2049
|
+
(0, import_react8.createElement)(Icon, { name: "folder", size: 14 }),
|
|
2050
|
+
"\u52A0\u5165\u9879\u76EE"
|
|
2051
|
+
),
|
|
2016
2052
|
(0, import_react8.createElement)("span", { className: "spacer" }),
|
|
2017
2053
|
html ? (0, import_react8.createElement)(
|
|
2018
2054
|
"button",
|
|
@@ -2102,6 +2138,27 @@ var FOLDER_LABELS = {
|
|
|
2102
2138
|
function folderName(name) {
|
|
2103
2139
|
return FOLDER_LABELS[name] ?? name;
|
|
2104
2140
|
}
|
|
2141
|
+
function isSentFolder(mailbox) {
|
|
2142
|
+
return /(^|[/.])(sent|sent items|sent mail|已发送|发件箱)/i.test(mailbox);
|
|
2143
|
+
}
|
|
2144
|
+
function normalizeSubject(subject) {
|
|
2145
|
+
return subject.replace(/^(\s*(re|fw|fwd|回复|转发)\s*[::]\s*)+/gi, "").replace(/\s+/g, " ").trim().toLowerCase();
|
|
2146
|
+
}
|
|
2147
|
+
function groupMessages(items) {
|
|
2148
|
+
const map = /* @__PURE__ */ new Map();
|
|
2149
|
+
const order = [];
|
|
2150
|
+
for (const item of items) {
|
|
2151
|
+
const key = normalizeSubject(item.subject) === "" ? `__${item.accountId}:${item.id}` : normalizeSubject(item.subject);
|
|
2152
|
+
const existing = map.get(key);
|
|
2153
|
+
if (existing === void 0) {
|
|
2154
|
+
map.set(key, [item]);
|
|
2155
|
+
order.push(key);
|
|
2156
|
+
} else {
|
|
2157
|
+
existing.push(item);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
return order.map((key) => ({ key, items: map.get(key) ?? [] }));
|
|
2161
|
+
}
|
|
2105
2162
|
function errorText5(error) {
|
|
2106
2163
|
return error instanceof ApiError || error instanceof Error ? error.message : String(error);
|
|
2107
2164
|
}
|
|
@@ -2134,11 +2191,26 @@ function MailPanel() {
|
|
|
2134
2191
|
const [narrow, setNarrow] = (0, import_react9.useState)(() => matchesNarrow());
|
|
2135
2192
|
const [railOpen, setRailOpen] = (0, import_react9.useState)(false);
|
|
2136
2193
|
const [selectMode, setSelectMode] = (0, import_react9.useState)(false);
|
|
2194
|
+
const [sideOpen, setSideOpen] = (0, import_react9.useState)(() => {
|
|
2195
|
+
try {
|
|
2196
|
+
return window.localStorage.getItem("mailharbor.side") !== "0";
|
|
2197
|
+
} catch {
|
|
2198
|
+
return true;
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
const [expandedGroups, setExpandedGroups] = (0, import_react9.useState)([]);
|
|
2137
2202
|
const [selectedKeys, setSelectedKeys] = (0, import_react9.useState)([]);
|
|
2138
2203
|
const [projectOptions, setProjectOptions] = (0, import_react9.useState)([]);
|
|
2139
2204
|
const [targetProject, setTargetProject] = (0, import_react9.useState)("");
|
|
2140
2205
|
const [extraction, setExtraction] = (0, import_react9.useState)(null);
|
|
2141
2206
|
const [extractBusy, setExtractBusy] = (0, import_react9.useState)(false);
|
|
2207
|
+
const [aiInfo, setAiInfo] = (0, import_react9.useState)(null);
|
|
2208
|
+
const [projectPicker, setProjectPicker] = (0, import_react9.useState)(null);
|
|
2209
|
+
const [pickerProjects, setPickerProjects] = (0, import_react9.useState)([]);
|
|
2210
|
+
const [pickerTarget, setPickerTarget] = (0, import_react9.useState)("");
|
|
2211
|
+
const [pickerNewName, setPickerNewName] = (0, import_react9.useState)("");
|
|
2212
|
+
const [pickerBusy, setPickerBusy] = (0, import_react9.useState)(false);
|
|
2213
|
+
const [aiSearching, setAiSearching] = (0, import_react9.useState)(false);
|
|
2142
2214
|
const [aiRequest, setAiRequest] = (0, import_react9.useState)(null);
|
|
2143
2215
|
const [tick, setTick] = (0, import_react9.useState)(0);
|
|
2144
2216
|
const accounts = state?.accounts ?? [];
|
|
@@ -2183,6 +2255,104 @@ function MailPanel() {
|
|
|
2183
2255
|
setError(errorText5(caught));
|
|
2184
2256
|
}
|
|
2185
2257
|
};
|
|
2258
|
+
const runAiSearch = async () => {
|
|
2259
|
+
const text = query2.trim();
|
|
2260
|
+
if (text === "" || accountScope === null) return;
|
|
2261
|
+
setAiSearching(true);
|
|
2262
|
+
setError("");
|
|
2263
|
+
try {
|
|
2264
|
+
const result = await Promise.race([
|
|
2265
|
+
api.aiSearch({ accountId: accountScope, source, mailbox, query: text }),
|
|
2266
|
+
new Promise((_resolve, reject) => {
|
|
2267
|
+
window.setTimeout(() => reject(new Error("AI \u641C\u7D22\u8D85\u65F6\uFF0C\u5DF2\u6539\u7528\u666E\u901A\u641C\u7D22")), 45e3);
|
|
2268
|
+
})
|
|
2269
|
+
]);
|
|
2270
|
+
setPage({ items: result.items, total: result.total, offset: 0, limit: result.limit });
|
|
2271
|
+
setDrafts([]);
|
|
2272
|
+
setAiInfo(result.ai);
|
|
2273
|
+
setSearch("");
|
|
2274
|
+
} catch (caught) {
|
|
2275
|
+
setError(errorText5(caught));
|
|
2276
|
+
setAiInfo(null);
|
|
2277
|
+
setSearch(text);
|
|
2278
|
+
} finally {
|
|
2279
|
+
setAiSearching(false);
|
|
2280
|
+
}
|
|
2281
|
+
};
|
|
2282
|
+
const openProjectPicker = () => {
|
|
2283
|
+
if (selected === null) return;
|
|
2284
|
+
const key = keyOf(selected);
|
|
2285
|
+
if (!key.startsWith("mid:") && !key.startsWith("local:")) {
|
|
2286
|
+
setError("\u8FD9\u5C01\u90AE\u4EF6\u7F3A\u5C11 Message-ID\uFF0C\u65E0\u6CD5\u5173\u8054\u5230\u9879\u76EE");
|
|
2287
|
+
return;
|
|
2288
|
+
}
|
|
2289
|
+
setProjectPicker({
|
|
2290
|
+
accountId: selected.accountId,
|
|
2291
|
+
key,
|
|
2292
|
+
subject: selected.subject,
|
|
2293
|
+
date: selected.date
|
|
2294
|
+
});
|
|
2295
|
+
setPickerNewName(selected.subject.replace(/^(re|fwd):\s*/i, "").slice(0, 80));
|
|
2296
|
+
setPickerTarget("");
|
|
2297
|
+
void api.projects().then((list) => {
|
|
2298
|
+
setPickerProjects(list.items);
|
|
2299
|
+
setPickerTarget(list.items[0]?.id ?? "");
|
|
2300
|
+
}).catch((caught) => setError(errorText5(caught)));
|
|
2301
|
+
};
|
|
2302
|
+
const saveProjectPick = async () => {
|
|
2303
|
+
if (projectPicker === null) return;
|
|
2304
|
+
setPickerBusy(true);
|
|
2305
|
+
setError("");
|
|
2306
|
+
try {
|
|
2307
|
+
if (pickerTarget !== "") {
|
|
2308
|
+
await api.addProjectMessage(pickerTarget, {
|
|
2309
|
+
accountId: projectPicker.accountId,
|
|
2310
|
+
key: projectPicker.key,
|
|
2311
|
+
subject: projectPicker.subject,
|
|
2312
|
+
date: projectPicker.date
|
|
2313
|
+
});
|
|
2314
|
+
notice("\u5DF2\u52A0\u5165\u9879\u76EE");
|
|
2315
|
+
} else {
|
|
2316
|
+
const name = pickerNewName.trim();
|
|
2317
|
+
if (name === "") throw new Error("\u5148\u9009\u62E9\u4E00\u4E2A\u9879\u76EE\uFF0C\u6216\u586B\u5199\u65B0\u9879\u76EE\u540D\u79F0");
|
|
2318
|
+
const settings = await api.settings();
|
|
2319
|
+
const created = await api.createProject({
|
|
2320
|
+
accountId: projectPicker.accountId,
|
|
2321
|
+
name,
|
|
2322
|
+
root: settings.projects.root,
|
|
2323
|
+
conversation: `\uFF08\u4ECE\u90AE\u4EF6\u52A0\u5165\uFF09
|
|
2324
|
+
|
|
2325
|
+
${projectPicker.subject}`,
|
|
2326
|
+
message: {
|
|
2327
|
+
key: projectPicker.key,
|
|
2328
|
+
subject: projectPicker.subject,
|
|
2329
|
+
date: projectPicker.date
|
|
2330
|
+
}
|
|
2331
|
+
});
|
|
2332
|
+
notice(`\u9879\u76EE\u5DF2\u521B\u5EFA\uFF1A${created.project.path}`);
|
|
2333
|
+
}
|
|
2334
|
+
setProjectPicker(null);
|
|
2335
|
+
setTick((value) => value + 1);
|
|
2336
|
+
} catch (caught) {
|
|
2337
|
+
setError(errorText5(caught));
|
|
2338
|
+
} finally {
|
|
2339
|
+
setPickerBusy(false);
|
|
2340
|
+
}
|
|
2341
|
+
};
|
|
2342
|
+
const toggleSide = () => {
|
|
2343
|
+
setSideOpen((open) => {
|
|
2344
|
+
try {
|
|
2345
|
+
window.localStorage.setItem("mailharbor.side", open ? "0" : "1");
|
|
2346
|
+
} catch {
|
|
2347
|
+
}
|
|
2348
|
+
return !open;
|
|
2349
|
+
});
|
|
2350
|
+
};
|
|
2351
|
+
const toggleGroup = (key) => {
|
|
2352
|
+
setExpandedGroups(
|
|
2353
|
+
(current) => current.includes(key) ? current.filter((entry) => entry !== key) : [...current, key]
|
|
2354
|
+
);
|
|
2355
|
+
};
|
|
2186
2356
|
const toggleSelect = (item) => {
|
|
2187
2357
|
const key = `${item.accountId}:${item.id}`;
|
|
2188
2358
|
setSelectedKeys(
|
|
@@ -2194,8 +2364,11 @@ function MailPanel() {
|
|
|
2194
2364
|
setError("\u5148\u521B\u5EFA\u4E00\u4E2A\u9879\u76EE");
|
|
2195
2365
|
return;
|
|
2196
2366
|
}
|
|
2197
|
-
const chosen = items.filter((item) => selectedKeys.includes(`${item.accountId}:${item.id}`));
|
|
2198
|
-
if (chosen.length === 0)
|
|
2367
|
+
const chosen = items.filter((item) => selectedKeys.includes(`${item.accountId}:${item.id}`)).filter((item) => item.messageId !== void 0 && item.messageId !== "");
|
|
2368
|
+
if (chosen.length === 0) {
|
|
2369
|
+
setError("\u6240\u9009\u90AE\u4EF6\u7F3A\u5C11 Message-ID\uFF0C\u65E0\u6CD5\u5173\u8054\u5230\u9879\u76EE");
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2199
2372
|
try {
|
|
2200
2373
|
for (const item of chosen) {
|
|
2201
2374
|
await api.addProjectMessage(targetProject, {
|
|
@@ -2313,11 +2486,15 @@ function MailPanel() {
|
|
|
2313
2486
|
(0, import_react9.useEffect)(() => {
|
|
2314
2487
|
setMailbox(source === "local" ? "all" : "INBOX");
|
|
2315
2488
|
setSelected(null);
|
|
2489
|
+
setAiInfo(null);
|
|
2490
|
+
setSearch("");
|
|
2316
2491
|
setLimit(state?.settings.render.listLimit ?? 40);
|
|
2317
2492
|
}, [source]);
|
|
2318
2493
|
(0, import_react9.useEffect)(() => {
|
|
2319
2494
|
if (accountScope === "all" && source === "server") setSource("local");
|
|
2320
2495
|
setSelected(null);
|
|
2496
|
+
setAiInfo(null);
|
|
2497
|
+
setSearch("");
|
|
2321
2498
|
}, [accountScope, source]);
|
|
2322
2499
|
(0, import_react9.useEffect)(() => {
|
|
2323
2500
|
if (accountScope === null) return;
|
|
@@ -2334,9 +2511,9 @@ function MailPanel() {
|
|
|
2334
2511
|
return [];
|
|
2335
2512
|
}
|
|
2336
2513
|
})
|
|
2337
|
-
).then((
|
|
2514
|
+
).then((groups2) => {
|
|
2338
2515
|
if (cancelled) return;
|
|
2339
|
-
setDrafts(
|
|
2516
|
+
setDrafts(groups2.flat().sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)));
|
|
2340
2517
|
setPage(EMPTY_PAGE);
|
|
2341
2518
|
}).finally(() => {
|
|
2342
2519
|
if (!cancelled) setLoading(false);
|
|
@@ -2589,6 +2766,65 @@ function MailPanel() {
|
|
|
2589
2766
|
const loggedIn = isAll ? accounts.some((item) => item.id === state.activeAccountId) : state.loggedIn;
|
|
2590
2767
|
const needsLogin = source === "server" && !isAll && state.loggedIn === false;
|
|
2591
2768
|
const items = page.items;
|
|
2769
|
+
const isSent = isSentFolder(mailbox);
|
|
2770
|
+
const groups = groupMessages(items);
|
|
2771
|
+
const renderMessage = (item, meta = {}) => {
|
|
2772
|
+
const sent = isSent && item.to.length > 0;
|
|
2773
|
+
const first = sent ? item.to[0] : item.from;
|
|
2774
|
+
const who = first === void 0 || first === null ? "" : first.name !== "" ? first.name : first.address;
|
|
2775
|
+
const extra = sent && item.to.length > 1 ? ` +${String(item.to.length - 1)}` : "";
|
|
2776
|
+
const isSelected = selected?.id === item.id && selected?.accountId === item.accountId;
|
|
2777
|
+
return (0, import_react9.createElement)(
|
|
2778
|
+
"div",
|
|
2779
|
+
{
|
|
2780
|
+
key: `${item.accountId}:${item.id}`,
|
|
2781
|
+
className: `mailharbor-row${item.unread ? " unread" : ""}${isSelected ? " selected" : ""}${selectMode ? " selectable" : ""}${meta.compact === true ? " compact" : ""}`,
|
|
2782
|
+
role: "button",
|
|
2783
|
+
tabIndex: 0,
|
|
2784
|
+
onClick: () => {
|
|
2785
|
+
if (selectMode) toggleSelect(item);
|
|
2786
|
+
else void openMessage(item);
|
|
2787
|
+
},
|
|
2788
|
+
onKeyDown: (event) => {
|
|
2789
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
2790
|
+
event.preventDefault();
|
|
2791
|
+
if (selectMode) toggleSelect(item);
|
|
2792
|
+
else void openMessage(item);
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
},
|
|
2796
|
+
(0, import_react9.createElement)(
|
|
2797
|
+
"span",
|
|
2798
|
+
{ className: "line-1" },
|
|
2799
|
+
selectMode ? (0, import_react9.createElement)("input", {
|
|
2800
|
+
type: "checkbox",
|
|
2801
|
+
checked: selectedKeys.includes(`${item.accountId}:${item.id}`),
|
|
2802
|
+
"aria-label": "\u9009\u62E9\u90AE\u4EF6",
|
|
2803
|
+
onClick: (event) => event.stopPropagation(),
|
|
2804
|
+
onChange: () => toggleSelect(item)
|
|
2805
|
+
}) : item.unread ? (0, import_react9.createElement)("span", { className: "dot" }) : null,
|
|
2806
|
+
sent ? (0, import_react9.createElement)("span", { className: "to-label" }, "\u6536\u4EF6\u4EBA ") : null,
|
|
2807
|
+
(0, import_react9.createElement)("span", { className: "from" }, `${who}${extra}`),
|
|
2808
|
+
item.hasAttachments ? (0, import_react9.createElement)(Icon, { name: "paperclip", size: 13 }) : null,
|
|
2809
|
+
source === "local" && item.backedUp === false ? (0, import_react9.createElement)("span", { className: "badge warn" }, "\u672A\u5907\u4EFD") : null,
|
|
2810
|
+
meta.groupCount !== void 0 && meta.groupCount > 1 ? (0, import_react9.createElement)(
|
|
2811
|
+
"button",
|
|
2812
|
+
{
|
|
2813
|
+
className: "thread-count",
|
|
2814
|
+
title: meta.expanded === true ? "\u6536\u8D77\u4F1A\u8BDD" : `\u5C55\u5F00\u4F1A\u8BDD\uFF08${String(meta.groupCount)} \u5C01\uFF09`,
|
|
2815
|
+
onClick: (event) => {
|
|
2816
|
+
event.stopPropagation();
|
|
2817
|
+
toggleGroup(meta.groupKey ?? "");
|
|
2818
|
+
}
|
|
2819
|
+
},
|
|
2820
|
+
meta.expanded === true ? "\u2212" : String(meta.groupCount)
|
|
2821
|
+
) : null,
|
|
2822
|
+
(0, import_react9.createElement)("span", { className: "date" }, shortDate(item.date))
|
|
2823
|
+
),
|
|
2824
|
+
meta.compact === true ? null : (0, import_react9.createElement)("span", { className: "line-2" }, (0, import_react9.createElement)("span", { className: "subject" }, item.subject)),
|
|
2825
|
+
item.snippet === "" ? null : (0, import_react9.createElement)("span", { className: "snippet" }, item.snippet)
|
|
2826
|
+
);
|
|
2827
|
+
};
|
|
2592
2828
|
return (0, import_react9.createElement)(
|
|
2593
2829
|
"div",
|
|
2594
2830
|
{ className: narrow ? "mailharbor mailharbor-narrow" : "mailharbor" },
|
|
@@ -2596,20 +2832,21 @@ function MailPanel() {
|
|
|
2596
2832
|
"div",
|
|
2597
2833
|
{ className: "mailharbor-topbar" },
|
|
2598
2834
|
(0, import_react9.createElement)(
|
|
2599
|
-
"
|
|
2600
|
-
{
|
|
2601
|
-
|
|
2835
|
+
"button",
|
|
2836
|
+
{
|
|
2837
|
+
className: "mailharbor-account",
|
|
2838
|
+
onClick: toggleSide,
|
|
2839
|
+
title: sideOpen ? "\u6536\u8D77\u8D26\u53F7\u4E0E\u6587\u4EF6\u5939" : "\u5C55\u5F00\u8D26\u53F7\u4E0E\u6587\u4EF6\u5939"
|
|
2840
|
+
},
|
|
2841
|
+
(0, import_react9.createElement)(Avatar, { email: currentAccount?.email ?? "?", size: 26 }),
|
|
2602
2842
|
(0, import_react9.createElement)(
|
|
2603
2843
|
"div",
|
|
2604
2844
|
{ style: { display: "flex", flexDirection: "column", minWidth: 0 } },
|
|
2605
|
-
(0, import_react9.createElement)("span", { className: "name" },
|
|
2606
|
-
(0, import_react9.createElement)(
|
|
2607
|
-
"span",
|
|
2608
|
-
{ className: "small muted" },
|
|
2609
|
-
isAll ? `${String(accounts.length)} \u4E2A\u8D26\u53F7` : currentAccount?.email ?? ""
|
|
2610
|
-
)
|
|
2845
|
+
(0, import_react9.createElement)("span", { className: "name" }, currentAccount?.label ?? ""),
|
|
2846
|
+
(0, import_react9.createElement)("span", { className: "small muted" }, currentAccount?.email ?? "")
|
|
2611
2847
|
),
|
|
2612
|
-
|
|
2848
|
+
state.loggedIn === false ? (0, import_react9.createElement)("span", { className: "badge warn" }, "\u672A\u767B\u5F55") : null,
|
|
2849
|
+
(0, import_react9.createElement)(Icon, { name: sideOpen ? "chevronLeft" : "chevronRight", size: 14 })
|
|
2613
2850
|
),
|
|
2614
2851
|
(0, import_react9.createElement)(
|
|
2615
2852
|
"div",
|
|
@@ -2637,16 +2874,6 @@ function MailPanel() {
|
|
|
2637
2874
|
)
|
|
2638
2875
|
),
|
|
2639
2876
|
(0, import_react9.createElement)("span", { className: "spacer" }),
|
|
2640
|
-
(0, import_react9.createElement)(
|
|
2641
|
-
"button",
|
|
2642
|
-
{
|
|
2643
|
-
className: "ghost icon",
|
|
2644
|
-
title: "\u6DFB\u52A0\u8D26\u53F7",
|
|
2645
|
-
"aria-label": "\u6DFB\u52A0\u8D26\u53F7",
|
|
2646
|
-
onClick: () => setShowAdd(true)
|
|
2647
|
-
},
|
|
2648
|
-
(0, import_react9.createElement)(Icon, { name: "plus" })
|
|
2649
|
-
),
|
|
2650
2877
|
(0, import_react9.createElement)(
|
|
2651
2878
|
"button",
|
|
2652
2879
|
{ className: "ghost icon", title: "\u5237\u65B0\u5217\u8868", "aria-label": "\u5237\u65B0\u5217\u8868", onClick: refresh },
|
|
@@ -2688,24 +2915,9 @@ function MailPanel() {
|
|
|
2688
2915
|
) : (0, import_react9.createElement)(
|
|
2689
2916
|
"div",
|
|
2690
2917
|
{ className: "mailharbor-body", "data-mode": narrow && selected !== null ? "reader" : "list" },
|
|
2691
|
-
(0, import_react9.createElement)(
|
|
2918
|
+
sideOpen ? (0, import_react9.createElement)(
|
|
2692
2919
|
"aside",
|
|
2693
2920
|
{ className: "mailharbor-side" },
|
|
2694
|
-
(0, import_react9.createElement)(
|
|
2695
|
-
"button",
|
|
2696
|
-
{
|
|
2697
|
-
className: `mailharbor-side-item${isAll ? " active" : ""}`,
|
|
2698
|
-
onClick: () => {
|
|
2699
|
-
setAccountScope("all");
|
|
2700
|
-
setSource("local");
|
|
2701
|
-
setMailbox("all");
|
|
2702
|
-
setSelected(null);
|
|
2703
|
-
}
|
|
2704
|
-
},
|
|
2705
|
-
(0, import_react9.createElement)(Icon, { name: "mail", size: 15 }),
|
|
2706
|
-
(0, import_react9.createElement)("span", { className: "name" }, "\u7EDF\u4E00\u6536\u4EF6\u7BB1"),
|
|
2707
|
-
(0, import_react9.createElement)("span", { className: "count" }, String(accounts.length))
|
|
2708
|
-
),
|
|
2709
2921
|
(0, import_react9.createElement)("div", { className: "mailharbor-side-section" }, "\u8D26\u53F7"),
|
|
2710
2922
|
accounts.map(
|
|
2711
2923
|
(item) => (0, import_react9.createElement)(
|
|
@@ -2729,12 +2941,12 @@ function MailPanel() {
|
|
|
2729
2941
|
item.enabled === false ? (0, import_react9.createElement)("span", { className: "badge warn" }, "\u505C\u7528") : null
|
|
2730
2942
|
)
|
|
2731
2943
|
),
|
|
2732
|
-
|
|
2944
|
+
(0, import_react9.createElement)(
|
|
2733
2945
|
"div",
|
|
2734
2946
|
{ className: "mailharbor-side-section" },
|
|
2735
2947
|
source === "server" ? "\u670D\u52A1\u5668\u6587\u4EF6\u5939" : "\u672C\u5730\u6587\u4EF6\u5939"
|
|
2736
2948
|
),
|
|
2737
|
-
|
|
2949
|
+
folders.map(
|
|
2738
2950
|
(folder) => (0, import_react9.createElement)(
|
|
2739
2951
|
"button",
|
|
2740
2952
|
{
|
|
@@ -2750,7 +2962,7 @@ function MailPanel() {
|
|
|
2750
2962
|
folder.count > 0 ? (0, import_react9.createElement)("span", { className: "count" }, String(folder.count)) : null
|
|
2751
2963
|
)
|
|
2752
2964
|
)
|
|
2753
|
-
),
|
|
2965
|
+
) : null,
|
|
2754
2966
|
(0, import_react9.createElement)(
|
|
2755
2967
|
"div",
|
|
2756
2968
|
{ className: "mailharbor-list" },
|
|
@@ -2759,19 +2971,23 @@ function MailPanel() {
|
|
|
2759
2971
|
{ className: "mailharbor-filters" },
|
|
2760
2972
|
(0, import_react9.createElement)("input", {
|
|
2761
2973
|
type: "search",
|
|
2762
|
-
placeholder: showingDrafts ? "\u641C\u7D22\u8349\u7A3F" : "\u641C\u7D22\u90AE\u4EF6",
|
|
2974
|
+
placeholder: showingDrafts ? "\u641C\u7D22\u8349\u7A3F" : aiSearching ? "AI \u6B63\u5728\u7406\u89E3\u4F60\u7684\u641C\u7D22\u2026" : "\u641C\u7D22\u90AE\u4EF6\uFF0C\u6216\u63CF\u8FF0\u4F60\u8981\u627E\u4EC0\u4E48\uFF08AI\uFF09",
|
|
2763
2975
|
"aria-label": "\u641C\u7D22\u90AE\u4EF6",
|
|
2764
2976
|
value: query2,
|
|
2765
2977
|
onChange: (event) => setQuery(event.target.value),
|
|
2766
2978
|
onKeyDown: (event) => {
|
|
2767
|
-
if (event.key === "Enter")
|
|
2979
|
+
if (event.key === "Enter") {
|
|
2980
|
+
if (showingDrafts) setSearch(query2);
|
|
2981
|
+
else void runAiSearch();
|
|
2982
|
+
}
|
|
2768
2983
|
if (event.key === "Escape") {
|
|
2769
2984
|
setQuery("");
|
|
2770
2985
|
setSearch("");
|
|
2986
|
+
setAiInfo(null);
|
|
2771
2987
|
}
|
|
2772
2988
|
}
|
|
2773
2989
|
}),
|
|
2774
|
-
|
|
2990
|
+
(0, import_react9.createElement)(
|
|
2775
2991
|
"button",
|
|
2776
2992
|
{
|
|
2777
2993
|
className: selectMode ? "ghost active" : "ghost",
|
|
@@ -2785,9 +3001,9 @@ function MailPanel() {
|
|
|
2785
3001
|
}
|
|
2786
3002
|
}
|
|
2787
3003
|
},
|
|
2788
|
-
Icon({ name: "
|
|
3004
|
+
Icon({ name: "list", size: 14 }),
|
|
2789
3005
|
"\u9009\u62E9"
|
|
2790
|
-
)
|
|
3006
|
+
),
|
|
2791
3007
|
query2 !== search || search !== "" ? (0, import_react9.createElement)(
|
|
2792
3008
|
"button",
|
|
2793
3009
|
{
|
|
@@ -2796,11 +3012,35 @@ function MailPanel() {
|
|
|
2796
3012
|
onClick: () => {
|
|
2797
3013
|
setQuery("");
|
|
2798
3014
|
setSearch("");
|
|
3015
|
+
setAiInfo(null);
|
|
2799
3016
|
}
|
|
2800
3017
|
},
|
|
2801
3018
|
(0, import_react9.createElement)(Icon, { name: "close", size: 14 })
|
|
2802
3019
|
) : null
|
|
2803
3020
|
),
|
|
3021
|
+
aiInfo === null ? null : (0, import_react9.createElement)(
|
|
3022
|
+
"div",
|
|
3023
|
+
{ className: "mailharbor-ai-search" },
|
|
3024
|
+
(0, import_react9.createElement)(Icon, { name: "sparkles", size: 13 }),
|
|
3025
|
+
(0, import_react9.createElement)(
|
|
3026
|
+
"span",
|
|
3027
|
+
null,
|
|
3028
|
+
aiInfo.explanation !== "" ? aiInfo.explanation : `\u5173\u952E\u8BCD\uFF1A${aiInfo.keywords.join("\u3001")}`
|
|
3029
|
+
),
|
|
3030
|
+
(0, import_react9.createElement)("span", { className: "spacer" }),
|
|
3031
|
+
(0, import_react9.createElement)(
|
|
3032
|
+
"button",
|
|
3033
|
+
{
|
|
3034
|
+
className: "subtle",
|
|
3035
|
+
onClick: () => {
|
|
3036
|
+
setAiInfo(null);
|
|
3037
|
+
setTick((value) => value + 1);
|
|
3038
|
+
}
|
|
3039
|
+
},
|
|
3040
|
+
"\u6E05\u9664"
|
|
3041
|
+
)
|
|
3042
|
+
),
|
|
3043
|
+
aiSearching ? (0, import_react9.createElement)("div", { className: "mailharbor-ai-search searching" }, "AI \u6B63\u5728\u7406\u89E3\u5E76\u641C\u7D22\u2026") : null,
|
|
2804
3044
|
selectMode ? (0, import_react9.createElement)(
|
|
2805
3045
|
"div",
|
|
2806
3046
|
{ className: "mailharbor-selectbar" },
|
|
@@ -2911,76 +3151,39 @@ function MailPanel() {
|
|
|
2911
3151
|
) : items.length === 0 ? (0, import_react9.createElement)(
|
|
2912
3152
|
"div",
|
|
2913
3153
|
{ className: "mailharbor-empty" },
|
|
2914
|
-
(0, import_react9.createElement)(Icon, { name: "mail", size: 28 }),
|
|
3154
|
+
(0, import_react9.createElement)(Icon, { name: aiInfo === null ? "mail" : "sparkles", size: 28 }),
|
|
2915
3155
|
(0, import_react9.createElement)(
|
|
2916
3156
|
"div",
|
|
2917
3157
|
{ className: "title" },
|
|
2918
|
-
source === "local" ? "\u672C\u5730\u5907\u4EFD\u91CC\u8FD8\u6CA1\u6709\u90AE\u4EF6" : "\u670D\u52A1\u5668\u4E0A\u6CA1\u6709\u90AE\u4EF6"
|
|
3158
|
+
aiInfo === null ? source === "local" ? "\u672C\u5730\u5907\u4EFD\u91CC\u8FD8\u6CA1\u6709\u90AE\u4EF6" : "\u670D\u52A1\u5668\u4E0A\u6CA1\u6709\u90AE\u4EF6" : "AI \u641C\u7D22\u6CA1\u6709\u627E\u5230\u5339\u914D\u90AE\u4EF6"
|
|
2919
3159
|
),
|
|
2920
3160
|
(0, import_react9.createElement)(
|
|
2921
3161
|
"div",
|
|
2922
3162
|
{ className: "small" },
|
|
2923
|
-
source === "local" ? "\u70B9\u9876\u90E8\u300C\u5907\u4EFD\u300D\u628A\u670D\u52A1\u5668\u90AE\u4EF6\u540C\u6B65\u4E0B\u6765\u3002" : "\u6362\u4E00\u4E2A\u6587\u4EF6\u5939\u6216\u7A0D\u540E\u5237\u65B0\u3002"
|
|
3163
|
+
aiInfo === null ? source === "local" ? "\u70B9\u9876\u90E8\u300C\u5907\u4EFD\u300D\u628A\u670D\u52A1\u5668\u90AE\u4EF6\u540C\u6B65\u4E0B\u6765\u3002" : "\u6362\u4E00\u4E2A\u6587\u4EF6\u5939\u6216\u7A0D\u540E\u5237\u65B0\u3002" : "\u6362\u4E2A\u8BF4\u6CD5\uFF0C\u6216\u76F4\u63A5\u8F93\u5165\u5173\u952E\u8BCD\u540E\u6309\u56DE\u8F66\u3002"
|
|
2924
3164
|
)
|
|
2925
|
-
) : items.map(
|
|
2926
|
-
|
|
3165
|
+
) : selectMode ? items.map((item) => renderMessage(item)) : groups.map((group) => {
|
|
3166
|
+
const latest = group.items[0];
|
|
3167
|
+
if (latest === void 0) return null;
|
|
3168
|
+
const expanded = expandedGroups.includes(group.key);
|
|
3169
|
+
return (0, import_react9.createElement)(
|
|
2927
3170
|
"div",
|
|
2928
|
-
{
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
onKeyDown: (event) => {
|
|
2938
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
2939
|
-
event.preventDefault();
|
|
2940
|
-
if (selectMode) toggleSelect(item);
|
|
2941
|
-
else void openMessage(item);
|
|
2942
|
-
}
|
|
2943
|
-
}
|
|
2944
|
-
},
|
|
2945
|
-
(0, import_react9.createElement)(
|
|
2946
|
-
"span",
|
|
2947
|
-
{ className: "line-1" },
|
|
2948
|
-
selectMode ? (0, import_react9.createElement)("input", {
|
|
2949
|
-
type: "checkbox",
|
|
2950
|
-
checked: selectedKeys.includes(`${item.accountId}:${item.id}`),
|
|
2951
|
-
"aria-label": "\u9009\u62E9\u90AE\u4EF6",
|
|
2952
|
-
onClick: (event) => event.stopPropagation(),
|
|
2953
|
-
onChange: () => toggleSelect(item)
|
|
2954
|
-
}) : item.unread ? (0, import_react9.createElement)("span", { className: "dot" }) : null,
|
|
2955
|
-
(0, import_react9.createElement)(
|
|
2956
|
-
"span",
|
|
2957
|
-
{ className: "from" },
|
|
2958
|
-
item.from.name !== "" ? item.from.name : item.from.address
|
|
2959
|
-
),
|
|
2960
|
-
item.hasAttachments ? (0, import_react9.createElement)(Icon, { name: "paperclip", size: 13 }) : null,
|
|
2961
|
-
isAll ? (0, import_react9.createElement)(
|
|
2962
|
-
"span",
|
|
2963
|
-
{ className: "badge" },
|
|
2964
|
-
accounts.find((entry) => entry.id === item.accountId)?.label ?? ""
|
|
2965
|
-
) : null,
|
|
2966
|
-
source === "local" && item.backedUp === false ? (0, import_react9.createElement)("span", { className: "badge warn" }, "\u672A\u5907\u4EFD") : null,
|
|
2967
|
-
(0, import_react9.createElement)("span", { className: "date" }, shortDate(item.date))
|
|
2968
|
-
),
|
|
2969
|
-
(0, import_react9.createElement)(
|
|
2970
|
-
"span",
|
|
2971
|
-
{ className: "line-2" },
|
|
2972
|
-
(0, import_react9.createElement)("span", { className: "subject" }, item.subject)
|
|
2973
|
-
),
|
|
2974
|
-
item.snippet === "" ? null : (0, import_react9.createElement)("span", { className: "snippet" }, item.snippet)
|
|
2975
|
-
)
|
|
2976
|
-
)
|
|
3171
|
+
{ className: "mailharbor-thread", key: group.key },
|
|
3172
|
+
renderMessage(latest, {
|
|
3173
|
+
groupCount: group.items.length,
|
|
3174
|
+
groupKey: group.key,
|
|
3175
|
+
expanded
|
|
3176
|
+
}),
|
|
3177
|
+
expanded ? group.items.slice(1).map((item) => renderMessage(item, { compact: true })) : null
|
|
3178
|
+
);
|
|
3179
|
+
})
|
|
2977
3180
|
),
|
|
2978
3181
|
!showingDrafts && items.length > 0 ? (0, import_react9.createElement)(
|
|
2979
3182
|
"div",
|
|
2980
3183
|
{ className: "mailharbor-list-foot" },
|
|
2981
3184
|
(0, import_react9.createElement)("span", null, `${String(items.length)} / ${String(page.total)} \u5C01`),
|
|
2982
3185
|
(0, import_react9.createElement)("span", { className: "spacer" }),
|
|
2983
|
-
page.total > items.length ? (0, import_react9.createElement)(
|
|
3186
|
+
page.total > items.length && aiInfo === null ? (0, import_react9.createElement)(
|
|
2984
3187
|
"button",
|
|
2985
3188
|
{ className: "subtle", onClick: () => setLimit((current) => current + 40) },
|
|
2986
3189
|
"\u52A0\u8F7D\u66F4\u591A"
|
|
@@ -3012,6 +3215,7 @@ function MailPanel() {
|
|
|
3012
3215
|
onReply: (mode) => startCompose(mode),
|
|
3013
3216
|
onAiAction: requestAi,
|
|
3014
3217
|
onExtractTasks: () => void extractTasks(),
|
|
3218
|
+
onAddToProject: openProjectPicker,
|
|
3015
3219
|
onClose: narrow ? () => setSelected(null) : void 0
|
|
3016
3220
|
})
|
|
3017
3221
|
),
|
|
@@ -3059,6 +3263,64 @@ function MailPanel() {
|
|
|
3059
3263
|
backup.output.length === 0 ? "\uFF08\u7B49\u5F85\u8F93\u51FA\u2026\uFF09" : backup.output.join("\n")
|
|
3060
3264
|
)
|
|
3061
3265
|
) : null,
|
|
3266
|
+
projectPicker !== null ? (0, import_react9.createElement)(
|
|
3267
|
+
Modal,
|
|
3268
|
+
{
|
|
3269
|
+
title: "\u52A0\u5165\u9879\u76EE",
|
|
3270
|
+
onClose: () => setProjectPicker(null),
|
|
3271
|
+
footer: (0, import_react9.createElement)(
|
|
3272
|
+
"div",
|
|
3273
|
+
{ style: { display: "flex", gap: "8px", width: "100%", alignItems: "center" } },
|
|
3274
|
+
(0, import_react9.createElement)("span", { className: "small muted" }, "\u628A\u8FD9\u5C01\u90AE\u4EF6\u5173\u8054\u5230\u4E00\u4E2A\u9879\u76EE"),
|
|
3275
|
+
(0, import_react9.createElement)("span", { className: "spacer" }),
|
|
3276
|
+
(0, import_react9.createElement)("button", { className: "ghost", onClick: () => setProjectPicker(null) }, "\u53D6\u6D88"),
|
|
3277
|
+
(0, import_react9.createElement)(
|
|
3278
|
+
"button",
|
|
3279
|
+
{ className: "primary", disabled: pickerBusy, onClick: () => void saveProjectPick() },
|
|
3280
|
+
pickerBusy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
|
|
3281
|
+
)
|
|
3282
|
+
)
|
|
3283
|
+
},
|
|
3284
|
+
(0, import_react9.createElement)(
|
|
3285
|
+
"div",
|
|
3286
|
+
{ style: { display: "flex", flexDirection: "column", gap: "10px" } },
|
|
3287
|
+
pickerProjects.length === 0 ? (0, import_react9.createElement)("p", { className: "small muted" }, "\u8FD8\u6CA1\u6709\u9879\u76EE\uFF0C\u5728\u4E0B\u9762\u65B0\u5EFA\u4E00\u4E2A\u3002") : (0, import_react9.createElement)(
|
|
3288
|
+
"div",
|
|
3289
|
+
{ className: "mailharbor-field" },
|
|
3290
|
+
(0, import_react9.createElement)("label", null, "\u9009\u62E9\u5DF2\u6709\u9879\u76EE"),
|
|
3291
|
+
(0, import_react9.createElement)(
|
|
3292
|
+
"select",
|
|
3293
|
+
{
|
|
3294
|
+
value: pickerTarget,
|
|
3295
|
+
onChange: (event) => setPickerTarget(event.target.value)
|
|
3296
|
+
},
|
|
3297
|
+
(0, import_react9.createElement)("option", { value: "" }, "\u4E0D\u52A0\u5165\u5DF2\u6709\u9879\u76EE"),
|
|
3298
|
+
pickerProjects.map(
|
|
3299
|
+
(project) => (0, import_react9.createElement)(
|
|
3300
|
+
"option",
|
|
3301
|
+
{ key: project.id, value: project.id },
|
|
3302
|
+
`${project.name} \xB7 ${project.messages.length} \u5C01`
|
|
3303
|
+
)
|
|
3304
|
+
)
|
|
3305
|
+
)
|
|
3306
|
+
),
|
|
3307
|
+
(0, import_react9.createElement)(
|
|
3308
|
+
"div",
|
|
3309
|
+
{ className: "mailharbor-field" },
|
|
3310
|
+
(0, import_react9.createElement)("label", null, pickerProjects.length === 0 ? "\u65B0\u5EFA\u9879\u76EE" : "\u6216\u65B0\u5EFA\u9879\u76EE"),
|
|
3311
|
+
(0, import_react9.createElement)("input", {
|
|
3312
|
+
value: pickerNewName,
|
|
3313
|
+
placeholder: "\u9879\u76EE\u540D\u79F0",
|
|
3314
|
+
onChange: (event) => setPickerNewName(event.target.value)
|
|
3315
|
+
})
|
|
3316
|
+
),
|
|
3317
|
+
(0, import_react9.createElement)(
|
|
3318
|
+
"p",
|
|
3319
|
+
{ className: "small muted" },
|
|
3320
|
+
pickerTarget === "" ? "\u4FDD\u5B58\u65F6\u4F1A\u7528\u4E0A\u9762\u7684\u540D\u79F0\u521B\u5EFA\u9879\u76EE\uFF0C\u5E76\u628A\u5F53\u524D\u90AE\u4EF6\u52A0\u8FDB\u53BB\u3002" : "\u4FDD\u5B58\u540E\u8FD9\u5C01\u90AE\u4EF6\u4F1A\u51FA\u73B0\u5728\u9879\u76EE\u7684\u6765\u6E90\u90AE\u4EF6\u5217\u8868\u91CC\u3002"
|
|
3321
|
+
)
|
|
3322
|
+
)
|
|
3323
|
+
) : null,
|
|
3062
3324
|
extraction !== null ? (0, import_react9.createElement)(
|
|
3063
3325
|
Modal,
|
|
3064
3326
|
{
|
|
@@ -3365,13 +3627,28 @@ function MailSettings() {
|
|
|
3365
3627
|
})
|
|
3366
3628
|
),
|
|
3367
3629
|
(0, import_react10.createElement)(
|
|
3368
|
-
"
|
|
3369
|
-
{
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3630
|
+
"div",
|
|
3631
|
+
{ style: { display: "flex", gap: "6px", alignSelf: "end" } },
|
|
3632
|
+
(0, import_react10.createElement)(
|
|
3633
|
+
"button",
|
|
3634
|
+
{
|
|
3635
|
+
className: "ghost small",
|
|
3636
|
+
onClick: () => {
|
|
3637
|
+
void api.pickDirectory().then((result) => {
|
|
3638
|
+
if (result.path !== null) setProjectRoot(result.path);
|
|
3639
|
+
}).catch((caught) => setError(errorText6(caught)));
|
|
3640
|
+
}
|
|
3641
|
+
},
|
|
3642
|
+
"\u6D4F\u89C8\u2026"
|
|
3643
|
+
),
|
|
3644
|
+
(0, import_react10.createElement)(
|
|
3645
|
+
"button",
|
|
3646
|
+
{
|
|
3647
|
+
className: "ghost small",
|
|
3648
|
+
onClick: () => void saveGeneral({ projects: { root: projectRoot } })
|
|
3649
|
+
},
|
|
3650
|
+
"\u4FDD\u5B58\u76EE\u5F55"
|
|
3651
|
+
)
|
|
3375
3652
|
)
|
|
3376
3653
|
)
|
|
3377
3654
|
),
|
|
@@ -3789,7 +4066,8 @@ var FILTERS = [
|
|
|
3789
4066
|
var COLUMNS = [
|
|
3790
4067
|
{ status: "NEEDS-ACTION", label: "\u5F85\u5904\u7406", hint: "\u8FD8\u6CA1\u5F00\u59CB" },
|
|
3791
4068
|
{ status: "IN-PROCESS", label: "\u8FDB\u884C\u4E2D", hint: "\u6B63\u5728\u505A" },
|
|
3792
|
-
{ status: "COMPLETED", label: "\u5DF2\u5B8C\u6210", hint: "\u6536\u5C3E" }
|
|
4069
|
+
{ status: "COMPLETED", label: "\u5DF2\u5B8C\u6210", hint: "\u6536\u5C3E" },
|
|
4070
|
+
{ status: "CANCELLED", label: "\u7EC8\u6B62", hint: "\u4E0D\u505A\u4E86" }
|
|
3793
4071
|
];
|
|
3794
4072
|
var PRIORITY_LABEL = { 0: "\u65E0", 5: "\u4E2D", 9: "\u9AD8" };
|
|
3795
4073
|
function errorText7(error) {
|
|
@@ -3833,7 +4111,9 @@ function TasksIcon() {
|
|
|
3833
4111
|
if (accountId === null) return;
|
|
3834
4112
|
const result = await api.tasks(accountId);
|
|
3835
4113
|
if (!cancelled) {
|
|
3836
|
-
setCount(
|
|
4114
|
+
setCount(
|
|
4115
|
+
result.items.filter((task) => task.status !== "COMPLETED" && task.status !== "CANCELLED").length
|
|
4116
|
+
);
|
|
3837
4117
|
}
|
|
3838
4118
|
} catch {
|
|
3839
4119
|
}
|
|
@@ -3893,6 +4173,7 @@ function TasksPanel() {
|
|
|
3893
4173
|
const [tasks, setTasks] = (0, import_react11.useState)([]);
|
|
3894
4174
|
const [projects, setProjects] = (0, import_react11.useState)([]);
|
|
3895
4175
|
const [filter, setFilter] = (0, import_react11.useState)("all");
|
|
4176
|
+
const [projectFilter, setProjectFilter] = (0, import_react11.useState)("");
|
|
3896
4177
|
const [error, setError] = (0, import_react11.useState)("");
|
|
3897
4178
|
const [toast, setToast] = (0, import_react11.useState)("");
|
|
3898
4179
|
const [busy, setBusy] = (0, import_react11.useState)(false);
|
|
@@ -3938,10 +4219,6 @@ function TasksPanel() {
|
|
|
3938
4219
|
},
|
|
3939
4220
|
[filter]
|
|
3940
4221
|
);
|
|
3941
|
-
const open = tasks.filter((task) => task.status !== "COMPLETED");
|
|
3942
|
-
const doneCount = tasks.length - open.length;
|
|
3943
|
-
const progress = tasks.length === 0 ? 0 : Math.round(doneCount / tasks.length * 100);
|
|
3944
|
-
const overdue = open.filter((task) => task.due !== "" && task.due.slice(0, 10) < dateKey(/* @__PURE__ */ new Date())).length;
|
|
3945
4222
|
const switchAccount = async (id) => {
|
|
3946
4223
|
try {
|
|
3947
4224
|
await api.activateAccount(id);
|
|
@@ -4047,47 +4324,6 @@ function TasksPanel() {
|
|
|
4047
4324
|
(0, import_react11.createElement)(
|
|
4048
4325
|
"div",
|
|
4049
4326
|
{ className: "tasks-board-wrap" },
|
|
4050
|
-
(0, import_react11.createElement)(
|
|
4051
|
-
"div",
|
|
4052
|
-
{ className: "tasks-summary" },
|
|
4053
|
-
(0, import_react11.createElement)(
|
|
4054
|
-
"div",
|
|
4055
|
-
{ className: "tasks-summary-main" },
|
|
4056
|
-
(0, import_react11.createElement)(
|
|
4057
|
-
"div",
|
|
4058
|
-
{ className: "tasks-summary-labels" },
|
|
4059
|
-
(0, import_react11.createElement)("strong", null, "\u603B\u4F53\u8FDB\u5EA6"),
|
|
4060
|
-
(0, import_react11.createElement)(
|
|
4061
|
-
"span",
|
|
4062
|
-
{ className: "muted small" },
|
|
4063
|
-
`${String(doneCount)} / ${String(tasks.length)} \xB7 ${String(progress)}%`
|
|
4064
|
-
)
|
|
4065
|
-
),
|
|
4066
|
-
(0, import_react11.createElement)("div", { className: "tasks-bar" }, (0, import_react11.createElement)("span", { style: { width: `${String(progress)}%` } }))
|
|
4067
|
-
),
|
|
4068
|
-
(0, import_react11.createElement)(
|
|
4069
|
-
"div",
|
|
4070
|
-
{ className: "tasks-stats" },
|
|
4071
|
-
(0, import_react11.createElement)(
|
|
4072
|
-
"span",
|
|
4073
|
-
{ className: "tasks-stat" },
|
|
4074
|
-
(0, import_react11.createElement)("strong", null, String(open.length)),
|
|
4075
|
-
(0, import_react11.createElement)("span", null, "\u5F85\u529E")
|
|
4076
|
-
),
|
|
4077
|
-
(0, import_react11.createElement)(
|
|
4078
|
-
"span",
|
|
4079
|
-
{ className: overdue > 0 ? "tasks-stat danger" : "tasks-stat" },
|
|
4080
|
-
(0, import_react11.createElement)("strong", null, String(overdue)),
|
|
4081
|
-
(0, import_react11.createElement)("span", null, "\u903E\u671F")
|
|
4082
|
-
),
|
|
4083
|
-
(0, import_react11.createElement)(
|
|
4084
|
-
"span",
|
|
4085
|
-
{ className: "tasks-stat" },
|
|
4086
|
-
(0, import_react11.createElement)("strong", null, String(projects.length)),
|
|
4087
|
-
(0, import_react11.createElement)("span", null, "\u9879\u76EE")
|
|
4088
|
-
)
|
|
4089
|
-
)
|
|
4090
|
-
),
|
|
4091
4327
|
(0, import_react11.createElement)(
|
|
4092
4328
|
"div",
|
|
4093
4329
|
{ className: "tasks-toolbar" },
|
|
@@ -4107,13 +4343,27 @@ function TasksPanel() {
|
|
|
4107
4343
|
)
|
|
4108
4344
|
),
|
|
4109
4345
|
(0, import_react11.createElement)("span", { className: "spacer" }),
|
|
4346
|
+
(0, import_react11.createElement)(
|
|
4347
|
+
"select",
|
|
4348
|
+
{
|
|
4349
|
+
value: projectFilter,
|
|
4350
|
+
onChange: (event) => setProjectFilter(event.target.value),
|
|
4351
|
+
"aria-label": "\u6309\u9879\u76EE\u7B5B\u9009"
|
|
4352
|
+
},
|
|
4353
|
+
(0, import_react11.createElement)("option", { value: "" }, "\u5168\u90E8\u9879\u76EE"),
|
|
4354
|
+
projects.map((project) => (0, import_react11.createElement)("option", { key: project.id, value: project.id }, project.name))
|
|
4355
|
+
),
|
|
4110
4356
|
(0, import_react11.createElement)("span", { className: "small muted" }, "\u62D6\u52A8\u5361\u7247\u53EF\u6539\u53D8\u72B6\u6001")
|
|
4111
4357
|
),
|
|
4112
4358
|
(0, import_react11.createElement)(
|
|
4113
4359
|
"div",
|
|
4114
4360
|
{ className: "tasks-board" },
|
|
4115
4361
|
COLUMNS.map((column) => {
|
|
4116
|
-
const cards = tasks.filter((task) => task.status === column.status).filter(matchesFilter)
|
|
4362
|
+
const cards = tasks.filter((task) => task.status === column.status).filter(matchesFilter).filter((task) => projectFilter === "" || task.projectId === projectFilter).sort((left, right) => {
|
|
4363
|
+
const leftDue = left.due === "" ? "9999" : left.due.slice(0, 10);
|
|
4364
|
+
const rightDue = right.due === "" ? "9999" : right.due.slice(0, 10);
|
|
4365
|
+
return leftDue.localeCompare(rightDue);
|
|
4366
|
+
});
|
|
4117
4367
|
return (0, import_react11.createElement)(
|
|
4118
4368
|
"div",
|
|
4119
4369
|
{
|
|
@@ -4394,7 +4644,7 @@ function TaskEditor({
|
|
|
4394
4644
|
}
|
|
4395
4645
|
|
|
4396
4646
|
// src/client/index.tsx
|
|
4397
|
-
var VERSION = "0.
|
|
4647
|
+
var VERSION = "0.7.1";
|
|
4398
4648
|
var inject = ["slots"];
|
|
4399
4649
|
var PANEL_ID = "mailharbor";
|
|
4400
4650
|
var TASKS_PANEL_ID = "mailharbor-tasks";
|