@zaclinley/dsh-mailharbor 0.1.0 → 0.2.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/lib/client.js CHANGED
@@ -34,7 +34,7 @@ __export(index_exports, {
34
34
  module.exports = __toCommonJS(index_exports);
35
35
 
36
36
  // src/client/styles.css
37
- var styles_default = "/* MailHarbor panel + settings. Colors come from the DSH shell tokens with\n light-mode fallbacks so the plugin also renders in a bare host page. */\n\n.mailharbor {\n --m-bg: var(--dsw-alias-bg-base, #ffffff);\n --m-bg-1: var(--dsw-alias-bg-layer-1, #f6f7f9);\n --m-bg-2: var(--dsw-alias-bg-layer-2, #eceef2);\n --m-bg-3: var(--dsw-alias-bg-layer-3, #e4e7ec);\n --m-line: var(--dsw-alias-border-l2, rgba(15, 23, 42, 0.1));\n --m-line-soft: var(--dsw-alias-border-l1, rgba(15, 23, 42, 0.06));\n --m-text: var(--dsw-alias-label-primary, #171a21);\n --m-text-2: var(--dsw-alias-label-secondary, #565c67);\n --m-text-3: var(--dsw-alias-label-tertiary, #8a909c);\n --m-brand: var(--dsw-alias-brand-primary, #4d6bfe);\n --m-brand-soft: color-mix(in srgb, var(--m-brand) 12%, transparent);\n --m-hover: var(--dsw-alias-interactive-bg-hover, rgba(15, 23, 42, 0.05));\n --m-danger: var(--dsw-alias-label-error, #d93025);\n --m-ok: var(--dsw-alias-state-success-primary, #1a9e5c);\n --m-warn: var(--dsw-alias-state-warn-primary, #d88a2a);\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}\n\n.mailharbor *,\n.mailharbor *::before,\n.mailharbor *::after {\n box-sizing: border-box;\n}\n\n/* ---------- shell ---------- */\n\n.mailharbor-topbar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-body {\n display: flex;\n flex: 1;\n min-height: 0;\n}\n\n.mailharbor-list {\n display: flex;\n flex-direction: column;\n width: 340px;\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: 900px) {\n .mailharbor-list {\n width: 280px;\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/* ---------- controls ---------- */\n\n.mailharbor button {\n font: inherit;\n color: inherit;\n background: transparent;\n border: 1px solid transparent;\n border-radius: 7px;\n padding: 5px 9px;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n white-space: nowrap;\n}\n\n.mailharbor button:hover:not(:disabled) {\n background: var(--m-hover);\n}\n\n.mailharbor button:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n.mailharbor button.primary {\n background: var(--m-brand);\n color: #fff;\n}\n\n.mailharbor button.primary:hover:not(:disabled) {\n filter: brightness(1.05);\n background: var(--m-brand);\n}\n\n.mailharbor button.ghost {\n border-color: var(--m-line);\n}\n\n.mailharbor button.subtle {\n color: var(--m-text-2);\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: inherit;\n background: var(--m-bg-1);\n border: 1px solid var(--m-line);\n border-radius: 7px;\n padding: 6px 8px;\n min-width: 0;\n}\n\n.mailharbor input:focus,\n.mailharbor select:focus,\n.mailharbor textarea:focus,\n.mailharbor [contenteditable='true']:focus {\n outline: 2px solid color-mix(in srgb, var(--m-brand) 45%, transparent);\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 font-size: 11px;\n padding: 1px 6px;\n border-radius: 999px;\n background: var(--m-bg-2);\n color: var(--m-text-2);\n}\n\n.mailharbor .badge.ok {\n background: color-mix(in srgb, var(--m-ok) 15%, transparent);\n color: var(--m-ok);\n}\n\n.mailharbor .badge.warn {\n background: color-mix(in srgb, var(--m-warn) 16%, transparent);\n color: var(--m-warn);\n}\n\n.mailharbor .error {\n color: var(--m-danger);\n padding: 8px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n background: color-mix(in srgb, var(--m-danger) 7%, transparent);\n}\n\n/* ---------- list ---------- */\n\n.mailharbor-filters {\n display: flex;\n gap: 8px;\n align-items: center;\n padding: 8px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-filters input[type='search'] {\n flex: 1;\n}\n\n.mailharbor-segment {\n display: inline-flex;\n background: var(--m-bg-2);\n border-radius: 8px;\n padding: 2px;\n gap: 2px;\n}\n\n.mailharbor-segment button {\n padding: 3px 10px;\n border-radius: 6px;\n color: var(--m-text-2);\n}\n\n.mailharbor-segment button.active {\n background: var(--m-bg);\n color: var(--m-text);\n box-shadow: 0 1px 2px rgba(15, 23, 42, 0.12);\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: 2px;\n padding: 9px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n cursor: pointer;\n text-align: left;\n width: 100%;\n border-radius: 0;\n border-left: 2px solid transparent;\n}\n\n.mailharbor-row:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-row.selected {\n background: var(--m-brand-soft);\n border-left-color: var(--m-brand);\n}\n\n.mailharbor-row .line-1,\n.mailharbor-row .line-2 {\n display: flex;\n gap: 8px;\n align-items: baseline;\n min-width: 0;\n}\n\n.mailharbor-row .from {\n font-weight: 600;\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-text-3);\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}\n\n.mailharbor-row.unread .subject,\n.mailharbor-row.unread .from {\n color: var(--m-text);\n}\n\n.mailharbor-row.unread .from::before {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--m-brand);\n margin-right: 6px;\n vertical-align: middle;\n}\n\n.mailharbor-row .snippet {\n color: var(--m-text-3);\n font-size: 12px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-empty {\n padding: 40px 20px;\n text-align: center;\n color: var(--m-text-3);\n}\n\n/* ---------- reader ---------- */\n\n.mailharbor-reader-head {\n padding: 10px 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.mailharbor-reader-head h2 {\n margin: 0;\n font-size: 15px;\n line-height: 1.35;\n word-break: break-word;\n}\n\n.mailharbor-reader-meta {\n color: var(--m-text-2);\n font-size: 12px;\n display: flex;\n flex-wrap: wrap;\n gap: 4px 12px;\n}\n\n.mailharbor-reader-actions {\n display: flex;\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 background: var(--m-bg-1);\n}\n\n.mailharbor-reader-body iframe {\n flex: 1;\n width: 100%;\n border: 0;\n background: #fff;\n}\n\n.mailharbor-reader-body pre {\n flex: 1;\n overflow: auto;\n margin: 0;\n padding: 16px 18px;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n line-height: 1.6;\n}\n\n.mailharbor-attachments {\n padding: 8px 14px;\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: 6px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n padding: 4px 8px;\n font-size: 12px;\n text-decoration: none;\n color: var(--m-text);\n max-width: 260px;\n}\n\n.mailharbor-attachment:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-attachment span.name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---------- modal / form ---------- */\n\n.mailharbor-modal-mask {\n position: fixed;\n inset: 0;\n background: rgba(15, 23, 42, 0.35);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 60;\n padding: 24px;\n}\n\n.mailharbor-modal {\n background: var(--m-bg);\n color: var(--m-text);\n border-radius: 12px;\n box-shadow: 0 18px 60px rgba(15, 23, 42, 0.28);\n width: min(760px, 100%);\n max-height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.mailharbor-modal header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n border-bottom: 1px solid var(--m-line-soft);\n font-weight: 600;\n}\n\n.mailharbor-modal .content {\n padding: 16px;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.mailharbor-modal footer {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n padding: 12px 16px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n}\n\n.mailharbor-field > label {\n font-size: 12px;\n color: var(--m-text-2);\n}\n\n.mailharbor-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n}\n\n.mailharbor-grid.three {\n grid-template-columns: 2fr 1fr auto;\n}\n\n.mailharbor-toggle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--m-text-2);\n cursor: pointer;\n}\n\n/* ---------- composer ---------- */\n\n.mailharbor-editor {\n min-height: 220px;\n max-height: 46vh;\n overflow: auto;\n padding: 10px 12px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n outline: none;\n}\n\n.mailharbor-editor:empty::before {\n content: attr(data-placeholder);\n color: var(--m-text-3);\n}\n\n.mailharbor-toolbar {\n display: flex;\n gap: 2px;\n flex-wrap: wrap;\n}\n\n.mailharbor-toolbar button {\n padding: 3px 8px;\n font-size: 12px;\n border: 1px solid transparent;\n}\n\n.mailharbor-toolbar button:hover {\n border-color: var(--m-line);\n}\n\n/* ---------- settings ---------- */\n\n.mailharbor-settings {\n padding: 16px 20px 40px;\n display: flex;\n flex-direction: column;\n gap: 18px;\n max-width: 860px;\n}\n\n.mailharbor-settings h2 {\n margin: 0 0 4px;\n font-size: 15px;\n}\n\n.mailharbor-settings h3 {\n margin: 0 0 8px;\n font-size: 13px;\n color: var(--m-text-2);\n font-weight: 600;\n}\n\n.mailharbor-card {\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n padding: 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n background: var(--m-bg);\n}\n\n.mailharbor-account-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.mailharbor-account-row .avatar {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: var(--m-brand-soft);\n color: var(--m-brand);\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n flex: none;\n}\n\n.mailharbor-log {\n background: var(--m-bg-1);\n border-radius: 8px;\n padding: 8px 10px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.5;\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, 180px) 1fr;\n gap: 4px 12px;\n font-size: 12px;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n word-break: break-all;\n}\n";
37
+ 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 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}\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/* ---------- 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 > label {\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n}\n\n.mailharbor-grid.three {\n grid-template-columns: 2fr 90px auto;\n align-items: end;\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/* ---------- settings ---------- */\n\n.mailharbor-settings {\n padding: 20px 24px 48px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 880px;\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}\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";
38
38
 
39
39
  // src/client/icon.tsx
40
40
  var import_react = require("react");
@@ -163,16 +163,24 @@ function MailIcon() {
163
163
  return (0, import_react.createElement)(
164
164
  "span",
165
165
  {
166
- style: { position: "relative", display: "inline-flex", alignItems: "center", justifyContent: "center" }
166
+ style: {
167
+ position: "relative",
168
+ display: "inline-flex",
169
+ alignItems: "center",
170
+ justifyContent: "center",
171
+ width: "18px",
172
+ height: "18px",
173
+ boxSizing: "border-box"
174
+ }
167
175
  },
168
176
  (0, import_react.createElement)(
169
177
  "svg",
170
- { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" },
171
- (0, import_react.createElement)("rect", { x: 2.5, y: 5, width: 19, height: 14, rx: 2.5, stroke: "currentColor", strokeWidth: 1.6 }),
178
+ { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" },
179
+ (0, import_react.createElement)("rect", { x: 2.5, y: 5, width: 19, height: 14, rx: 2.5, stroke: "currentColor", strokeWidth: 1.7 }),
172
180
  (0, import_react.createElement)("path", {
173
181
  d: "M3.5 7l7.6 5.4a1.6 1.6 0 0 0 1.8 0L20.5 7",
174
182
  stroke: "currentColor",
175
- strokeWidth: 1.6,
183
+ strokeWidth: 1.7,
176
184
  strokeLinecap: "round"
177
185
  })
178
186
  ),
@@ -181,18 +189,26 @@ function MailIcon() {
181
189
  {
182
190
  style: {
183
191
  position: "absolute",
184
- top: "-4px",
185
- right: "-6px",
186
- minWidth: "14px",
187
- height: "14px",
192
+ right: "-5px",
193
+ bottom: "-3px",
194
+ display: "flex",
195
+ alignItems: "center",
196
+ justifyContent: "center",
197
+ boxSizing: "border-box",
198
+ minWidth: "13px",
199
+ height: "13px",
188
200
  padding: "0 3px",
189
201
  borderRadius: "999px",
190
- background: "var(--dsw-alias-brand-primary, #4d6bfe)",
202
+ background: "#5686fe",
191
203
  color: "#fff",
192
204
  fontSize: "9px",
193
- lineHeight: "14px",
194
- textAlign: "center",
195
- fontWeight: 600
205
+ fontWeight: 600,
206
+ lineHeight: "13px",
207
+ zIndex: 1,
208
+ letterSpacing: "-0.01em",
209
+ fontVariantNumeric: "tabular-nums",
210
+ boxShadow: "0 0 0 2px var(--dsw-alias-bg-base, #151517)",
211
+ pointerEvents: "none"
196
212
  }
197
213
  },
198
214
  unread > 99 ? "99+" : String(unread)
@@ -201,7 +217,7 @@ function MailIcon() {
201
217
  }
202
218
 
203
219
  // src/client/panel.tsx
204
- var import_react6 = require("react");
220
+ var import_react7 = require("react");
205
221
 
206
222
  // src/client/account-form.tsx
207
223
  var import_react3 = require("react");
@@ -256,6 +272,15 @@ function Toggle({
256
272
  label
257
273
  );
258
274
  }
275
+ function portalRoot() {
276
+ const existing = document.getElementById("mailharbor-portal");
277
+ if (existing !== null) return existing;
278
+ const element = document.createElement("div");
279
+ element.id = "mailharbor-portal";
280
+ element.className = "mailharbor mailharbor-portal";
281
+ document.body.append(element);
282
+ return element;
283
+ }
259
284
  function Modal({
260
285
  title,
261
286
  children,
@@ -301,7 +326,7 @@ function Modal({
301
326
  footer === void 0 ? null : (0, import_react2.createElement)("footer", null, footer)
302
327
  )
303
328
  ),
304
- document.body
329
+ portalRoot()
305
330
  );
306
331
  }
307
332
  function ErrorBar({ message, onDismiss }) {
@@ -837,13 +862,68 @@ function Composer({
837
862
  );
838
863
  }
839
864
 
840
- // src/client/reader.tsx
865
+ // src/client/icons.tsx
841
866
  var import_react5 = require("react");
867
+ var PATHS = {
868
+ refresh: (0, import_react5.createElement)("path", { d: "M20 11a8 8 0 1 0-2.3 5.7M20 5v6h-6" }),
869
+ plus: (0, import_react5.createElement)("path", { d: "M12 5v14M5 12h14" }),
870
+ compose: (0, import_react5.createElement)("path", { d: "M4 20h4l10.5-10.5a2.1 2.1 0 0 0-3-3L5 17v3zM13.5 6.5l3 3" }),
871
+ archive: (0, import_react5.createElement)(
872
+ "g",
873
+ null,
874
+ (0, import_react5.createElement)("rect", { x: 3, y: 4, width: 18, height: 5, rx: 1.5 }),
875
+ (0, import_react5.createElement)("path", { d: "M5 9v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9M10 13h4" })
876
+ ),
877
+ paperclip: (0, import_react5.createElement)("path", {
878
+ d: "M20 11.5 12 19.5a5 5 0 0 1-7-7l8-8a3.3 3.3 0 0 1 4.7 4.7l-8 8a1.7 1.7 0 0 1-2.4-2.4l7.3-7.3"
879
+ }),
880
+ mail: (0, import_react5.createElement)(
881
+ "g",
882
+ null,
883
+ (0, import_react5.createElement)("rect", { x: 3, y: 5, width: 18, height: 14, rx: 2.5 }),
884
+ (0, import_react5.createElement)("path", { d: "m4 7 7.1 5a1.6 1.6 0 0 0 1.8 0L20 7" })
885
+ ),
886
+ search: (0, import_react5.createElement)("path", { d: "M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14zM20 20l-4-4" }),
887
+ reply: (0, import_react5.createElement)("path", { d: "M9 7 4 12l5 5M4 12h9a6 6 0 0 1 6 6v1" }),
888
+ replyAll: (0, import_react5.createElement)("path", { d: "m9 7-5 5 5 5M14 7l-5 5 5 5M13 12h5a5 5 0 0 1 5 5" }),
889
+ forward: (0, import_react5.createElement)("path", { d: "m15 7 5 5-5 5M20 12h-9a6 6 0 0 0-6 6v1" }),
890
+ check: (0, import_react5.createElement)("path", { d: "m5 13 4 4L19 7" }),
891
+ image: (0, import_react5.createElement)(
892
+ "g",
893
+ null,
894
+ (0, import_react5.createElement)("rect", { x: 3, y: 4, width: 18, height: 16, rx: 2 }),
895
+ (0, import_react5.createElement)("circle", { cx: 8.5, cy: 9.5, r: 1.5 }),
896
+ (0, import_react5.createElement)("path", { d: "m4 18 5-5 4 4 3-3 4 4" })
897
+ ),
898
+ close: (0, import_react5.createElement)("path", { d: "M6 6l12 12M18 6 6 18" }),
899
+ chevronLeft: (0, import_react5.createElement)("path", { d: "m14 6-6 6 6 6" })
900
+ };
901
+ function Icon({ name, size = 16 }) {
902
+ return (0, import_react5.createElement)(
903
+ "svg",
904
+ {
905
+ width: size,
906
+ height: size,
907
+ viewBox: "0 0 24 24",
908
+ fill: "none",
909
+ stroke: "currentColor",
910
+ strokeWidth: 1.7,
911
+ strokeLinecap: "round",
912
+ strokeLinejoin: "round",
913
+ "aria-hidden": "true",
914
+ focusable: "false"
915
+ },
916
+ PATHS[name] ?? null
917
+ );
918
+ }
919
+
920
+ // src/client/reader.tsx
921
+ var import_react6 = require("react");
842
922
  var IFRAME_STYLE = `
843
923
  html, body { margin: 0; padding: 0; }
844
924
  body {
845
- font: 15px/1.7 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
846
- color: #171a21; background: #fff; padding: 18px 20px;
925
+ font: 15px/1.75 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
926
+ color: #171a21; background: #fff; padding: 20px 22px;
847
927
  overflow-wrap: anywhere;
848
928
  }
849
929
  img { max-width: 100%; height: auto; }
@@ -873,6 +953,9 @@ function escapeHtml(value) {
873
953
  function hasRemoteImages(detail) {
874
954
  return detail.html !== null && /<img[^>]+src=["']https?:/i.test(detail.html);
875
955
  }
956
+ function addressLine(list) {
957
+ return list.map((item) => item.name !== "" ? `${item.name} <${item.address}>` : item.address).join("\u3001");
958
+ }
876
959
  function Reader({
877
960
  detail,
878
961
  account,
@@ -882,11 +965,11 @@ function Reader({
882
965
  onReply,
883
966
  onClose
884
967
  }) {
885
- const [plain, setPlain] = (0, import_react5.useState)(false);
886
- const [loadImages, setLoadImages] = (0, import_react5.useState)(false);
887
- const [busy, setBusy] = (0, import_react5.useState)(false);
888
- const [error, setError] = (0, import_react5.useState)("");
889
- const remoteImages = (0, import_react5.useMemo)(() => hasRemoteImages(detail), [detail]);
968
+ const [plain, setPlain] = (0, import_react6.useState)(false);
969
+ const [loadImages, setLoadImages] = (0, import_react6.useState)(false);
970
+ const [busy, setBusy] = (0, import_react6.useState)(false);
971
+ const [error, setError] = (0, import_react6.useState)("");
972
+ const remoteImages = (0, import_react6.useMemo)(() => hasRemoteImages(detail), [detail]);
890
973
  const html = detail.html !== null && detail.html !== "";
891
974
  const toggleRead = async () => {
892
975
  setBusy(true);
@@ -906,102 +989,103 @@ function Reader({
906
989
  setBusy(false);
907
990
  }
908
991
  };
909
- return (0, import_react5.createElement)(
992
+ return (0, import_react6.createElement)(
910
993
  "div",
911
994
  { className: "mailharbor-reader" },
912
- (0, import_react5.createElement)(
995
+ (0, import_react6.createElement)(
913
996
  "div",
914
997
  { className: "mailharbor-reader-head" },
915
- (0, import_react5.createElement)(
998
+ (0, import_react6.createElement)(
916
999
  "div",
917
- { style: { display: "flex", alignItems: "center", gap: "8px" } },
918
- (0, import_react5.createElement)("h2", { style: { flex: 1 } }, detail.subject),
919
- onClose === void 0 ? null : (0, import_react5.createElement)("button", { className: "ghost", onClick: onClose }, "\u8FD4\u56DE\u5217\u8868")
1000
+ { className: "mailharbor-reader-title" },
1001
+ onClose === void 0 ? null : (0, import_react6.createElement)(
1002
+ "button",
1003
+ { className: "ghost icon", onClick: onClose, "aria-label": "\u8FD4\u56DE\u5217\u8868", title: "\u8FD4\u56DE\u5217\u8868" },
1004
+ (0, import_react6.createElement)(Icon, { name: "chevronLeft" })
1005
+ ),
1006
+ (0, import_react6.createElement)("h2", { style: { flex: 1 } }, detail.subject),
1007
+ (0, import_react6.createElement)(
1008
+ "button",
1009
+ {
1010
+ className: "ghost icon",
1011
+ onClick: () => void toggleRead(),
1012
+ disabled: busy,
1013
+ title: detail.unread ? "\u6807\u4E3A\u5DF2\u8BFB" : "\u6807\u4E3A\u672A\u8BFB",
1014
+ "aria-label": detail.unread ? "\u6807\u4E3A\u5DF2\u8BFB" : "\u6807\u4E3A\u672A\u8BFB"
1015
+ },
1016
+ (0, import_react6.createElement)(Icon, { name: "check" })
1017
+ )
920
1018
  ),
921
- (0, import_react5.createElement)(
1019
+ (0, import_react6.createElement)(
922
1020
  "div",
923
1021
  { className: "mailharbor-reader-meta" },
924
- (0, import_react5.createElement)(
1022
+ (0, import_react6.createElement)(
925
1023
  "span",
926
- null,
927
- `${detail.from.name !== "" ? detail.from.name : detail.from.address} <${detail.from.address}>`
1024
+ { className: "who" },
1025
+ (0, import_react6.createElement)(Avatar, { email: detail.from.address, size: 22 }),
1026
+ (0, import_react6.createElement)("strong", null, detail.from.name !== "" ? detail.from.name : detail.from.address),
1027
+ detail.from.name !== "" ? (0, import_react6.createElement)("span", null, `<${detail.from.address}>`) : null
928
1028
  ),
929
- (0, import_react5.createElement)("span", null, longDate(detail.date)),
930
- detail.backedUp === false ? (0, import_react5.createElement)("span", { className: "badge warn" }, "\u672A\u5907\u4EFD") : null
1029
+ (0, import_react6.createElement)("span", null, longDate(detail.date)),
1030
+ detail.backedUp === false ? (0, import_react6.createElement)("span", { className: "badge warn" }, "\u672A\u5907\u4EFD") : null
931
1031
  ),
932
- (0, import_react5.createElement)(
1032
+ (0, import_react6.createElement)(
933
1033
  "div",
934
1034
  { className: "mailharbor-reader-meta" },
935
- (0, import_react5.createElement)(
936
- "span",
937
- null,
938
- `\u6536\u4EF6\u4EBA: ${detail.to.map((item) => item.name !== "" ? `${item.name} <${item.address}>` : item.address).join(", ") || "\u2014"}`
939
- ),
940
- detail.cc.length === 0 ? null : (0, import_react5.createElement)("span", null, `\u6284\u9001: ${detail.cc.map((item) => item.address).join(", ")}`)
1035
+ (0, import_react6.createElement)("span", null, `\u6536\u4EF6\u4EBA: ${addressLine(detail.to) || "\u2014"}`),
1036
+ detail.cc.length === 0 ? null : (0, import_react6.createElement)("span", null, `\u6284\u9001: ${addressLine(detail.cc)}`)
941
1037
  ),
942
- (0, import_react5.createElement)(
1038
+ (0, import_react6.createElement)(
943
1039
  "div",
944
1040
  { className: "mailharbor-reader-actions" },
945
- (0, import_react5.createElement)(
1041
+ (0, import_react6.createElement)(
946
1042
  "button",
947
- {
948
- className: "primary",
949
- onClick: () => {
950
- onReply("reply");
951
- }
952
- },
1043
+ { className: "ghost", onClick: () => onReply("reply") },
1044
+ (0, import_react6.createElement)(Icon, { name: "reply" }),
953
1045
  "\u56DE\u590D"
954
1046
  ),
955
- (0, import_react5.createElement)(
1047
+ (0, import_react6.createElement)(
956
1048
  "button",
957
- {
958
- className: "ghost",
959
- onClick: () => {
960
- onReply("replyAll");
961
- }
962
- },
1049
+ { className: "ghost", onClick: () => onReply("replyAll") },
1050
+ (0, import_react6.createElement)(Icon, { name: "replyAll" }),
963
1051
  "\u5168\u90E8\u56DE\u590D"
964
1052
  ),
965
- (0, import_react5.createElement)(
1053
+ (0, import_react6.createElement)(
966
1054
  "button",
967
- {
968
- className: "ghost",
969
- onClick: () => {
970
- onReply("forward");
971
- }
972
- },
1055
+ { className: "ghost", onClick: () => onReply("forward") },
1056
+ (0, import_react6.createElement)(Icon, { name: "forward" }),
973
1057
  "\u8F6C\u53D1"
974
1058
  ),
975
- (0, import_react5.createElement)("span", { className: "spacer" }),
976
- (0, import_react5.createElement)(
977
- "button",
978
- { className: "ghost", onClick: () => void toggleRead(), disabled: busy },
979
- detail.unread ? "\u6807\u4E3A\u5DF2\u8BFB" : "\u6807\u4E3A\u672A\u8BFB"
980
- ),
981
- html ? (0, import_react5.createElement)(
1059
+ (0, import_react6.createElement)("span", { className: "spacer" }),
1060
+ html ? (0, import_react6.createElement)(
982
1061
  "button",
983
- { className: "ghost", onClick: () => setPlain(!plain) },
984
- plain ? "\u663E\u793A HTML" : "\u663E\u793A\u7EAF\u6587\u672C"
1062
+ { className: "subtle", onClick: () => setPlain(!plain) },
1063
+ plain ? "\u663E\u793A HTML" : "\u7EAF\u6587\u672C"
985
1064
  ) : null,
986
- remoteImages && !loadImages ? (0, import_react5.createElement)("button", { className: "ghost", onClick: () => setLoadImages(true) }, "\u663E\u793A\u8FDC\u7A0B\u56FE\u7247") : null
1065
+ remoteImages && !loadImages ? (0, import_react6.createElement)(
1066
+ "button",
1067
+ { className: "subtle", onClick: () => setLoadImages(true) },
1068
+ (0, import_react6.createElement)(Icon, { name: "image", size: 14 }),
1069
+ "\u663E\u793A\u56FE\u7247"
1070
+ ) : null
987
1071
  ),
988
- error === "" ? null : (0, import_react5.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error)
1072
+ error === "" ? null : (0, import_react6.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error)
989
1073
  ),
990
- (0, import_react5.createElement)(
1074
+ (0, import_react6.createElement)(
991
1075
  "div",
992
1076
  { className: "mailharbor-reader-body" },
993
- html && !plain ? (0, import_react5.createElement)("iframe", {
1077
+ html && !plain ? (0, import_react6.createElement)("iframe", {
994
1078
  title: "\u90AE\u4EF6\u6B63\u6587",
995
1079
  sandbox: "",
996
1080
  srcDoc: srcDoc(detail, loadImages),
997
1081
  referrerPolicy: "no-referrer"
998
- }) : (0, import_react5.createElement)("pre", null, detail.text !== "" ? detail.text : "\uFF08\u65E0\u6B63\u6587\uFF09")
1082
+ }) : (0, import_react6.createElement)("pre", null, detail.text !== "" ? detail.text : "\uFF08\u65E0\u6B63\u6587\uFF09")
999
1083
  ),
1000
- detail.attachments.length === 0 ? null : (0, import_react5.createElement)(
1084
+ detail.attachments.length === 0 ? null : (0, import_react6.createElement)(
1001
1085
  "div",
1002
1086
  { className: "mailharbor-attachments" },
1003
1087
  detail.attachments.map(
1004
- (file) => (0, import_react5.createElement)(
1088
+ (file) => (0, import_react6.createElement)(
1005
1089
  "a",
1006
1090
  {
1007
1091
  className: "mailharbor-attachment",
@@ -1018,10 +1102,12 @@ function Reader({
1018
1102
  emailId: detail.id,
1019
1103
  attachmentId: file.id
1020
1104
  }),
1021
- download: file.filename
1105
+ download: file.filename,
1106
+ title: file.filename
1022
1107
  },
1023
- (0, import_react5.createElement)("span", { className: "name" }, file.filename),
1024
- (0, import_react5.createElement)("span", { className: "muted small" }, formatBytes(file.size))
1108
+ (0, import_react6.createElement)(Icon, { name: "paperclip", size: 14 }),
1109
+ (0, import_react6.createElement)("span", { className: "name" }, file.filename),
1110
+ (0, import_react6.createElement)("span", { className: "muted small" }, formatBytes(file.size))
1025
1111
  )
1026
1112
  )
1027
1113
  )
@@ -1033,44 +1119,50 @@ var EMPTY_PAGE = { items: [], total: 0, offset: 0, limit: 40 };
1033
1119
  function errorText3(error) {
1034
1120
  return error instanceof ApiError || error instanceof Error ? error.message : String(error);
1035
1121
  }
1122
+ function matchesNarrow() {
1123
+ return typeof window.matchMedia === "function" ? window.matchMedia("(max-width: 900px)").matches : false;
1124
+ }
1036
1125
  function quoteForReply(detail) {
1037
1126
  const body = detail.html ?? `<pre>${detail.text.replaceAll("&", "&amp;").replaceAll("<", "&lt;")}</pre>`;
1038
1127
  return `<p><br></p><p>------------------ \u539F\u59CB\u90AE\u4EF6 ------------------</p><blockquote style="margin:0 0 0 12px;padding-left:12px;border-left:2px solid #d7dbe3;color:#565c67">${body}</blockquote>`;
1039
1128
  }
1040
1129
  function MailPanel() {
1041
- const [state, setState] = (0, import_react6.useState)(null);
1042
- const [error, setError] = (0, import_react6.useState)("");
1043
- const [source, setSource] = (0, import_react6.useState)("local");
1044
- const [mailbox, setMailbox] = (0, import_react6.useState)("all");
1045
- const [folders, setFolders] = (0, import_react6.useState)([]);
1046
- const [query2, setQuery] = (0, import_react6.useState)("");
1047
- const [search, setSearch] = (0, import_react6.useState)("");
1048
- const [page, setPage] = (0, import_react6.useState)(EMPTY_PAGE);
1049
- const [limit, setLimit] = (0, import_react6.useState)(40);
1050
- const [loading, setLoading] = (0, import_react6.useState)(false);
1051
- const [selected, setSelected] = (0, import_react6.useState)(null);
1052
- const [compose, setCompose] = (0, import_react6.useState)(null);
1053
- const [showAdd, setShowAdd] = (0, import_react6.useState)(false);
1054
- const [showBackup, setShowBackup] = (0, import_react6.useState)(false);
1055
- const [backup, setBackup] = (0, import_react6.useState)(null);
1056
- const [toast, setToast] = (0, import_react6.useState)("");
1057
- const [narrow, setNarrow] = (0, import_react6.useState)(() => window.matchMedia("(max-width: 900px)").matches);
1058
- const [tick, setTick] = (0, import_react6.useState)(0);
1130
+ const [state, setState] = (0, import_react7.useState)(null);
1131
+ const [error, setError] = (0, import_react7.useState)("");
1132
+ const [source, setSource] = (0, import_react7.useState)("local");
1133
+ const [mailbox, setMailbox] = (0, import_react7.useState)("all");
1134
+ const [folders, setFolders] = (0, import_react7.useState)([]);
1135
+ const [query2, setQuery] = (0, import_react7.useState)("");
1136
+ const [search, setSearch] = (0, import_react7.useState)("");
1137
+ const [page, setPage] = (0, import_react7.useState)(EMPTY_PAGE);
1138
+ const [limit, setLimit] = (0, import_react7.useState)(40);
1139
+ const [loading, setLoading] = (0, import_react7.useState)(false);
1140
+ const [selected, setSelected] = (0, import_react7.useState)(null);
1141
+ const [compose, setCompose] = (0, import_react7.useState)(null);
1142
+ const [showAdd, setShowAdd] = (0, import_react7.useState)(false);
1143
+ const [showBackup, setShowBackup] = (0, import_react7.useState)(false);
1144
+ const [backup, setBackup] = (0, import_react7.useState)(null);
1145
+ const [toast, setToast] = (0, import_react7.useState)("");
1146
+ const [narrow, setNarrow] = (0, import_react7.useState)(() => matchesNarrow());
1147
+ const [tick, setTick] = (0, import_react7.useState)(0);
1059
1148
  const account = state?.accounts.find((item) => item.id === state.activeAccountId) ?? null;
1060
1149
  const accountId = account?.id ?? null;
1061
- const refresh = (0, import_react6.useCallback)(() => {
1150
+ const refresh = (0, import_react7.useCallback)(() => {
1062
1151
  setTick((value) => value + 1);
1063
1152
  }, []);
1064
- const notice = (0, import_react6.useCallback)((message) => {
1153
+ const notice = (0, import_react7.useCallback)((message) => {
1065
1154
  setToast(message);
1066
1155
  window.setTimeout(() => {
1067
1156
  setToast("");
1068
1157
  }, 3200);
1069
1158
  }, []);
1070
- (0, import_react6.useEffect)(() => {
1159
+ (0, import_react7.useEffect)(() => {
1071
1160
  let cancelled = false;
1072
1161
  api.state().then((next) => {
1073
- if (!cancelled) setState(next);
1162
+ if (!cancelled) {
1163
+ setState(next);
1164
+ if (next.settings.render.listLimit > 0) setLimit(next.settings.render.listLimit);
1165
+ }
1074
1166
  }).catch((caught) => {
1075
1167
  if (!cancelled) setError(errorText3(caught));
1076
1168
  });
@@ -1078,12 +1170,12 @@ function MailPanel() {
1078
1170
  cancelled = true;
1079
1171
  };
1080
1172
  }, [tick]);
1081
- (0, import_react6.useEffect)(() => {
1173
+ (0, import_react7.useEffect)(() => {
1082
1174
  if (accountId === null) return;
1083
1175
  let cancelled = false;
1084
1176
  api.folders({ accountId, source }).then((result) => {
1085
1177
  if (cancelled) return;
1086
- const items = source === "local" ? [
1178
+ const items2 = source === "local" ? [
1087
1179
  {
1088
1180
  name: "all",
1089
1181
  label: "\u5168\u90E8\u90AE\u4EF6",
@@ -1091,7 +1183,7 @@ function MailPanel() {
1091
1183
  },
1092
1184
  ...result.items.map((item) => ({ ...item, label: item.label ?? item.name }))
1093
1185
  ] : result.items.map((item) => ({ ...item, label: item.label ?? item.name }));
1094
- setFolders(items);
1186
+ setFolders(items2);
1095
1187
  }).catch(() => {
1096
1188
  if (!cancelled) setFolders([]);
1097
1189
  });
@@ -1099,12 +1191,11 @@ function MailPanel() {
1099
1191
  cancelled = true;
1100
1192
  };
1101
1193
  }, [accountId, source, tick]);
1102
- (0, import_react6.useEffect)(() => {
1194
+ (0, import_react7.useEffect)(() => {
1103
1195
  setMailbox(source === "local" ? "all" : "INBOX");
1104
1196
  setSelected(null);
1105
- setLimit(state?.settings.render.listLimit ?? 40);
1106
1197
  }, [source]);
1107
- (0, import_react6.useEffect)(() => {
1198
+ (0, import_react7.useEffect)(() => {
1108
1199
  if (accountId === null) return;
1109
1200
  let cancelled = false;
1110
1201
  setLoading(true);
@@ -1119,7 +1210,8 @@ function MailPanel() {
1119
1210
  cancelled = true;
1120
1211
  };
1121
1212
  }, [accountId, source, mailbox, search, limit, tick]);
1122
- (0, import_react6.useEffect)(() => {
1213
+ (0, import_react7.useEffect)(() => {
1214
+ if (typeof window.matchMedia !== "function") return;
1123
1215
  const media = window.matchMedia("(max-width: 900px)");
1124
1216
  const onChange = () => setNarrow(media.matches);
1125
1217
  media.addEventListener("change", onChange);
@@ -1127,7 +1219,7 @@ function MailPanel() {
1127
1219
  media.removeEventListener("change", onChange);
1128
1220
  };
1129
1221
  }, []);
1130
- (0, import_react6.useEffect)(() => {
1222
+ (0, import_react7.useEffect)(() => {
1131
1223
  if (!showBackup || accountId === null) return;
1132
1224
  let cancelled = false;
1133
1225
  const poll = async () => {
@@ -1228,32 +1320,35 @@ function MailPanel() {
1228
1320
  setError(errorText3(caught));
1229
1321
  }
1230
1322
  };
1231
- const folderOptions = (0, import_react6.useMemo)(
1323
+ const folderOptions = (0, import_react7.useMemo)(
1232
1324
  () => folders.map((folder) => ({
1233
1325
  value: folder.name,
1234
1326
  label: `${folder.label ?? folder.name}${folder.count > 0 ? ` (${String(folder.count)})` : ""}`
1235
1327
  })),
1236
1328
  [folders]
1237
1329
  );
1238
- const unreadCount = page.items.filter((item) => item.unread).length;
1239
1330
  if (state === null) {
1240
- return (0, import_react6.createElement)("div", { className: "mailharbor mailharbor-empty" }, error === "" ? "\u6B63\u5728\u52A0\u8F7D\u90AE\u7BB1\u2026" : error);
1331
+ return (0, import_react7.createElement)(
1332
+ "div",
1333
+ { className: "mailharbor" },
1334
+ (0, import_react7.createElement)("div", { className: "mailharbor-empty" }, error === "" ? "\u6B63\u5728\u52A0\u8F7D\u90AE\u7BB1\u2026" : error)
1335
+ );
1241
1336
  }
1242
1337
  if (account === null) {
1243
- return (0, import_react6.createElement)(
1338
+ return (0, import_react7.createElement)(
1244
1339
  "div",
1245
1340
  { className: "mailharbor" },
1246
- (0, import_react6.createElement)(
1341
+ (0, import_react7.createElement)(
1247
1342
  "div",
1248
1343
  { className: "mailharbor-settings" },
1249
- (0, import_react6.createElement)("h2", null, "\u6B22\u8FCE\u4F7F\u7528 MailHarbor"),
1250
- (0, import_react6.createElement)(
1344
+ (0, import_react7.createElement)("h2", null, "\u6B22\u8FCE\u4F7F\u7528 MailHarbor"),
1345
+ (0, import_react7.createElement)(
1251
1346
  "p",
1252
1347
  { className: "muted small" },
1253
- "\u628A\u4EFB\u610F IMAP/SMTP \u90AE\u7BB1\u63A5\u8FDB DeepSeek Harness\uFF1A\u672C\u5730\u5907\u4EFD\u3001\u5B9E\u65F6\u8BFB\u4FE1\u3001\u5199\u90AE\u4EF6\u3001AI \u4E0E\u4EFB\u52A1\u3002"
1348
+ "\u628A\u4EFB\u610F IMAP/SMTP \u90AE\u7BB1\u63A5\u8FDB DeepSeek Harness\uFF1A\u672C\u5730\u5907\u4EFD\u3001\u5B9E\u65F6\u8BFB\u4FE1\u3001\u5199\u90AE\u4EF6\u4E0E Agent \u5DE5\u5177\u3002"
1254
1349
  ),
1255
- error === "" ? null : (0, import_react6.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error),
1256
- (0, import_react6.createElement)(AddAccountForm, {
1350
+ error === "" ? null : (0, import_react7.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error),
1351
+ (0, import_react7.createElement)(AddAccountForm, {
1257
1352
  onDone: (next) => {
1258
1353
  setState(next);
1259
1354
  setSource("local");
@@ -1263,64 +1358,83 @@ function MailPanel() {
1263
1358
  );
1264
1359
  }
1265
1360
  const needsLogin = source === "server" && state.loggedIn === false;
1266
- return (0, import_react6.createElement)(
1361
+ const items = page.items;
1362
+ return (0, import_react7.createElement)(
1267
1363
  "div",
1268
1364
  { className: narrow ? "mailharbor mailharbor-narrow" : "mailharbor" },
1269
- (0, import_react6.createElement)(
1365
+ (0, import_react7.createElement)(
1270
1366
  "div",
1271
1367
  { className: "mailharbor-topbar" },
1272
- (0, import_react6.createElement)(Avatar, { email: account.email, size: 26 }),
1273
- state.accounts.length > 1 ? (0, import_react6.createElement)(
1274
- "select",
1275
- {
1276
- value: account.id,
1277
- onChange: (event) => void switchAccount(event.target.value),
1278
- "aria-label": "\u8D26\u53F7"
1279
- },
1280
- state.accounts.map((item) => (0, import_react6.createElement)("option", { key: item.id, value: item.id }, item.label))
1281
- ) : (0, import_react6.createElement)("span", { className: "small" }, account.label),
1282
- (0, import_react6.createElement)(
1368
+ (0, import_react7.createElement)(
1369
+ "div",
1370
+ { className: "mailharbor-account" },
1371
+ (0, import_react7.createElement)(Avatar, { email: account.email, size: 26 }),
1372
+ state.accounts.length > 1 ? (0, import_react7.createElement)(
1373
+ "select",
1374
+ {
1375
+ value: account.id,
1376
+ onChange: (event) => void switchAccount(event.target.value),
1377
+ "aria-label": "\u8D26\u53F7"
1378
+ },
1379
+ state.accounts.map((item) => (0, import_react7.createElement)("option", { key: item.id, value: item.id }, item.label))
1380
+ ) : (0, import_react7.createElement)("span", { className: "name" }, account.label),
1381
+ state.loggedIn === false ? (0, import_react7.createElement)("span", { className: "badge warn" }, "\u672A\u767B\u5F55") : null
1382
+ ),
1383
+ (0, import_react7.createElement)(
1283
1384
  "div",
1284
1385
  { className: "mailharbor-segment", role: "tablist" },
1285
- (0, import_react6.createElement)(
1386
+ (0, import_react7.createElement)(
1286
1387
  "button",
1287
1388
  { className: source === "local" ? "active" : "", onClick: () => setSource("local"), role: "tab" },
1288
1389
  "\u672C\u5730\u5907\u4EFD"
1289
1390
  ),
1290
- (0, import_react6.createElement)(
1391
+ (0, import_react7.createElement)(
1291
1392
  "button",
1292
1393
  { className: source === "server" ? "active" : "", onClick: () => setSource("server"), role: "tab" },
1293
1394
  "\u670D\u52A1\u5668\u5B9E\u65F6"
1294
1395
  )
1295
1396
  ),
1296
- (0, import_react6.createElement)("span", { className: "spacer" }),
1297
- state.loggedIn === false ? (0, import_react6.createElement)("span", { className: "badge warn" }, "\u672A\u767B\u5F55") : null,
1298
- (0, import_react6.createElement)("button", { className: "ghost", onClick: () => setShowAdd(true), title: "\u6DFB\u52A0\u8D26\u53F7" }, "+ \u8D26\u53F7"),
1299
- (0, import_react6.createElement)("button", { className: "primary", onClick: () => startCompose("new") }, "\u5199\u90AE\u4EF6"),
1300
- (0, import_react6.createElement)("button", { className: "ghost", onClick: () => void startBackup() }, "\u5907\u4EFD"),
1301
- (0, import_react6.createElement)(
1397
+ (0, import_react7.createElement)("span", { className: "spacer" }),
1398
+ (0, import_react7.createElement)(
1302
1399
  "button",
1303
1400
  {
1304
- className: "ghost",
1305
- onClick: () => {
1306
- refresh();
1307
- }
1401
+ className: "ghost icon",
1402
+ title: "\u6DFB\u52A0\u8D26\u53F7",
1403
+ "aria-label": "\u6DFB\u52A0\u8D26\u53F7",
1404
+ onClick: () => setShowAdd(true)
1308
1405
  },
1309
- "\u5237\u65B0"
1406
+ (0, import_react7.createElement)(Icon, { name: "plus" })
1407
+ ),
1408
+ (0, import_react7.createElement)(
1409
+ "button",
1410
+ { className: "ghost icon", title: "\u5237\u65B0\u5217\u8868", "aria-label": "\u5237\u65B0\u5217\u8868", onClick: refresh },
1411
+ (0, import_react7.createElement)(Icon, { name: "refresh" })
1412
+ ),
1413
+ (0, import_react7.createElement)(
1414
+ "button",
1415
+ { className: "ghost", onClick: () => void startBackup() },
1416
+ (0, import_react7.createElement)(Icon, { name: "archive" }),
1417
+ "\u5907\u4EFD"
1418
+ ),
1419
+ (0, import_react7.createElement)(
1420
+ "button",
1421
+ { className: "primary", onClick: () => startCompose("new") },
1422
+ (0, import_react7.createElement)(Icon, { name: "compose" }),
1423
+ "\u5199\u90AE\u4EF6"
1310
1424
  )
1311
1425
  ),
1312
- toast === "" ? null : (0, import_react6.createElement)("div", { className: "small", style: { padding: "6px 12px", color: "var(--m-ok)" } }, toast),
1313
- error === "" ? null : (0, import_react6.createElement)(ErrorBar, { message: error, onDismiss: () => setError("") }),
1314
- needsLogin ? (0, import_react6.createElement)("div", { className: "mailharbor-settings" }, (0, import_react6.createElement)(LoginForm, { account, onDone: refresh })) : (0, import_react6.createElement)(
1426
+ toast === "" ? null : (0, import_react7.createElement)("div", { className: "small", style: { padding: "6px 14px", color: "var(--m-ok)" } }, toast),
1427
+ error === "" ? null : (0, import_react7.createElement)(ErrorBar, { message: error, onDismiss: () => setError("") }),
1428
+ needsLogin ? (0, import_react7.createElement)("div", { className: "mailharbor-settings" }, (0, import_react7.createElement)(LoginForm, { account, onDone: refresh })) : (0, import_react7.createElement)(
1315
1429
  "div",
1316
1430
  { className: "mailharbor-body", "data-mode": narrow && selected !== null ? "reader" : "list" },
1317
- (0, import_react6.createElement)(
1431
+ (0, import_react7.createElement)(
1318
1432
  "div",
1319
1433
  { className: "mailharbor-list" },
1320
- (0, import_react6.createElement)(
1434
+ (0, import_react7.createElement)(
1321
1435
  "div",
1322
1436
  { className: "mailharbor-filters" },
1323
- (0, import_react6.createElement)(
1437
+ (0, import_react7.createElement)(
1324
1438
  "select",
1325
1439
  {
1326
1440
  value: mailbox,
@@ -1331,12 +1445,13 @@ function MailPanel() {
1331
1445
  "aria-label": "\u90AE\u7BB1\u6587\u4EF6\u5939"
1332
1446
  },
1333
1447
  folderOptions.map(
1334
- (option) => (0, import_react6.createElement)("option", { key: option.value, value: option.value }, option.label)
1448
+ (option) => (0, import_react7.createElement)("option", { key: option.value, value: option.value }, option.label)
1335
1449
  )
1336
1450
  ),
1337
- (0, import_react6.createElement)("input", {
1451
+ (0, import_react7.createElement)("input", {
1338
1452
  type: "search",
1339
1453
  placeholder: "\u641C\u7D22\u90AE\u4EF6",
1454
+ "aria-label": "\u641C\u7D22\u90AE\u4EF6",
1340
1455
  value: query2,
1341
1456
  onChange: (event) => setQuery(event.target.value),
1342
1457
  onKeyDown: (event) => {
@@ -1347,78 +1462,96 @@ function MailPanel() {
1347
1462
  }
1348
1463
  }
1349
1464
  }),
1350
- query2 !== search || search !== "" ? (0, import_react6.createElement)(
1465
+ query2 !== search || search !== "" ? (0, import_react7.createElement)(
1351
1466
  "button",
1352
1467
  {
1353
- className: "subtle small",
1468
+ className: "subtle",
1469
+ title: "\u6E05\u9664\u641C\u7D22",
1354
1470
  onClick: () => {
1355
1471
  setQuery("");
1356
1472
  setSearch("");
1357
1473
  }
1358
1474
  },
1359
- "\u6E05\u9664"
1475
+ (0, import_react7.createElement)(Icon, { name: "close", size: 14 })
1360
1476
  ) : null
1361
1477
  ),
1362
- (0, import_react6.createElement)(
1478
+ (0, import_react7.createElement)(
1363
1479
  "div",
1364
1480
  { className: "mailharbor-rows" },
1365
- loading && page.items.length === 0 ? (0, import_react6.createElement)("div", { className: "mailharbor-empty" }, "\u6B63\u5728\u8BFB\u53D6\u2026") : page.items.length === 0 ? (0, import_react6.createElement)(
1481
+ loading && items.length === 0 ? (0, import_react7.createElement)("div", { className: "mailharbor-empty" }, "\u6B63\u5728\u8BFB\u53D6\u2026") : items.length === 0 ? (0, import_react7.createElement)(
1366
1482
  "div",
1367
1483
  { className: "mailharbor-empty" },
1368
- source === "local" ? "\u672C\u5730\u5907\u4EFD\u91CC\u8FD8\u6CA1\u6709\u90AE\u4EF6\u3002\u70B9\u9876\u90E8\u300C\u5907\u4EFD\u300D\u628A\u670D\u52A1\u5668\u90AE\u4EF6\u540C\u6B65\u4E0B\u6765\u3002" : "\u670D\u52A1\u5668\u4E0A\u6CA1\u6709\u90AE\u4EF6\u3002"
1369
- ) : page.items.map(
1370
- (item) => (0, import_react6.createElement)(
1371
- "button",
1484
+ (0, import_react7.createElement)(Icon, { name: "mail", size: 28 }),
1485
+ (0, import_react7.createElement)(
1486
+ "div",
1487
+ { className: "title" },
1488
+ source === "local" ? "\u672C\u5730\u5907\u4EFD\u91CC\u8FD8\u6CA1\u6709\u90AE\u4EF6" : "\u670D\u52A1\u5668\u4E0A\u6CA1\u6709\u90AE\u4EF6"
1489
+ ),
1490
+ (0, import_react7.createElement)(
1491
+ "div",
1492
+ { className: "small" },
1493
+ 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"
1494
+ )
1495
+ ) : items.map(
1496
+ (item) => (0, import_react7.createElement)(
1497
+ "div",
1372
1498
  {
1373
1499
  key: item.id,
1374
1500
  className: `mailharbor-row${item.unread ? " unread" : ""}${selected?.id === item.id ? " selected" : ""}`,
1375
- onClick: () => void openMessage(item)
1501
+ role: "button",
1502
+ tabIndex: 0,
1503
+ onClick: () => void openMessage(item),
1504
+ onKeyDown: (event) => {
1505
+ if (event.key === "Enter" || event.key === " ") {
1506
+ event.preventDefault();
1507
+ void openMessage(item);
1508
+ }
1509
+ }
1376
1510
  },
1377
- (0, import_react6.createElement)(
1511
+ (0, import_react7.createElement)(
1378
1512
  "span",
1379
1513
  { className: "line-1" },
1380
- (0, import_react6.createElement)(
1514
+ item.unread ? (0, import_react7.createElement)("span", { className: "dot" }) : null,
1515
+ (0, import_react7.createElement)(
1381
1516
  "span",
1382
1517
  { className: "from" },
1383
1518
  item.from.name !== "" ? item.from.name : item.from.address
1384
1519
  ),
1385
- item.backedUp === false ? (0, import_react6.createElement)("span", { className: "badge warn" }, "\u672A\u5907\u4EFD") : null,
1386
- (0, import_react6.createElement)("span", { className: "date" }, shortDate(item.date))
1520
+ item.hasAttachments ? (0, import_react7.createElement)(Icon, { name: "paperclip", size: 13 }) : null,
1521
+ item.backedUp === false ? (0, import_react7.createElement)("span", { className: "badge warn" }, "\u672A\u5907\u4EFD") : null,
1522
+ (0, import_react7.createElement)("span", { className: "date" }, shortDate(item.date))
1387
1523
  ),
1388
- (0, import_react6.createElement)("span", { className: "line-2" }, (0, import_react6.createElement)("span", { className: "subject" }, item.subject)),
1389
- item.snippet === "" ? null : (0, import_react6.createElement)("span", { className: "snippet" }, item.snippet)
1524
+ (0, import_react7.createElement)("span", { className: "line-2" }, (0, import_react7.createElement)("span", { className: "subject" }, item.subject)),
1525
+ item.snippet === "" ? null : (0, import_react7.createElement)("span", { className: "snippet" }, item.snippet)
1390
1526
  )
1391
- ),
1392
- page.items.length > 0 ? (0, import_react6.createElement)(
1393
- "div",
1394
- { style: { padding: "10px 12px", display: "flex", gap: "8px", alignItems: "center" } },
1395
- (0, import_react6.createElement)(
1396
- "span",
1397
- { className: "small muted" },
1398
- `${String(page.items.length)} / ${String(page.total)} \u5C01${unreadCount > 0 ? ` \xB7 ${String(unreadCount)} \u672A\u8BFB` : ""}`
1399
- ),
1400
- (0, import_react6.createElement)("span", { className: "spacer" }),
1401
- page.total > page.items.length ? (0, import_react6.createElement)(
1402
- "button",
1403
- { className: "subtle small", onClick: () => setLimit((current) => current + 40) },
1404
- "\u52A0\u8F7D\u66F4\u591A"
1405
- ) : null
1527
+ )
1528
+ ),
1529
+ items.length > 0 ? (0, import_react7.createElement)(
1530
+ "div",
1531
+ { className: "mailharbor-list-foot" },
1532
+ (0, import_react7.createElement)("span", null, `${String(items.length)} / ${String(page.total)} \u5C01`),
1533
+ (0, import_react7.createElement)("span", { className: "spacer" }),
1534
+ page.total > items.length ? (0, import_react7.createElement)(
1535
+ "button",
1536
+ { className: "subtle", onClick: () => setLimit((current) => current + 40) },
1537
+ "\u52A0\u8F7D\u66F4\u591A"
1406
1538
  ) : null
1407
- )
1539
+ ) : null
1408
1540
  ),
1409
- (0, import_react6.createElement)(
1541
+ (0, import_react7.createElement)(
1410
1542
  "div",
1411
1543
  { className: "mailharbor-reader" },
1412
- selected === null ? (0, import_react6.createElement)(
1544
+ selected === null ? (0, import_react7.createElement)(
1413
1545
  "div",
1414
1546
  { className: "mailharbor-empty" },
1415
- (0, import_react6.createElement)("p", null, "\u4ECE\u5DE6\u4FA7\u9009\u62E9\u4E00\u5C01\u90AE\u4EF6"),
1416
- (0, import_react6.createElement)(
1417
- "p",
1547
+ (0, import_react7.createElement)(Icon, { name: "mail", size: 34 }),
1548
+ (0, import_react7.createElement)("div", { className: "title" }, "\u9009\u62E9\u4E00\u5C01\u90AE\u4EF6\u5F00\u59CB\u9605\u8BFB"),
1549
+ (0, import_react7.createElement)(
1550
+ "div",
1418
1551
  { className: "small" },
1419
1552
  state.loggedIn ? "\u5DF2\u767B\u5F55\uFF0C\u53EF\u5207\u6362\u300C\u670D\u52A1\u5668\u5B9E\u65F6\u300D\u67E5\u770B\u6700\u65B0\u90AE\u4EF6\u3002" : "\u6D4F\u89C8\u672C\u5730\u5907\u4EFD\u4E0D\u9700\u8981\u767B\u5F55\u3002"
1420
1553
  )
1421
- ) : (0, import_react6.createElement)(Reader, {
1554
+ ) : (0, import_react7.createElement)(Reader, {
1422
1555
  detail: selected,
1423
1556
  account,
1424
1557
  source,
@@ -1429,45 +1562,45 @@ function MailPanel() {
1429
1562
  })
1430
1563
  )
1431
1564
  ),
1432
- showBackup && backup !== null ? (0, import_react6.createElement)(
1565
+ showBackup && backup !== null ? (0, import_react7.createElement)(
1433
1566
  Modal,
1434
1567
  {
1435
1568
  title: "\u5907\u4EFD",
1436
1569
  onClose: () => setShowBackup(false),
1437
- footer: (0, import_react6.createElement)(
1570
+ footer: (0, import_react7.createElement)(
1438
1571
  "div",
1439
1572
  { style: { display: "flex", gap: "8px", width: "100%", alignItems: "center" } },
1440
- (0, import_react6.createElement)("span", { className: "small muted" }, backup.running ? "\u5907\u4EFD\u8FDB\u884C\u4E2D\u2026" : backup.message),
1441
- (0, import_react6.createElement)("span", { className: "spacer" }),
1442
- backup.running ? (0, import_react6.createElement)("button", { className: "danger ghost", onClick: () => void stopBackup() }, "\u505C\u6B62\u5907\u4EFD") : (0, import_react6.createElement)("button", { className: "primary", onClick: () => void startBackup() }, "\u5F00\u59CB\u5907\u4EFD"),
1443
- (0, import_react6.createElement)("button", { className: "ghost", onClick: () => setShowBackup(false) }, "\u5173\u95ED")
1573
+ (0, import_react7.createElement)("span", { className: "small muted" }, backup.running ? "\u5907\u4EFD\u8FDB\u884C\u4E2D\u2026" : backup.message),
1574
+ (0, import_react7.createElement)("span", { className: "spacer" }),
1575
+ backup.running ? (0, import_react7.createElement)("button", { className: "ghost danger", onClick: () => void stopBackup() }, "\u505C\u6B62\u5907\u4EFD") : (0, import_react7.createElement)("button", { className: "primary", onClick: () => void startBackup() }, "\u5F00\u59CB\u5907\u4EFD"),
1576
+ (0, import_react7.createElement)("button", { className: "ghost", onClick: () => setShowBackup(false) }, "\u5173\u95ED")
1444
1577
  )
1445
1578
  },
1446
- (0, import_react6.createElement)(
1579
+ (0, import_react7.createElement)(
1447
1580
  "div",
1448
1581
  { className: "mailharbor-kv" },
1449
- (0, import_react6.createElement)("dt", null, "\u5F00\u59CB\u65F6\u95F4"),
1450
- (0, import_react6.createElement)("dd", null, backup.startedAt ?? "\u2014"),
1451
- (0, import_react6.createElement)("dt", null, "\u4E0A\u6B21\u6210\u529F"),
1452
- (0, import_react6.createElement)("dd", null, backup.lastSuccessAt ?? "\u2014"),
1453
- (0, import_react6.createElement)("dt", null, "\u65B0\u589E"),
1454
- (0, import_react6.createElement)("dd", null, String(backup.added)),
1455
- (0, import_react6.createElement)("dt", null, "\u603B\u6570"),
1456
- (0, import_react6.createElement)("dd", null, String(backup.total))
1582
+ (0, import_react7.createElement)("dt", null, "\u5F00\u59CB\u65F6\u95F4"),
1583
+ (0, import_react7.createElement)("dd", null, backup.startedAt ?? "\u2014"),
1584
+ (0, import_react7.createElement)("dt", null, "\u4E0A\u6B21\u6210\u529F"),
1585
+ (0, import_react7.createElement)("dd", null, backup.lastSuccessAt ?? "\u2014"),
1586
+ (0, import_react7.createElement)("dt", null, "\u65B0\u589E"),
1587
+ (0, import_react7.createElement)("dd", null, String(backup.added)),
1588
+ (0, import_react7.createElement)("dt", null, "\u603B\u6570"),
1589
+ (0, import_react7.createElement)("dd", null, String(backup.total))
1457
1590
  ),
1458
- (0, import_react6.createElement)(
1591
+ (0, import_react7.createElement)(
1459
1592
  "div",
1460
1593
  { className: "mailharbor-log" },
1461
1594
  backup.output.length === 0 ? "\uFF08\u7B49\u5F85\u8F93\u51FA\u2026\uFF09" : backup.output.join("\n")
1462
1595
  )
1463
1596
  ) : null,
1464
- compose !== null ? (0, import_react6.createElement)(Composer, {
1597
+ compose !== null ? (0, import_react7.createElement)(Composer, {
1465
1598
  account,
1466
1599
  initial: compose,
1467
1600
  onClose: () => setCompose(null),
1468
1601
  onSent: (message) => notice(message)
1469
1602
  }) : null,
1470
- showAdd ? (0, import_react6.createElement)(AddAccountModal, {
1603
+ showAdd ? (0, import_react7.createElement)(AddAccountModal, {
1471
1604
  onClose: () => setShowAdd(false),
1472
1605
  onDone: (next) => {
1473
1606
  setState(next);
@@ -1478,27 +1611,27 @@ function MailPanel() {
1478
1611
  }
1479
1612
 
1480
1613
  // src/client/settings.tsx
1481
- var import_react7 = require("react");
1614
+ var import_react8 = require("react");
1482
1615
  function errorText4(error) {
1483
1616
  return error instanceof ApiError || error instanceof Error ? error.message : String(error);
1484
1617
  }
1485
1618
  function MailSettings() {
1486
- const [state, setState] = (0, import_react7.useState)(null);
1487
- const [settings, setSettings] = (0, import_react7.useState)(null);
1488
- const [error, setError] = (0, import_react7.useState)("");
1489
- const [toast, setToast] = (0, import_react7.useState)("");
1490
- const [signature, setSignature] = (0, import_react7.useState)("");
1491
- const [markOnOpen, setMarkOnOpen] = (0, import_react7.useState)(true);
1492
- const [pollSeconds, setPollSeconds] = (0, import_react7.useState)(60);
1493
- const [listLimit, setListLimit] = (0, import_react7.useState)(40);
1494
- const [aiEnabled, setAiEnabled] = (0, import_react7.useState)(true);
1495
- const [aiProvider, setAiProvider] = (0, import_react7.useState)("deepseek-account");
1496
- const [aiModel, setAiModel] = (0, import_react7.useState)("deepseek-flash");
1497
- const [editing, setEditing] = (0, import_react7.useState)(null);
1498
- const [checkResult, setCheckResult] = (0, import_react7.useState)("");
1499
- const [adding, setAdding] = (0, import_react7.useState)(false);
1500
- const [tick, setTick] = (0, import_react7.useState)(0);
1501
- (0, import_react7.useEffect)(() => {
1619
+ const [state, setState] = (0, import_react8.useState)(null);
1620
+ const [settings, setSettings] = (0, import_react8.useState)(null);
1621
+ const [error, setError] = (0, import_react8.useState)("");
1622
+ const [toast, setToast] = (0, import_react8.useState)("");
1623
+ const [signature, setSignature] = (0, import_react8.useState)("");
1624
+ const [markOnOpen, setMarkOnOpen] = (0, import_react8.useState)(true);
1625
+ const [pollSeconds, setPollSeconds] = (0, import_react8.useState)(60);
1626
+ const [listLimit, setListLimit] = (0, import_react8.useState)(40);
1627
+ const [aiEnabled, setAiEnabled] = (0, import_react8.useState)(true);
1628
+ const [aiProvider, setAiProvider] = (0, import_react8.useState)("deepseek-account");
1629
+ const [aiModel, setAiModel] = (0, import_react8.useState)("deepseek-flash");
1630
+ const [editing, setEditing] = (0, import_react8.useState)(null);
1631
+ const [checkResult, setCheckResult] = (0, import_react8.useState)("");
1632
+ const [adding, setAdding] = (0, import_react8.useState)(false);
1633
+ const [tick, setTick] = (0, import_react8.useState)(0);
1634
+ (0, import_react8.useEffect)(() => {
1502
1635
  let cancelled = false;
1503
1636
  Promise.all([api.state(), api.settings()]).then(([appState, view]) => {
1504
1637
  if (cancelled) return;
@@ -1536,24 +1669,24 @@ function MailSettings() {
1536
1669
  };
1537
1670
  const account = settings?.accounts.find((item) => item.id === settings.activeAccountId) ?? null;
1538
1671
  if (state === null || settings === null) {
1539
- return (0, import_react7.createElement)("div", { className: "mailharbor mailharbor-settings" }, error === "" ? "\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026" : error);
1672
+ return (0, import_react8.createElement)("div", { className: "mailharbor mailharbor-settings" }, error === "" ? "\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026" : error);
1540
1673
  }
1541
- return (0, import_react7.createElement)(
1674
+ return (0, import_react8.createElement)(
1542
1675
  "div",
1543
1676
  { className: "mailharbor" },
1544
- (0, import_react7.createElement)(
1677
+ (0, import_react8.createElement)(
1545
1678
  "div",
1546
1679
  { className: "mailharbor-settings" },
1547
- (0, import_react7.createElement)("h2", null, "MailHarbor"),
1548
- (0, import_react7.createElement)("p", { className: "small muted" }, "\u591A\u8D26\u53F7 IMAP/SMTP \u90AE\u7BB1\u3001\u672C\u5730\u5907\u4EFD\u3001AI \u4E0E\u4EFB\u52A1\u3002\u8BBE\u7F6E\u4F1A\u7ACB\u5373\u751F\u6548\u3002"),
1549
- toast === "" ? null : (0, import_react7.createElement)("div", { className: "small", style: { color: "var(--m-ok)" } }, toast),
1550
- error === "" ? null : (0, import_react7.createElement)(ErrorBar, { message: error, onDismiss: () => setError("") }),
1551
- (0, import_react7.createElement)(
1680
+ (0, import_react8.createElement)("h2", null, "MailHarbor"),
1681
+ (0, import_react8.createElement)("p", { className: "small muted" }, "\u591A\u8D26\u53F7 IMAP/SMTP \u90AE\u7BB1\u3001\u672C\u5730\u5907\u4EFD\u3001AI \u4E0E\u4EFB\u52A1\u3002\u8BBE\u7F6E\u4F1A\u7ACB\u5373\u751F\u6548\u3002"),
1682
+ toast === "" ? null : (0, import_react8.createElement)("div", { className: "small", style: { color: "var(--m-ok)" } }, toast),
1683
+ error === "" ? null : (0, import_react8.createElement)(ErrorBar, { message: error, onDismiss: () => setError("") }),
1684
+ (0, import_react8.createElement)(
1552
1685
  "div",
1553
1686
  { className: "mailharbor-card" },
1554
- (0, import_react7.createElement)("h3", null, "\u8D26\u53F7"),
1555
- settings.accounts.length === 0 ? (0, import_react7.createElement)(AddAccountForm, { onDone: () => reload() }) : settings.accounts.map(
1556
- (item) => (0, import_react7.createElement)(AccountRow, {
1687
+ (0, import_react8.createElement)("h3", null, "\u8D26\u53F7"),
1688
+ settings.accounts.length === 0 ? (0, import_react8.createElement)(AddAccountForm, { onDone: () => reload() }) : settings.accounts.map(
1689
+ (item) => (0, import_react8.createElement)(AccountRow, {
1557
1690
  key: item.id,
1558
1691
  account: item,
1559
1692
  active: item.id === settings.activeAccountId,
@@ -1597,32 +1730,32 @@ function MailSettings() {
1597
1730
  }
1598
1731
  })
1599
1732
  ),
1600
- adding ? (0, import_react7.createElement)(AddAccountForm, {
1733
+ adding ? (0, import_react8.createElement)(AddAccountForm, {
1601
1734
  onDone: () => {
1602
1735
  setAdding(false);
1603
1736
  reload();
1604
1737
  },
1605
1738
  onCancel: () => setAdding(false)
1606
- }) : (0, import_react7.createElement)("button", { className: "ghost", onClick: () => setAdding(true) }, "+ \u6DFB\u52A0\u8D26\u53F7")
1739
+ }) : (0, import_react8.createElement)("button", { className: "ghost", onClick: () => setAdding(true) }, "+ \u6DFB\u52A0\u8D26\u53F7")
1607
1740
  ),
1608
- (0, import_react7.createElement)(
1741
+ (0, import_react8.createElement)(
1609
1742
  "div",
1610
1743
  { className: "mailharbor-card" },
1611
- (0, import_react7.createElement)("h3", null, "\u5199\u4FE1\u4E0E\u9605\u8BFB"),
1612
- (0, import_react7.createElement)(
1744
+ (0, import_react8.createElement)("h3", null, "\u5199\u4FE1\u4E0E\u9605\u8BFB"),
1745
+ (0, import_react8.createElement)(
1613
1746
  Field,
1614
1747
  { label: "\u7B7E\u540D\uFF08\u7EAF\u6587\u672C\uFF0C\u53D1\u9001\u65F6\u8FFD\u52A0\u5230\u6B63\u6587\u672B\u5C3E\uFF09" },
1615
- (0, import_react7.createElement)("textarea", {
1748
+ (0, import_react8.createElement)("textarea", {
1616
1749
  rows: 4,
1617
1750
  value: signature,
1618
1751
  onChange: (event) => setSignature(event.target.value)
1619
1752
  })
1620
1753
  ),
1621
- (0, import_react7.createElement)(
1754
+ (0, import_react8.createElement)(
1622
1755
  "div",
1623
1756
  { style: { display: "flex", gap: "10px", alignItems: "center", flexWrap: "wrap" } },
1624
- (0, import_react7.createElement)("button", { className: "ghost", onClick: () => void saveGeneral({ signature }) }, "\u4FDD\u5B58\u7B7E\u540D"),
1625
- (0, import_react7.createElement)(Toggle, {
1757
+ (0, import_react8.createElement)("button", { className: "ghost", onClick: () => void saveGeneral({ signature }) }, "\u4FDD\u5B58\u7B7E\u540D"),
1758
+ (0, import_react8.createElement)(Toggle, {
1626
1759
  checked: markOnOpen,
1627
1760
  onChange: (value) => {
1628
1761
  setMarkOnOpen(value);
@@ -1631,13 +1764,13 @@ function MailSettings() {
1631
1764
  label: "\u6253\u5F00\u90AE\u4EF6\u65F6\u6807\u4E3A\u5DF2\u8BFB"
1632
1765
  })
1633
1766
  ),
1634
- (0, import_react7.createElement)(
1767
+ (0, import_react8.createElement)(
1635
1768
  "div",
1636
1769
  { className: "mailharbor-grid" },
1637
- (0, import_react7.createElement)(
1770
+ (0, import_react8.createElement)(
1638
1771
  Field,
1639
1772
  { label: "\u5217\u8868\u6BCF\u9875\u6570\u91CF" },
1640
- (0, import_react7.createElement)("input", {
1773
+ (0, import_react8.createElement)("input", {
1641
1774
  type: "number",
1642
1775
  min: 10,
1643
1776
  max: 200,
@@ -1646,10 +1779,10 @@ function MailSettings() {
1646
1779
  onBlur: () => void saveGeneral({ render: { listLimit } })
1647
1780
  })
1648
1781
  ),
1649
- (0, import_react7.createElement)(
1782
+ (0, import_react8.createElement)(
1650
1783
  Field,
1651
1784
  { label: "\u672A\u8BFB\u89D2\u6807\u8F6E\u8BE2\uFF08\u79D2\uFF09" },
1652
- (0, import_react7.createElement)("input", {
1785
+ (0, import_react8.createElement)("input", {
1653
1786
  type: "number",
1654
1787
  min: 15,
1655
1788
  max: 3600,
@@ -1660,11 +1793,11 @@ function MailSettings() {
1660
1793
  )
1661
1794
  )
1662
1795
  ),
1663
- (0, import_react7.createElement)(
1796
+ (0, import_react8.createElement)(
1664
1797
  "div",
1665
1798
  { className: "mailharbor-card" },
1666
- (0, import_react7.createElement)("h3", null, "AI"),
1667
- (0, import_react7.createElement)(Toggle, {
1799
+ (0, import_react8.createElement)("h3", null, "AI"),
1800
+ (0, import_react8.createElement)(Toggle, {
1668
1801
  checked: aiEnabled,
1669
1802
  onChange: (value) => {
1670
1803
  setAiEnabled(value);
@@ -1672,54 +1805,54 @@ function MailSettings() {
1672
1805
  },
1673
1806
  label: "\u542F\u7528 AI\uFF08\u6458\u8981\u3001\u8D77\u8349\u3001\u6DA6\u8272\u3001\u81EA\u7136\u8BED\u8A00\u641C\u7D22\uFF09"
1674
1807
  }),
1675
- (0, import_react7.createElement)(
1808
+ (0, import_react8.createElement)(
1676
1809
  "div",
1677
1810
  { className: "mailharbor-grid" },
1678
- (0, import_react7.createElement)(
1811
+ (0, import_react8.createElement)(
1679
1812
  Field,
1680
1813
  { label: "Provider" },
1681
- (0, import_react7.createElement)("input", {
1814
+ (0, import_react8.createElement)("input", {
1682
1815
  value: aiProvider,
1683
1816
  onChange: (event) => setAiProvider(event.target.value),
1684
1817
  onBlur: () => void saveGeneral({ ai: { provider: aiProvider } })
1685
1818
  })
1686
1819
  ),
1687
- (0, import_react7.createElement)(
1820
+ (0, import_react8.createElement)(
1688
1821
  Field,
1689
1822
  { label: "\u6A21\u578B" },
1690
- (0, import_react7.createElement)("input", {
1823
+ (0, import_react8.createElement)("input", {
1691
1824
  value: aiModel,
1692
1825
  onChange: (event) => setAiModel(event.target.value),
1693
1826
  onBlur: () => void saveGeneral({ ai: { model: aiModel } })
1694
1827
  })
1695
1828
  )
1696
1829
  ),
1697
- (0, import_react7.createElement)(
1830
+ (0, import_react8.createElement)(
1698
1831
  "p",
1699
1832
  { className: "small muted" },
1700
1833
  "AI \u8C03\u7528\u8D70 DSH \u81EA\u5DF1\u7684\u6A21\u578B\u670D\u52A1\uFF0C\u4E0D\u989D\u5916\u4FDD\u5B58\u5BC6\u94A5\u3002AI \u9762\u677F\u529F\u80FD\u5C06\u5728 v0.2 \u63D0\u4F9B\u3002"
1701
1834
  )
1702
1835
  ),
1703
- (0, import_react7.createElement)(
1836
+ (0, import_react8.createElement)(
1704
1837
  "div",
1705
1838
  { className: "mailharbor-card" },
1706
- (0, import_react7.createElement)("h3", null, "\u6570\u636E"),
1707
- (0, import_react7.createElement)(
1839
+ (0, import_react8.createElement)("h3", null, "\u6570\u636E"),
1840
+ (0, import_react8.createElement)(
1708
1841
  "dl",
1709
1842
  { className: "mailharbor-kv" },
1710
- (0, import_react7.createElement)("dt", null, "\u6570\u636E\u76EE\u5F55"),
1711
- (0, import_react7.createElement)("dd", null, settings.dataDir),
1712
- (0, import_react7.createElement)("dt", null, "\u914D\u7F6E\u6587\u4EF6"),
1713
- (0, import_react7.createElement)("dd", null, settings.configFile),
1714
- (0, import_react7.createElement)("dt", null, "\u5F53\u524D\u8D26\u53F7\u6570\u636E\u5E93"),
1715
- (0, import_react7.createElement)("dd", null, account === null ? "\u2014" : `${settings.dataDir}/accounts/${account.id}/mail.db`),
1716
- (0, import_react7.createElement)("dt", null, "\u63D2\u4EF6\u7248\u672C"),
1717
- (0, import_react7.createElement)("dd", null, state.version)
1843
+ (0, import_react8.createElement)("dt", null, "\u6570\u636E\u76EE\u5F55"),
1844
+ (0, import_react8.createElement)("dd", null, settings.dataDir),
1845
+ (0, import_react8.createElement)("dt", null, "\u914D\u7F6E\u6587\u4EF6"),
1846
+ (0, import_react8.createElement)("dd", null, settings.configFile),
1847
+ (0, import_react8.createElement)("dt", null, "\u5F53\u524D\u8D26\u53F7\u6570\u636E\u5E93"),
1848
+ (0, import_react8.createElement)("dd", null, account === null ? "\u2014" : `${settings.dataDir}/accounts/${account.id}/mail.db`),
1849
+ (0, import_react8.createElement)("dt", null, "\u63D2\u4EF6\u7248\u672C"),
1850
+ (0, import_react8.createElement)("dd", null, state.version)
1718
1851
  ),
1719
- (0, import_react7.createElement)(
1852
+ (0, import_react8.createElement)(
1720
1853
  "div",
1721
1854
  { style: { display: "flex", gap: "8px", flexWrap: "wrap" } },
1722
- account === null ? null : (0, import_react7.createElement)(
1855
+ account === null ? null : (0, import_react8.createElement)(
1723
1856
  "button",
1724
1857
  {
1725
1858
  className: "ghost",
@@ -1754,19 +1887,19 @@ function AccountRow({
1754
1887
  onSave,
1755
1888
  onRemove
1756
1889
  }) {
1757
- const [password, setPassword] = (0, import_react7.useState)("");
1758
- const [remember, setRemember] = (0, import_react7.useState)(true);
1759
- const [label, setLabel] = (0, import_react7.useState)(account.label);
1760
- const [username, setUsername] = (0, import_react7.useState)(account.username);
1761
- const [imapHost, setImapHost] = (0, import_react7.useState)(account.imap.host);
1762
- const [imapPort, setImapPort] = (0, import_react7.useState)(String(account.imap.port));
1763
- const [imapSecure, setImapSecure] = (0, import_react7.useState)(account.imap.secure);
1764
- const [smtpHost, setSmtpHost] = (0, import_react7.useState)(account.smtp.host);
1765
- const [smtpPort, setSmtpPort] = (0, import_react7.useState)(String(account.smtp.port));
1766
- const [smtpSecure, setSmtpSecure] = (0, import_react7.useState)(account.smtp.secure);
1767
- const [fromName, setFromName] = (0, import_react7.useState)(account.smtp.fromName);
1768
- const [busy, setBusy] = (0, import_react7.useState)(false);
1769
- (0, import_react7.useEffect)(() => {
1890
+ const [password, setPassword] = (0, import_react8.useState)("");
1891
+ const [remember, setRemember] = (0, import_react8.useState)(true);
1892
+ const [label, setLabel] = (0, import_react8.useState)(account.label);
1893
+ const [username, setUsername] = (0, import_react8.useState)(account.username);
1894
+ const [imapHost, setImapHost] = (0, import_react8.useState)(account.imap.host);
1895
+ const [imapPort, setImapPort] = (0, import_react8.useState)(String(account.imap.port));
1896
+ const [imapSecure, setImapSecure] = (0, import_react8.useState)(account.imap.secure);
1897
+ const [smtpHost, setSmtpHost] = (0, import_react8.useState)(account.smtp.host);
1898
+ const [smtpPort, setSmtpPort] = (0, import_react8.useState)(String(account.smtp.port));
1899
+ const [smtpSecure, setSmtpSecure] = (0, import_react8.useState)(account.smtp.secure);
1900
+ const [fromName, setFromName] = (0, import_react8.useState)(account.smtp.fromName);
1901
+ const [busy, setBusy] = (0, import_react8.useState)(false);
1902
+ (0, import_react8.useEffect)(() => {
1770
1903
  setLabel(account.label);
1771
1904
  setUsername(account.username);
1772
1905
  setImapHost(account.imap.host);
@@ -1785,103 +1918,103 @@ function AccountRow({
1785
1918
  setBusy(false);
1786
1919
  }
1787
1920
  };
1788
- return (0, import_react7.createElement)(
1921
+ return (0, import_react8.createElement)(
1789
1922
  "div",
1790
1923
  { className: "mailharbor-card", style: { background: "var(--m-bg-1)" } },
1791
- (0, import_react7.createElement)(
1924
+ (0, import_react8.createElement)(
1792
1925
  "div",
1793
1926
  { className: "mailharbor-account-row" },
1794
- (0, import_react7.createElement)(Avatar, { email: account.email, size: 30 }),
1795
- (0, import_react7.createElement)(
1927
+ (0, import_react8.createElement)(Avatar, { email: account.email, size: 30 }),
1928
+ (0, import_react8.createElement)(
1796
1929
  "div",
1797
1930
  { style: { display: "flex", flexDirection: "column", minWidth: 0 } },
1798
- (0, import_react7.createElement)("strong", null, account.label),
1799
- (0, import_react7.createElement)("span", { className: "small muted" }, account.email)
1931
+ (0, import_react8.createElement)("strong", null, account.label),
1932
+ (0, import_react8.createElement)("span", { className: "small muted" }, account.email)
1800
1933
  ),
1801
- active ? (0, import_react7.createElement)("span", { className: "badge ok" }, "\u5F53\u524D\u8D26\u53F7") : null,
1802
- loggedIn === false ? (0, import_react7.createElement)("span", { className: "badge warn" }, "\u672A\u767B\u5F55") : null,
1803
- (0, import_react7.createElement)("span", { className: "spacer" }),
1804
- active ? null : (0, import_react7.createElement)("button", { className: "ghost small", onClick: () => void wrap(onActivate) }, "\u8BBE\u4E3A\u5F53\u524D"),
1805
- (0, import_react7.createElement)("button", { className: "ghost small", onClick: () => void wrap(onCheck) }, "\u68C0\u67E5\u8FDE\u63A5"),
1806
- (0, import_react7.createElement)("button", { className: "ghost small", onClick: onToggleEdit }, editing ? "\u6536\u8D77" : "\u7F16\u8F91")
1934
+ active ? (0, import_react8.createElement)("span", { className: "badge ok" }, "\u5F53\u524D\u8D26\u53F7") : null,
1935
+ loggedIn === false ? (0, import_react8.createElement)("span", { className: "badge warn" }, "\u672A\u767B\u5F55") : null,
1936
+ (0, import_react8.createElement)("span", { className: "spacer" }),
1937
+ active ? null : (0, import_react8.createElement)("button", { className: "ghost small", onClick: () => void wrap(onActivate) }, "\u8BBE\u4E3A\u5F53\u524D"),
1938
+ (0, import_react8.createElement)("button", { className: "ghost small", onClick: () => void wrap(onCheck) }, "\u68C0\u67E5\u8FDE\u63A5"),
1939
+ (0, import_react8.createElement)("button", { className: "ghost small", onClick: onToggleEdit }, editing ? "\u6536\u8D77" : "\u7F16\u8F91")
1807
1940
  ),
1808
- editing ? (0, import_react7.createElement)(
1941
+ editing ? (0, import_react8.createElement)(
1809
1942
  "div",
1810
1943
  { style: { display: "flex", flexDirection: "column", gap: "10px" } },
1811
- (0, import_react7.createElement)(
1944
+ (0, import_react8.createElement)(
1812
1945
  "div",
1813
1946
  { className: "mailharbor-grid" },
1814
- (0, import_react7.createElement)(
1947
+ (0, import_react8.createElement)(
1815
1948
  Field,
1816
1949
  { label: "\u663E\u793A\u540D\u79F0" },
1817
- (0, import_react7.createElement)("input", {
1950
+ (0, import_react8.createElement)("input", {
1818
1951
  value: label,
1819
1952
  onChange: (event) => setLabel(event.target.value)
1820
1953
  })
1821
1954
  ),
1822
- (0, import_react7.createElement)(
1955
+ (0, import_react8.createElement)(
1823
1956
  Field,
1824
1957
  { label: "\u767B\u5F55\u7528\u6237\u540D" },
1825
- (0, import_react7.createElement)("input", {
1958
+ (0, import_react8.createElement)("input", {
1826
1959
  value: username,
1827
1960
  onChange: (event) => setUsername(event.target.value)
1828
1961
  })
1829
1962
  )
1830
1963
  ),
1831
- (0, import_react7.createElement)(
1964
+ (0, import_react8.createElement)(
1832
1965
  "div",
1833
1966
  { className: "mailharbor-grid three" },
1834
- (0, import_react7.createElement)(
1967
+ (0, import_react8.createElement)(
1835
1968
  Field,
1836
1969
  { label: "IMAP \u4E3B\u673A" },
1837
- (0, import_react7.createElement)("input", {
1970
+ (0, import_react8.createElement)("input", {
1838
1971
  value: imapHost,
1839
1972
  onChange: (event) => setImapHost(event.target.value)
1840
1973
  })
1841
1974
  ),
1842
- (0, import_react7.createElement)(
1975
+ (0, import_react8.createElement)(
1843
1976
  Field,
1844
1977
  { label: "\u7AEF\u53E3" },
1845
- (0, import_react7.createElement)("input", {
1978
+ (0, import_react8.createElement)("input", {
1846
1979
  value: imapPort,
1847
1980
  onChange: (event) => setImapPort(event.target.value)
1848
1981
  })
1849
1982
  ),
1850
- (0, import_react7.createElement)(Toggle, { checked: imapSecure, onChange: setImapSecure, label: "TLS" })
1983
+ (0, import_react8.createElement)(Toggle, { checked: imapSecure, onChange: setImapSecure, label: "TLS" })
1851
1984
  ),
1852
- (0, import_react7.createElement)(
1985
+ (0, import_react8.createElement)(
1853
1986
  "div",
1854
1987
  { className: "mailharbor-grid three" },
1855
- (0, import_react7.createElement)(
1988
+ (0, import_react8.createElement)(
1856
1989
  Field,
1857
1990
  { label: "SMTP \u4E3B\u673A" },
1858
- (0, import_react7.createElement)("input", {
1991
+ (0, import_react8.createElement)("input", {
1859
1992
  value: smtpHost,
1860
1993
  onChange: (event) => setSmtpHost(event.target.value)
1861
1994
  })
1862
1995
  ),
1863
- (0, import_react7.createElement)(
1996
+ (0, import_react8.createElement)(
1864
1997
  Field,
1865
1998
  { label: "\u7AEF\u53E3" },
1866
- (0, import_react7.createElement)("input", {
1999
+ (0, import_react8.createElement)("input", {
1867
2000
  value: smtpPort,
1868
2001
  onChange: (event) => setSmtpPort(event.target.value)
1869
2002
  })
1870
2003
  ),
1871
- (0, import_react7.createElement)(Toggle, { checked: smtpSecure, onChange: setSmtpSecure, label: "TLS" })
2004
+ (0, import_react8.createElement)(Toggle, { checked: smtpSecure, onChange: setSmtpSecure, label: "TLS" })
1872
2005
  ),
1873
- (0, import_react7.createElement)(
2006
+ (0, import_react8.createElement)(
1874
2007
  Field,
1875
2008
  { label: "\u53D1\u4EF6\u4EBA\u540D\u79F0" },
1876
- (0, import_react7.createElement)("input", {
2009
+ (0, import_react8.createElement)("input", {
1877
2010
  value: fromName,
1878
2011
  onChange: (event) => setFromName(event.target.value)
1879
2012
  })
1880
2013
  ),
1881
- (0, import_react7.createElement)(
2014
+ (0, import_react8.createElement)(
1882
2015
  "div",
1883
2016
  { style: { display: "flex", gap: "8px", alignItems: "center", flexWrap: "wrap" } },
1884
- (0, import_react7.createElement)(
2017
+ (0, import_react8.createElement)(
1885
2018
  "button",
1886
2019
  {
1887
2020
  className: "primary small",
@@ -1897,7 +2030,7 @@ function AccountRow({
1897
2030
  },
1898
2031
  "\u4FDD\u5B58\u8D26\u53F7"
1899
2032
  ),
1900
- (0, import_react7.createElement)(
2033
+ (0, import_react8.createElement)(
1901
2034
  "button",
1902
2035
  {
1903
2036
  className: "ghost small danger",
@@ -1906,21 +2039,21 @@ function AccountRow({
1906
2039
  "\u79FB\u9664\u8D26\u53F7"
1907
2040
  )
1908
2041
  ),
1909
- (0, import_react7.createElement)("hr", { style: { border: 0, borderTop: "1px solid var(--m-line)", width: "100%" } }),
1910
- (0, import_react7.createElement)(
2042
+ (0, import_react8.createElement)("hr", { style: { border: 0, borderTop: "1px solid var(--m-line)", width: "100%" } }),
2043
+ (0, import_react8.createElement)(
1911
2044
  Field,
1912
2045
  { label: "\u5BC6\u7801 / \u5E94\u7528\u4E13\u7528\u5BC6\u7801\uFF08\u4E0D\u5199\u5165\u914D\u7F6E\u6587\u4EF6\uFF09" },
1913
- (0, import_react7.createElement)("input", {
2046
+ (0, import_react8.createElement)("input", {
1914
2047
  type: "password",
1915
2048
  value: password,
1916
2049
  onChange: (event) => setPassword(event.target.value)
1917
2050
  })
1918
2051
  ),
1919
- (0, import_react7.createElement)(
2052
+ (0, import_react8.createElement)(
1920
2053
  "div",
1921
2054
  { style: { display: "flex", gap: "8px", alignItems: "center" } },
1922
- (0, import_react7.createElement)(Toggle, { checked: remember, onChange: setRemember, label: "\u8BB0\u4F4F\u5BC6\u7801" }),
1923
- (0, import_react7.createElement)(
2055
+ (0, import_react8.createElement)(Toggle, { checked: remember, onChange: setRemember, label: "\u8BB0\u4F4F\u5BC6\u7801" }),
2056
+ (0, import_react8.createElement)(
1924
2057
  "button",
1925
2058
  {
1926
2059
  className: "primary small",
@@ -1932,15 +2065,15 @@ function AccountRow({
1932
2065
  },
1933
2066
  "\u767B\u5F55"
1934
2067
  ),
1935
- (0, import_react7.createElement)("button", { className: "ghost small", onClick: () => void wrap(onLogout) }, "\u9000\u51FA\u767B\u5F55")
2068
+ (0, import_react8.createElement)("button", { className: "ghost small", onClick: () => void wrap(onLogout) }, "\u9000\u51FA\u767B\u5F55")
1936
2069
  ),
1937
- checkResult === "" ? null : (0, import_react7.createElement)("div", { className: "small muted" }, checkResult)
2070
+ checkResult === "" ? null : (0, import_react8.createElement)("div", { className: "small muted" }, checkResult)
1938
2071
  ) : null
1939
2072
  );
1940
2073
  }
1941
2074
 
1942
2075
  // src/client/index.tsx
1943
- var VERSION = "0.1.0";
2076
+ var VERSION = "0.2.1";
1944
2077
  var inject = ["slots"];
1945
2078
  var PANEL_ID = "mailharbor";
1946
2079
  var STYLE_ID = "mailharbor-style";