@zaclinley/dsh-mailharbor 0.1.0 → 0.2.0

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");
@@ -201,7 +201,7 @@ function MailIcon() {
201
201
  }
202
202
 
203
203
  // src/client/panel.tsx
204
- var import_react6 = require("react");
204
+ var import_react7 = require("react");
205
205
 
206
206
  // src/client/account-form.tsx
207
207
  var import_react3 = require("react");
@@ -256,6 +256,15 @@ function Toggle({
256
256
  label
257
257
  );
258
258
  }
259
+ function portalRoot() {
260
+ const existing = document.getElementById("mailharbor-portal");
261
+ if (existing !== null) return existing;
262
+ const element = document.createElement("div");
263
+ element.id = "mailharbor-portal";
264
+ element.className = "mailharbor mailharbor-portal";
265
+ document.body.append(element);
266
+ return element;
267
+ }
259
268
  function Modal({
260
269
  title,
261
270
  children,
@@ -301,7 +310,7 @@ function Modal({
301
310
  footer === void 0 ? null : (0, import_react2.createElement)("footer", null, footer)
302
311
  )
303
312
  ),
304
- document.body
313
+ portalRoot()
305
314
  );
306
315
  }
307
316
  function ErrorBar({ message, onDismiss }) {
@@ -837,13 +846,68 @@ function Composer({
837
846
  );
838
847
  }
839
848
 
840
- // src/client/reader.tsx
849
+ // src/client/icons.tsx
841
850
  var import_react5 = require("react");
851
+ var PATHS = {
852
+ refresh: (0, import_react5.createElement)("path", { d: "M20 11a8 8 0 1 0-2.3 5.7M20 5v6h-6" }),
853
+ plus: (0, import_react5.createElement)("path", { d: "M12 5v14M5 12h14" }),
854
+ 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" }),
855
+ archive: (0, import_react5.createElement)(
856
+ "g",
857
+ null,
858
+ (0, import_react5.createElement)("rect", { x: 3, y: 4, width: 18, height: 5, rx: 1.5 }),
859
+ (0, import_react5.createElement)("path", { d: "M5 9v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9M10 13h4" })
860
+ ),
861
+ paperclip: (0, import_react5.createElement)("path", {
862
+ 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"
863
+ }),
864
+ mail: (0, import_react5.createElement)(
865
+ "g",
866
+ null,
867
+ (0, import_react5.createElement)("rect", { x: 3, y: 5, width: 18, height: 14, rx: 2.5 }),
868
+ (0, import_react5.createElement)("path", { d: "m4 7 7.1 5a1.6 1.6 0 0 0 1.8 0L20 7" })
869
+ ),
870
+ 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" }),
871
+ reply: (0, import_react5.createElement)("path", { d: "M9 7 4 12l5 5M4 12h9a6 6 0 0 1 6 6v1" }),
872
+ 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" }),
873
+ forward: (0, import_react5.createElement)("path", { d: "m15 7 5 5-5 5M20 12h-9a6 6 0 0 0-6 6v1" }),
874
+ check: (0, import_react5.createElement)("path", { d: "m5 13 4 4L19 7" }),
875
+ image: (0, import_react5.createElement)(
876
+ "g",
877
+ null,
878
+ (0, import_react5.createElement)("rect", { x: 3, y: 4, width: 18, height: 16, rx: 2 }),
879
+ (0, import_react5.createElement)("circle", { cx: 8.5, cy: 9.5, r: 1.5 }),
880
+ (0, import_react5.createElement)("path", { d: "m4 18 5-5 4 4 3-3 4 4" })
881
+ ),
882
+ close: (0, import_react5.createElement)("path", { d: "M6 6l12 12M18 6 6 18" }),
883
+ chevronLeft: (0, import_react5.createElement)("path", { d: "m14 6-6 6 6 6" })
884
+ };
885
+ function Icon({ name, size = 16 }) {
886
+ return (0, import_react5.createElement)(
887
+ "svg",
888
+ {
889
+ width: size,
890
+ height: size,
891
+ viewBox: "0 0 24 24",
892
+ fill: "none",
893
+ stroke: "currentColor",
894
+ strokeWidth: 1.7,
895
+ strokeLinecap: "round",
896
+ strokeLinejoin: "round",
897
+ "aria-hidden": "true",
898
+ focusable: "false"
899
+ },
900
+ PATHS[name] ?? null
901
+ );
902
+ }
903
+
904
+ // src/client/reader.tsx
905
+ var import_react6 = require("react");
842
906
  var IFRAME_STYLE = `
843
907
  html, body { margin: 0; padding: 0; }
844
908
  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;
909
+ font: 15px/1.75 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
910
+ color: #171a21; background: #fff; padding: 20px 22px;
847
911
  overflow-wrap: anywhere;
848
912
  }
849
913
  img { max-width: 100%; height: auto; }
@@ -873,6 +937,9 @@ function escapeHtml(value) {
873
937
  function hasRemoteImages(detail) {
874
938
  return detail.html !== null && /<img[^>]+src=["']https?:/i.test(detail.html);
875
939
  }
940
+ function addressLine(list) {
941
+ return list.map((item) => item.name !== "" ? `${item.name} <${item.address}>` : item.address).join("\u3001");
942
+ }
876
943
  function Reader({
877
944
  detail,
878
945
  account,
@@ -882,11 +949,11 @@ function Reader({
882
949
  onReply,
883
950
  onClose
884
951
  }) {
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]);
952
+ const [plain, setPlain] = (0, import_react6.useState)(false);
953
+ const [loadImages, setLoadImages] = (0, import_react6.useState)(false);
954
+ const [busy, setBusy] = (0, import_react6.useState)(false);
955
+ const [error, setError] = (0, import_react6.useState)("");
956
+ const remoteImages = (0, import_react6.useMemo)(() => hasRemoteImages(detail), [detail]);
890
957
  const html = detail.html !== null && detail.html !== "";
891
958
  const toggleRead = async () => {
892
959
  setBusy(true);
@@ -906,102 +973,103 @@ function Reader({
906
973
  setBusy(false);
907
974
  }
908
975
  };
909
- return (0, import_react5.createElement)(
976
+ return (0, import_react6.createElement)(
910
977
  "div",
911
978
  { className: "mailharbor-reader" },
912
- (0, import_react5.createElement)(
979
+ (0, import_react6.createElement)(
913
980
  "div",
914
981
  { className: "mailharbor-reader-head" },
915
- (0, import_react5.createElement)(
982
+ (0, import_react6.createElement)(
916
983
  "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")
984
+ { className: "mailharbor-reader-title" },
985
+ onClose === void 0 ? null : (0, import_react6.createElement)(
986
+ "button",
987
+ { className: "ghost icon", onClick: onClose, "aria-label": "\u8FD4\u56DE\u5217\u8868", title: "\u8FD4\u56DE\u5217\u8868" },
988
+ (0, import_react6.createElement)(Icon, { name: "chevronLeft" })
989
+ ),
990
+ (0, import_react6.createElement)("h2", { style: { flex: 1 } }, detail.subject),
991
+ (0, import_react6.createElement)(
992
+ "button",
993
+ {
994
+ className: "ghost icon",
995
+ onClick: () => void toggleRead(),
996
+ disabled: busy,
997
+ title: detail.unread ? "\u6807\u4E3A\u5DF2\u8BFB" : "\u6807\u4E3A\u672A\u8BFB",
998
+ "aria-label": detail.unread ? "\u6807\u4E3A\u5DF2\u8BFB" : "\u6807\u4E3A\u672A\u8BFB"
999
+ },
1000
+ (0, import_react6.createElement)(Icon, { name: "check" })
1001
+ )
920
1002
  ),
921
- (0, import_react5.createElement)(
1003
+ (0, import_react6.createElement)(
922
1004
  "div",
923
1005
  { className: "mailharbor-reader-meta" },
924
- (0, import_react5.createElement)(
1006
+ (0, import_react6.createElement)(
925
1007
  "span",
926
- null,
927
- `${detail.from.name !== "" ? detail.from.name : detail.from.address} <${detail.from.address}>`
1008
+ { className: "who" },
1009
+ (0, import_react6.createElement)(Avatar, { email: detail.from.address, size: 22 }),
1010
+ (0, import_react6.createElement)("strong", null, detail.from.name !== "" ? detail.from.name : detail.from.address),
1011
+ detail.from.name !== "" ? (0, import_react6.createElement)("span", null, `<${detail.from.address}>`) : null
928
1012
  ),
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
1013
+ (0, import_react6.createElement)("span", null, longDate(detail.date)),
1014
+ detail.backedUp === false ? (0, import_react6.createElement)("span", { className: "badge warn" }, "\u672A\u5907\u4EFD") : null
931
1015
  ),
932
- (0, import_react5.createElement)(
1016
+ (0, import_react6.createElement)(
933
1017
  "div",
934
1018
  { 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(", ")}`)
1019
+ (0, import_react6.createElement)("span", null, `\u6536\u4EF6\u4EBA: ${addressLine(detail.to) || "\u2014"}`),
1020
+ detail.cc.length === 0 ? null : (0, import_react6.createElement)("span", null, `\u6284\u9001: ${addressLine(detail.cc)}`)
941
1021
  ),
942
- (0, import_react5.createElement)(
1022
+ (0, import_react6.createElement)(
943
1023
  "div",
944
1024
  { className: "mailharbor-reader-actions" },
945
- (0, import_react5.createElement)(
1025
+ (0, import_react6.createElement)(
946
1026
  "button",
947
- {
948
- className: "primary",
949
- onClick: () => {
950
- onReply("reply");
951
- }
952
- },
1027
+ { className: "ghost", onClick: () => onReply("reply") },
1028
+ (0, import_react6.createElement)(Icon, { name: "reply" }),
953
1029
  "\u56DE\u590D"
954
1030
  ),
955
- (0, import_react5.createElement)(
1031
+ (0, import_react6.createElement)(
956
1032
  "button",
957
- {
958
- className: "ghost",
959
- onClick: () => {
960
- onReply("replyAll");
961
- }
962
- },
1033
+ { className: "ghost", onClick: () => onReply("replyAll") },
1034
+ (0, import_react6.createElement)(Icon, { name: "replyAll" }),
963
1035
  "\u5168\u90E8\u56DE\u590D"
964
1036
  ),
965
- (0, import_react5.createElement)(
1037
+ (0, import_react6.createElement)(
966
1038
  "button",
967
- {
968
- className: "ghost",
969
- onClick: () => {
970
- onReply("forward");
971
- }
972
- },
1039
+ { className: "ghost", onClick: () => onReply("forward") },
1040
+ (0, import_react6.createElement)(Icon, { name: "forward" }),
973
1041
  "\u8F6C\u53D1"
974
1042
  ),
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)(
1043
+ (0, import_react6.createElement)("span", { className: "spacer" }),
1044
+ html ? (0, import_react6.createElement)(
982
1045
  "button",
983
- { className: "ghost", onClick: () => setPlain(!plain) },
984
- plain ? "\u663E\u793A HTML" : "\u663E\u793A\u7EAF\u6587\u672C"
1046
+ { className: "subtle", onClick: () => setPlain(!plain) },
1047
+ plain ? "\u663E\u793A HTML" : "\u7EAF\u6587\u672C"
985
1048
  ) : null,
986
- remoteImages && !loadImages ? (0, import_react5.createElement)("button", { className: "ghost", onClick: () => setLoadImages(true) }, "\u663E\u793A\u8FDC\u7A0B\u56FE\u7247") : null
1049
+ remoteImages && !loadImages ? (0, import_react6.createElement)(
1050
+ "button",
1051
+ { className: "subtle", onClick: () => setLoadImages(true) },
1052
+ (0, import_react6.createElement)(Icon, { name: "image", size: 14 }),
1053
+ "\u663E\u793A\u56FE\u7247"
1054
+ ) : null
987
1055
  ),
988
- error === "" ? null : (0, import_react5.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error)
1056
+ error === "" ? null : (0, import_react6.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error)
989
1057
  ),
990
- (0, import_react5.createElement)(
1058
+ (0, import_react6.createElement)(
991
1059
  "div",
992
1060
  { className: "mailharbor-reader-body" },
993
- html && !plain ? (0, import_react5.createElement)("iframe", {
1061
+ html && !plain ? (0, import_react6.createElement)("iframe", {
994
1062
  title: "\u90AE\u4EF6\u6B63\u6587",
995
1063
  sandbox: "",
996
1064
  srcDoc: srcDoc(detail, loadImages),
997
1065
  referrerPolicy: "no-referrer"
998
- }) : (0, import_react5.createElement)("pre", null, detail.text !== "" ? detail.text : "\uFF08\u65E0\u6B63\u6587\uFF09")
1066
+ }) : (0, import_react6.createElement)("pre", null, detail.text !== "" ? detail.text : "\uFF08\u65E0\u6B63\u6587\uFF09")
999
1067
  ),
1000
- detail.attachments.length === 0 ? null : (0, import_react5.createElement)(
1068
+ detail.attachments.length === 0 ? null : (0, import_react6.createElement)(
1001
1069
  "div",
1002
1070
  { className: "mailharbor-attachments" },
1003
1071
  detail.attachments.map(
1004
- (file) => (0, import_react5.createElement)(
1072
+ (file) => (0, import_react6.createElement)(
1005
1073
  "a",
1006
1074
  {
1007
1075
  className: "mailharbor-attachment",
@@ -1018,10 +1086,12 @@ function Reader({
1018
1086
  emailId: detail.id,
1019
1087
  attachmentId: file.id
1020
1088
  }),
1021
- download: file.filename
1089
+ download: file.filename,
1090
+ title: file.filename
1022
1091
  },
1023
- (0, import_react5.createElement)("span", { className: "name" }, file.filename),
1024
- (0, import_react5.createElement)("span", { className: "muted small" }, formatBytes(file.size))
1092
+ (0, import_react6.createElement)(Icon, { name: "paperclip", size: 14 }),
1093
+ (0, import_react6.createElement)("span", { className: "name" }, file.filename),
1094
+ (0, import_react6.createElement)("span", { className: "muted small" }, formatBytes(file.size))
1025
1095
  )
1026
1096
  )
1027
1097
  )
@@ -1033,44 +1103,50 @@ var EMPTY_PAGE = { items: [], total: 0, offset: 0, limit: 40 };
1033
1103
  function errorText3(error) {
1034
1104
  return error instanceof ApiError || error instanceof Error ? error.message : String(error);
1035
1105
  }
1106
+ function matchesNarrow() {
1107
+ return typeof window.matchMedia === "function" ? window.matchMedia("(max-width: 900px)").matches : false;
1108
+ }
1036
1109
  function quoteForReply(detail) {
1037
1110
  const body = detail.html ?? `<pre>${detail.text.replaceAll("&", "&amp;").replaceAll("<", "&lt;")}</pre>`;
1038
1111
  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
1112
  }
1040
1113
  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);
1114
+ const [state, setState] = (0, import_react7.useState)(null);
1115
+ const [error, setError] = (0, import_react7.useState)("");
1116
+ const [source, setSource] = (0, import_react7.useState)("local");
1117
+ const [mailbox, setMailbox] = (0, import_react7.useState)("all");
1118
+ const [folders, setFolders] = (0, import_react7.useState)([]);
1119
+ const [query2, setQuery] = (0, import_react7.useState)("");
1120
+ const [search, setSearch] = (0, import_react7.useState)("");
1121
+ const [page, setPage] = (0, import_react7.useState)(EMPTY_PAGE);
1122
+ const [limit, setLimit] = (0, import_react7.useState)(40);
1123
+ const [loading, setLoading] = (0, import_react7.useState)(false);
1124
+ const [selected, setSelected] = (0, import_react7.useState)(null);
1125
+ const [compose, setCompose] = (0, import_react7.useState)(null);
1126
+ const [showAdd, setShowAdd] = (0, import_react7.useState)(false);
1127
+ const [showBackup, setShowBackup] = (0, import_react7.useState)(false);
1128
+ const [backup, setBackup] = (0, import_react7.useState)(null);
1129
+ const [toast, setToast] = (0, import_react7.useState)("");
1130
+ const [narrow, setNarrow] = (0, import_react7.useState)(() => matchesNarrow());
1131
+ const [tick, setTick] = (0, import_react7.useState)(0);
1059
1132
  const account = state?.accounts.find((item) => item.id === state.activeAccountId) ?? null;
1060
1133
  const accountId = account?.id ?? null;
1061
- const refresh = (0, import_react6.useCallback)(() => {
1134
+ const refresh = (0, import_react7.useCallback)(() => {
1062
1135
  setTick((value) => value + 1);
1063
1136
  }, []);
1064
- const notice = (0, import_react6.useCallback)((message) => {
1137
+ const notice = (0, import_react7.useCallback)((message) => {
1065
1138
  setToast(message);
1066
1139
  window.setTimeout(() => {
1067
1140
  setToast("");
1068
1141
  }, 3200);
1069
1142
  }, []);
1070
- (0, import_react6.useEffect)(() => {
1143
+ (0, import_react7.useEffect)(() => {
1071
1144
  let cancelled = false;
1072
1145
  api.state().then((next) => {
1073
- if (!cancelled) setState(next);
1146
+ if (!cancelled) {
1147
+ setState(next);
1148
+ if (next.settings.render.listLimit > 0) setLimit(next.settings.render.listLimit);
1149
+ }
1074
1150
  }).catch((caught) => {
1075
1151
  if (!cancelled) setError(errorText3(caught));
1076
1152
  });
@@ -1078,12 +1154,12 @@ function MailPanel() {
1078
1154
  cancelled = true;
1079
1155
  };
1080
1156
  }, [tick]);
1081
- (0, import_react6.useEffect)(() => {
1157
+ (0, import_react7.useEffect)(() => {
1082
1158
  if (accountId === null) return;
1083
1159
  let cancelled = false;
1084
1160
  api.folders({ accountId, source }).then((result) => {
1085
1161
  if (cancelled) return;
1086
- const items = source === "local" ? [
1162
+ const items2 = source === "local" ? [
1087
1163
  {
1088
1164
  name: "all",
1089
1165
  label: "\u5168\u90E8\u90AE\u4EF6",
@@ -1091,7 +1167,7 @@ function MailPanel() {
1091
1167
  },
1092
1168
  ...result.items.map((item) => ({ ...item, label: item.label ?? item.name }))
1093
1169
  ] : result.items.map((item) => ({ ...item, label: item.label ?? item.name }));
1094
- setFolders(items);
1170
+ setFolders(items2);
1095
1171
  }).catch(() => {
1096
1172
  if (!cancelled) setFolders([]);
1097
1173
  });
@@ -1099,12 +1175,11 @@ function MailPanel() {
1099
1175
  cancelled = true;
1100
1176
  };
1101
1177
  }, [accountId, source, tick]);
1102
- (0, import_react6.useEffect)(() => {
1178
+ (0, import_react7.useEffect)(() => {
1103
1179
  setMailbox(source === "local" ? "all" : "INBOX");
1104
1180
  setSelected(null);
1105
- setLimit(state?.settings.render.listLimit ?? 40);
1106
1181
  }, [source]);
1107
- (0, import_react6.useEffect)(() => {
1182
+ (0, import_react7.useEffect)(() => {
1108
1183
  if (accountId === null) return;
1109
1184
  let cancelled = false;
1110
1185
  setLoading(true);
@@ -1119,7 +1194,8 @@ function MailPanel() {
1119
1194
  cancelled = true;
1120
1195
  };
1121
1196
  }, [accountId, source, mailbox, search, limit, tick]);
1122
- (0, import_react6.useEffect)(() => {
1197
+ (0, import_react7.useEffect)(() => {
1198
+ if (typeof window.matchMedia !== "function") return;
1123
1199
  const media = window.matchMedia("(max-width: 900px)");
1124
1200
  const onChange = () => setNarrow(media.matches);
1125
1201
  media.addEventListener("change", onChange);
@@ -1127,7 +1203,7 @@ function MailPanel() {
1127
1203
  media.removeEventListener("change", onChange);
1128
1204
  };
1129
1205
  }, []);
1130
- (0, import_react6.useEffect)(() => {
1206
+ (0, import_react7.useEffect)(() => {
1131
1207
  if (!showBackup || accountId === null) return;
1132
1208
  let cancelled = false;
1133
1209
  const poll = async () => {
@@ -1228,32 +1304,35 @@ function MailPanel() {
1228
1304
  setError(errorText3(caught));
1229
1305
  }
1230
1306
  };
1231
- const folderOptions = (0, import_react6.useMemo)(
1307
+ const folderOptions = (0, import_react7.useMemo)(
1232
1308
  () => folders.map((folder) => ({
1233
1309
  value: folder.name,
1234
1310
  label: `${folder.label ?? folder.name}${folder.count > 0 ? ` (${String(folder.count)})` : ""}`
1235
1311
  })),
1236
1312
  [folders]
1237
1313
  );
1238
- const unreadCount = page.items.filter((item) => item.unread).length;
1239
1314
  if (state === null) {
1240
- return (0, import_react6.createElement)("div", { className: "mailharbor mailharbor-empty" }, error === "" ? "\u6B63\u5728\u52A0\u8F7D\u90AE\u7BB1\u2026" : error);
1315
+ return (0, import_react7.createElement)(
1316
+ "div",
1317
+ { className: "mailharbor" },
1318
+ (0, import_react7.createElement)("div", { className: "mailharbor-empty" }, error === "" ? "\u6B63\u5728\u52A0\u8F7D\u90AE\u7BB1\u2026" : error)
1319
+ );
1241
1320
  }
1242
1321
  if (account === null) {
1243
- return (0, import_react6.createElement)(
1322
+ return (0, import_react7.createElement)(
1244
1323
  "div",
1245
1324
  { className: "mailharbor" },
1246
- (0, import_react6.createElement)(
1325
+ (0, import_react7.createElement)(
1247
1326
  "div",
1248
1327
  { className: "mailharbor-settings" },
1249
- (0, import_react6.createElement)("h2", null, "\u6B22\u8FCE\u4F7F\u7528 MailHarbor"),
1250
- (0, import_react6.createElement)(
1328
+ (0, import_react7.createElement)("h2", null, "\u6B22\u8FCE\u4F7F\u7528 MailHarbor"),
1329
+ (0, import_react7.createElement)(
1251
1330
  "p",
1252
1331
  { 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"
1332
+ "\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
1333
  ),
1255
- error === "" ? null : (0, import_react6.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error),
1256
- (0, import_react6.createElement)(AddAccountForm, {
1334
+ error === "" ? null : (0, import_react7.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error),
1335
+ (0, import_react7.createElement)(AddAccountForm, {
1257
1336
  onDone: (next) => {
1258
1337
  setState(next);
1259
1338
  setSource("local");
@@ -1263,64 +1342,83 @@ function MailPanel() {
1263
1342
  );
1264
1343
  }
1265
1344
  const needsLogin = source === "server" && state.loggedIn === false;
1266
- return (0, import_react6.createElement)(
1345
+ const items = page.items;
1346
+ return (0, import_react7.createElement)(
1267
1347
  "div",
1268
1348
  { className: narrow ? "mailharbor mailharbor-narrow" : "mailharbor" },
1269
- (0, import_react6.createElement)(
1349
+ (0, import_react7.createElement)(
1270
1350
  "div",
1271
1351
  { 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)(
1352
+ (0, import_react7.createElement)(
1353
+ "div",
1354
+ { className: "mailharbor-account" },
1355
+ (0, import_react7.createElement)(Avatar, { email: account.email, size: 26 }),
1356
+ state.accounts.length > 1 ? (0, import_react7.createElement)(
1357
+ "select",
1358
+ {
1359
+ value: account.id,
1360
+ onChange: (event) => void switchAccount(event.target.value),
1361
+ "aria-label": "\u8D26\u53F7"
1362
+ },
1363
+ state.accounts.map((item) => (0, import_react7.createElement)("option", { key: item.id, value: item.id }, item.label))
1364
+ ) : (0, import_react7.createElement)("span", { className: "name" }, account.label),
1365
+ state.loggedIn === false ? (0, import_react7.createElement)("span", { className: "badge warn" }, "\u672A\u767B\u5F55") : null
1366
+ ),
1367
+ (0, import_react7.createElement)(
1283
1368
  "div",
1284
1369
  { className: "mailharbor-segment", role: "tablist" },
1285
- (0, import_react6.createElement)(
1370
+ (0, import_react7.createElement)(
1286
1371
  "button",
1287
1372
  { className: source === "local" ? "active" : "", onClick: () => setSource("local"), role: "tab" },
1288
1373
  "\u672C\u5730\u5907\u4EFD"
1289
1374
  ),
1290
- (0, import_react6.createElement)(
1375
+ (0, import_react7.createElement)(
1291
1376
  "button",
1292
1377
  { className: source === "server" ? "active" : "", onClick: () => setSource("server"), role: "tab" },
1293
1378
  "\u670D\u52A1\u5668\u5B9E\u65F6"
1294
1379
  )
1295
1380
  ),
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)(
1381
+ (0, import_react7.createElement)("span", { className: "spacer" }),
1382
+ (0, import_react7.createElement)(
1302
1383
  "button",
1303
1384
  {
1304
- className: "ghost",
1305
- onClick: () => {
1306
- refresh();
1307
- }
1385
+ className: "ghost icon",
1386
+ title: "\u6DFB\u52A0\u8D26\u53F7",
1387
+ "aria-label": "\u6DFB\u52A0\u8D26\u53F7",
1388
+ onClick: () => setShowAdd(true)
1308
1389
  },
1309
- "\u5237\u65B0"
1390
+ (0, import_react7.createElement)(Icon, { name: "plus" })
1391
+ ),
1392
+ (0, import_react7.createElement)(
1393
+ "button",
1394
+ { className: "ghost icon", title: "\u5237\u65B0\u5217\u8868", "aria-label": "\u5237\u65B0\u5217\u8868", onClick: refresh },
1395
+ (0, import_react7.createElement)(Icon, { name: "refresh" })
1396
+ ),
1397
+ (0, import_react7.createElement)(
1398
+ "button",
1399
+ { className: "ghost", onClick: () => void startBackup() },
1400
+ (0, import_react7.createElement)(Icon, { name: "archive" }),
1401
+ "\u5907\u4EFD"
1402
+ ),
1403
+ (0, import_react7.createElement)(
1404
+ "button",
1405
+ { className: "primary", onClick: () => startCompose("new") },
1406
+ (0, import_react7.createElement)(Icon, { name: "compose" }),
1407
+ "\u5199\u90AE\u4EF6"
1310
1408
  )
1311
1409
  ),
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)(
1410
+ toast === "" ? null : (0, import_react7.createElement)("div", { className: "small", style: { padding: "6px 14px", color: "var(--m-ok)" } }, toast),
1411
+ error === "" ? null : (0, import_react7.createElement)(ErrorBar, { message: error, onDismiss: () => setError("") }),
1412
+ needsLogin ? (0, import_react7.createElement)("div", { className: "mailharbor-settings" }, (0, import_react7.createElement)(LoginForm, { account, onDone: refresh })) : (0, import_react7.createElement)(
1315
1413
  "div",
1316
1414
  { className: "mailharbor-body", "data-mode": narrow && selected !== null ? "reader" : "list" },
1317
- (0, import_react6.createElement)(
1415
+ (0, import_react7.createElement)(
1318
1416
  "div",
1319
1417
  { className: "mailharbor-list" },
1320
- (0, import_react6.createElement)(
1418
+ (0, import_react7.createElement)(
1321
1419
  "div",
1322
1420
  { className: "mailharbor-filters" },
1323
- (0, import_react6.createElement)(
1421
+ (0, import_react7.createElement)(
1324
1422
  "select",
1325
1423
  {
1326
1424
  value: mailbox,
@@ -1331,12 +1429,13 @@ function MailPanel() {
1331
1429
  "aria-label": "\u90AE\u7BB1\u6587\u4EF6\u5939"
1332
1430
  },
1333
1431
  folderOptions.map(
1334
- (option) => (0, import_react6.createElement)("option", { key: option.value, value: option.value }, option.label)
1432
+ (option) => (0, import_react7.createElement)("option", { key: option.value, value: option.value }, option.label)
1335
1433
  )
1336
1434
  ),
1337
- (0, import_react6.createElement)("input", {
1435
+ (0, import_react7.createElement)("input", {
1338
1436
  type: "search",
1339
1437
  placeholder: "\u641C\u7D22\u90AE\u4EF6",
1438
+ "aria-label": "\u641C\u7D22\u90AE\u4EF6",
1340
1439
  value: query2,
1341
1440
  onChange: (event) => setQuery(event.target.value),
1342
1441
  onKeyDown: (event) => {
@@ -1347,78 +1446,96 @@ function MailPanel() {
1347
1446
  }
1348
1447
  }
1349
1448
  }),
1350
- query2 !== search || search !== "" ? (0, import_react6.createElement)(
1449
+ query2 !== search || search !== "" ? (0, import_react7.createElement)(
1351
1450
  "button",
1352
1451
  {
1353
- className: "subtle small",
1452
+ className: "subtle",
1453
+ title: "\u6E05\u9664\u641C\u7D22",
1354
1454
  onClick: () => {
1355
1455
  setQuery("");
1356
1456
  setSearch("");
1357
1457
  }
1358
1458
  },
1359
- "\u6E05\u9664"
1459
+ (0, import_react7.createElement)(Icon, { name: "close", size: 14 })
1360
1460
  ) : null
1361
1461
  ),
1362
- (0, import_react6.createElement)(
1462
+ (0, import_react7.createElement)(
1363
1463
  "div",
1364
1464
  { 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)(
1465
+ 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
1466
  "div",
1367
1467
  { 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",
1468
+ (0, import_react7.createElement)(Icon, { name: "mail", size: 28 }),
1469
+ (0, import_react7.createElement)(
1470
+ "div",
1471
+ { className: "title" },
1472
+ source === "local" ? "\u672C\u5730\u5907\u4EFD\u91CC\u8FD8\u6CA1\u6709\u90AE\u4EF6" : "\u670D\u52A1\u5668\u4E0A\u6CA1\u6709\u90AE\u4EF6"
1473
+ ),
1474
+ (0, import_react7.createElement)(
1475
+ "div",
1476
+ { className: "small" },
1477
+ 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"
1478
+ )
1479
+ ) : items.map(
1480
+ (item) => (0, import_react7.createElement)(
1481
+ "div",
1372
1482
  {
1373
1483
  key: item.id,
1374
1484
  className: `mailharbor-row${item.unread ? " unread" : ""}${selected?.id === item.id ? " selected" : ""}`,
1375
- onClick: () => void openMessage(item)
1485
+ role: "button",
1486
+ tabIndex: 0,
1487
+ onClick: () => void openMessage(item),
1488
+ onKeyDown: (event) => {
1489
+ if (event.key === "Enter" || event.key === " ") {
1490
+ event.preventDefault();
1491
+ void openMessage(item);
1492
+ }
1493
+ }
1376
1494
  },
1377
- (0, import_react6.createElement)(
1495
+ (0, import_react7.createElement)(
1378
1496
  "span",
1379
1497
  { className: "line-1" },
1380
- (0, import_react6.createElement)(
1498
+ item.unread ? (0, import_react7.createElement)("span", { className: "dot" }) : null,
1499
+ (0, import_react7.createElement)(
1381
1500
  "span",
1382
1501
  { className: "from" },
1383
1502
  item.from.name !== "" ? item.from.name : item.from.address
1384
1503
  ),
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))
1504
+ item.hasAttachments ? (0, import_react7.createElement)(Icon, { name: "paperclip", size: 13 }) : null,
1505
+ item.backedUp === false ? (0, import_react7.createElement)("span", { className: "badge warn" }, "\u672A\u5907\u4EFD") : null,
1506
+ (0, import_react7.createElement)("span", { className: "date" }, shortDate(item.date))
1387
1507
  ),
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)
1508
+ (0, import_react7.createElement)("span", { className: "line-2" }, (0, import_react7.createElement)("span", { className: "subject" }, item.subject)),
1509
+ item.snippet === "" ? null : (0, import_react7.createElement)("span", { className: "snippet" }, item.snippet)
1390
1510
  )
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
1511
+ )
1512
+ ),
1513
+ items.length > 0 ? (0, import_react7.createElement)(
1514
+ "div",
1515
+ { className: "mailharbor-list-foot" },
1516
+ (0, import_react7.createElement)("span", null, `${String(items.length)} / ${String(page.total)} \u5C01`),
1517
+ (0, import_react7.createElement)("span", { className: "spacer" }),
1518
+ page.total > items.length ? (0, import_react7.createElement)(
1519
+ "button",
1520
+ { className: "subtle", onClick: () => setLimit((current) => current + 40) },
1521
+ "\u52A0\u8F7D\u66F4\u591A"
1406
1522
  ) : null
1407
- )
1523
+ ) : null
1408
1524
  ),
1409
- (0, import_react6.createElement)(
1525
+ (0, import_react7.createElement)(
1410
1526
  "div",
1411
1527
  { className: "mailharbor-reader" },
1412
- selected === null ? (0, import_react6.createElement)(
1528
+ selected === null ? (0, import_react7.createElement)(
1413
1529
  "div",
1414
1530
  { 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",
1531
+ (0, import_react7.createElement)(Icon, { name: "mail", size: 34 }),
1532
+ (0, import_react7.createElement)("div", { className: "title" }, "\u9009\u62E9\u4E00\u5C01\u90AE\u4EF6\u5F00\u59CB\u9605\u8BFB"),
1533
+ (0, import_react7.createElement)(
1534
+ "div",
1418
1535
  { className: "small" },
1419
1536
  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
1537
  )
1421
- ) : (0, import_react6.createElement)(Reader, {
1538
+ ) : (0, import_react7.createElement)(Reader, {
1422
1539
  detail: selected,
1423
1540
  account,
1424
1541
  source,
@@ -1429,45 +1546,45 @@ function MailPanel() {
1429
1546
  })
1430
1547
  )
1431
1548
  ),
1432
- showBackup && backup !== null ? (0, import_react6.createElement)(
1549
+ showBackup && backup !== null ? (0, import_react7.createElement)(
1433
1550
  Modal,
1434
1551
  {
1435
1552
  title: "\u5907\u4EFD",
1436
1553
  onClose: () => setShowBackup(false),
1437
- footer: (0, import_react6.createElement)(
1554
+ footer: (0, import_react7.createElement)(
1438
1555
  "div",
1439
1556
  { 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")
1557
+ (0, import_react7.createElement)("span", { className: "small muted" }, backup.running ? "\u5907\u4EFD\u8FDB\u884C\u4E2D\u2026" : backup.message),
1558
+ (0, import_react7.createElement)("span", { className: "spacer" }),
1559
+ 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"),
1560
+ (0, import_react7.createElement)("button", { className: "ghost", onClick: () => setShowBackup(false) }, "\u5173\u95ED")
1444
1561
  )
1445
1562
  },
1446
- (0, import_react6.createElement)(
1563
+ (0, import_react7.createElement)(
1447
1564
  "div",
1448
1565
  { 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))
1566
+ (0, import_react7.createElement)("dt", null, "\u5F00\u59CB\u65F6\u95F4"),
1567
+ (0, import_react7.createElement)("dd", null, backup.startedAt ?? "\u2014"),
1568
+ (0, import_react7.createElement)("dt", null, "\u4E0A\u6B21\u6210\u529F"),
1569
+ (0, import_react7.createElement)("dd", null, backup.lastSuccessAt ?? "\u2014"),
1570
+ (0, import_react7.createElement)("dt", null, "\u65B0\u589E"),
1571
+ (0, import_react7.createElement)("dd", null, String(backup.added)),
1572
+ (0, import_react7.createElement)("dt", null, "\u603B\u6570"),
1573
+ (0, import_react7.createElement)("dd", null, String(backup.total))
1457
1574
  ),
1458
- (0, import_react6.createElement)(
1575
+ (0, import_react7.createElement)(
1459
1576
  "div",
1460
1577
  { className: "mailharbor-log" },
1461
1578
  backup.output.length === 0 ? "\uFF08\u7B49\u5F85\u8F93\u51FA\u2026\uFF09" : backup.output.join("\n")
1462
1579
  )
1463
1580
  ) : null,
1464
- compose !== null ? (0, import_react6.createElement)(Composer, {
1581
+ compose !== null ? (0, import_react7.createElement)(Composer, {
1465
1582
  account,
1466
1583
  initial: compose,
1467
1584
  onClose: () => setCompose(null),
1468
1585
  onSent: (message) => notice(message)
1469
1586
  }) : null,
1470
- showAdd ? (0, import_react6.createElement)(AddAccountModal, {
1587
+ showAdd ? (0, import_react7.createElement)(AddAccountModal, {
1471
1588
  onClose: () => setShowAdd(false),
1472
1589
  onDone: (next) => {
1473
1590
  setState(next);
@@ -1478,27 +1595,27 @@ function MailPanel() {
1478
1595
  }
1479
1596
 
1480
1597
  // src/client/settings.tsx
1481
- var import_react7 = require("react");
1598
+ var import_react8 = require("react");
1482
1599
  function errorText4(error) {
1483
1600
  return error instanceof ApiError || error instanceof Error ? error.message : String(error);
1484
1601
  }
1485
1602
  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)(() => {
1603
+ const [state, setState] = (0, import_react8.useState)(null);
1604
+ const [settings, setSettings] = (0, import_react8.useState)(null);
1605
+ const [error, setError] = (0, import_react8.useState)("");
1606
+ const [toast, setToast] = (0, import_react8.useState)("");
1607
+ const [signature, setSignature] = (0, import_react8.useState)("");
1608
+ const [markOnOpen, setMarkOnOpen] = (0, import_react8.useState)(true);
1609
+ const [pollSeconds, setPollSeconds] = (0, import_react8.useState)(60);
1610
+ const [listLimit, setListLimit] = (0, import_react8.useState)(40);
1611
+ const [aiEnabled, setAiEnabled] = (0, import_react8.useState)(true);
1612
+ const [aiProvider, setAiProvider] = (0, import_react8.useState)("deepseek-account");
1613
+ const [aiModel, setAiModel] = (0, import_react8.useState)("deepseek-flash");
1614
+ const [editing, setEditing] = (0, import_react8.useState)(null);
1615
+ const [checkResult, setCheckResult] = (0, import_react8.useState)("");
1616
+ const [adding, setAdding] = (0, import_react8.useState)(false);
1617
+ const [tick, setTick] = (0, import_react8.useState)(0);
1618
+ (0, import_react8.useEffect)(() => {
1502
1619
  let cancelled = false;
1503
1620
  Promise.all([api.state(), api.settings()]).then(([appState, view]) => {
1504
1621
  if (cancelled) return;
@@ -1536,24 +1653,24 @@ function MailSettings() {
1536
1653
  };
1537
1654
  const account = settings?.accounts.find((item) => item.id === settings.activeAccountId) ?? null;
1538
1655
  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);
1656
+ return (0, import_react8.createElement)("div", { className: "mailharbor mailharbor-settings" }, error === "" ? "\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026" : error);
1540
1657
  }
1541
- return (0, import_react7.createElement)(
1658
+ return (0, import_react8.createElement)(
1542
1659
  "div",
1543
1660
  { className: "mailharbor" },
1544
- (0, import_react7.createElement)(
1661
+ (0, import_react8.createElement)(
1545
1662
  "div",
1546
1663
  { 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)(
1664
+ (0, import_react8.createElement)("h2", null, "MailHarbor"),
1665
+ (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"),
1666
+ toast === "" ? null : (0, import_react8.createElement)("div", { className: "small", style: { color: "var(--m-ok)" } }, toast),
1667
+ error === "" ? null : (0, import_react8.createElement)(ErrorBar, { message: error, onDismiss: () => setError("") }),
1668
+ (0, import_react8.createElement)(
1552
1669
  "div",
1553
1670
  { 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, {
1671
+ (0, import_react8.createElement)("h3", null, "\u8D26\u53F7"),
1672
+ settings.accounts.length === 0 ? (0, import_react8.createElement)(AddAccountForm, { onDone: () => reload() }) : settings.accounts.map(
1673
+ (item) => (0, import_react8.createElement)(AccountRow, {
1557
1674
  key: item.id,
1558
1675
  account: item,
1559
1676
  active: item.id === settings.activeAccountId,
@@ -1597,32 +1714,32 @@ function MailSettings() {
1597
1714
  }
1598
1715
  })
1599
1716
  ),
1600
- adding ? (0, import_react7.createElement)(AddAccountForm, {
1717
+ adding ? (0, import_react8.createElement)(AddAccountForm, {
1601
1718
  onDone: () => {
1602
1719
  setAdding(false);
1603
1720
  reload();
1604
1721
  },
1605
1722
  onCancel: () => setAdding(false)
1606
- }) : (0, import_react7.createElement)("button", { className: "ghost", onClick: () => setAdding(true) }, "+ \u6DFB\u52A0\u8D26\u53F7")
1723
+ }) : (0, import_react8.createElement)("button", { className: "ghost", onClick: () => setAdding(true) }, "+ \u6DFB\u52A0\u8D26\u53F7")
1607
1724
  ),
1608
- (0, import_react7.createElement)(
1725
+ (0, import_react8.createElement)(
1609
1726
  "div",
1610
1727
  { className: "mailharbor-card" },
1611
- (0, import_react7.createElement)("h3", null, "\u5199\u4FE1\u4E0E\u9605\u8BFB"),
1612
- (0, import_react7.createElement)(
1728
+ (0, import_react8.createElement)("h3", null, "\u5199\u4FE1\u4E0E\u9605\u8BFB"),
1729
+ (0, import_react8.createElement)(
1613
1730
  Field,
1614
1731
  { 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", {
1732
+ (0, import_react8.createElement)("textarea", {
1616
1733
  rows: 4,
1617
1734
  value: signature,
1618
1735
  onChange: (event) => setSignature(event.target.value)
1619
1736
  })
1620
1737
  ),
1621
- (0, import_react7.createElement)(
1738
+ (0, import_react8.createElement)(
1622
1739
  "div",
1623
1740
  { 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, {
1741
+ (0, import_react8.createElement)("button", { className: "ghost", onClick: () => void saveGeneral({ signature }) }, "\u4FDD\u5B58\u7B7E\u540D"),
1742
+ (0, import_react8.createElement)(Toggle, {
1626
1743
  checked: markOnOpen,
1627
1744
  onChange: (value) => {
1628
1745
  setMarkOnOpen(value);
@@ -1631,13 +1748,13 @@ function MailSettings() {
1631
1748
  label: "\u6253\u5F00\u90AE\u4EF6\u65F6\u6807\u4E3A\u5DF2\u8BFB"
1632
1749
  })
1633
1750
  ),
1634
- (0, import_react7.createElement)(
1751
+ (0, import_react8.createElement)(
1635
1752
  "div",
1636
1753
  { className: "mailharbor-grid" },
1637
- (0, import_react7.createElement)(
1754
+ (0, import_react8.createElement)(
1638
1755
  Field,
1639
1756
  { label: "\u5217\u8868\u6BCF\u9875\u6570\u91CF" },
1640
- (0, import_react7.createElement)("input", {
1757
+ (0, import_react8.createElement)("input", {
1641
1758
  type: "number",
1642
1759
  min: 10,
1643
1760
  max: 200,
@@ -1646,10 +1763,10 @@ function MailSettings() {
1646
1763
  onBlur: () => void saveGeneral({ render: { listLimit } })
1647
1764
  })
1648
1765
  ),
1649
- (0, import_react7.createElement)(
1766
+ (0, import_react8.createElement)(
1650
1767
  Field,
1651
1768
  { label: "\u672A\u8BFB\u89D2\u6807\u8F6E\u8BE2\uFF08\u79D2\uFF09" },
1652
- (0, import_react7.createElement)("input", {
1769
+ (0, import_react8.createElement)("input", {
1653
1770
  type: "number",
1654
1771
  min: 15,
1655
1772
  max: 3600,
@@ -1660,11 +1777,11 @@ function MailSettings() {
1660
1777
  )
1661
1778
  )
1662
1779
  ),
1663
- (0, import_react7.createElement)(
1780
+ (0, import_react8.createElement)(
1664
1781
  "div",
1665
1782
  { className: "mailharbor-card" },
1666
- (0, import_react7.createElement)("h3", null, "AI"),
1667
- (0, import_react7.createElement)(Toggle, {
1783
+ (0, import_react8.createElement)("h3", null, "AI"),
1784
+ (0, import_react8.createElement)(Toggle, {
1668
1785
  checked: aiEnabled,
1669
1786
  onChange: (value) => {
1670
1787
  setAiEnabled(value);
@@ -1672,54 +1789,54 @@ function MailSettings() {
1672
1789
  },
1673
1790
  label: "\u542F\u7528 AI\uFF08\u6458\u8981\u3001\u8D77\u8349\u3001\u6DA6\u8272\u3001\u81EA\u7136\u8BED\u8A00\u641C\u7D22\uFF09"
1674
1791
  }),
1675
- (0, import_react7.createElement)(
1792
+ (0, import_react8.createElement)(
1676
1793
  "div",
1677
1794
  { className: "mailharbor-grid" },
1678
- (0, import_react7.createElement)(
1795
+ (0, import_react8.createElement)(
1679
1796
  Field,
1680
1797
  { label: "Provider" },
1681
- (0, import_react7.createElement)("input", {
1798
+ (0, import_react8.createElement)("input", {
1682
1799
  value: aiProvider,
1683
1800
  onChange: (event) => setAiProvider(event.target.value),
1684
1801
  onBlur: () => void saveGeneral({ ai: { provider: aiProvider } })
1685
1802
  })
1686
1803
  ),
1687
- (0, import_react7.createElement)(
1804
+ (0, import_react8.createElement)(
1688
1805
  Field,
1689
1806
  { label: "\u6A21\u578B" },
1690
- (0, import_react7.createElement)("input", {
1807
+ (0, import_react8.createElement)("input", {
1691
1808
  value: aiModel,
1692
1809
  onChange: (event) => setAiModel(event.target.value),
1693
1810
  onBlur: () => void saveGeneral({ ai: { model: aiModel } })
1694
1811
  })
1695
1812
  )
1696
1813
  ),
1697
- (0, import_react7.createElement)(
1814
+ (0, import_react8.createElement)(
1698
1815
  "p",
1699
1816
  { className: "small muted" },
1700
1817
  "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
1818
  )
1702
1819
  ),
1703
- (0, import_react7.createElement)(
1820
+ (0, import_react8.createElement)(
1704
1821
  "div",
1705
1822
  { className: "mailharbor-card" },
1706
- (0, import_react7.createElement)("h3", null, "\u6570\u636E"),
1707
- (0, import_react7.createElement)(
1823
+ (0, import_react8.createElement)("h3", null, "\u6570\u636E"),
1824
+ (0, import_react8.createElement)(
1708
1825
  "dl",
1709
1826
  { 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)
1827
+ (0, import_react8.createElement)("dt", null, "\u6570\u636E\u76EE\u5F55"),
1828
+ (0, import_react8.createElement)("dd", null, settings.dataDir),
1829
+ (0, import_react8.createElement)("dt", null, "\u914D\u7F6E\u6587\u4EF6"),
1830
+ (0, import_react8.createElement)("dd", null, settings.configFile),
1831
+ (0, import_react8.createElement)("dt", null, "\u5F53\u524D\u8D26\u53F7\u6570\u636E\u5E93"),
1832
+ (0, import_react8.createElement)("dd", null, account === null ? "\u2014" : `${settings.dataDir}/accounts/${account.id}/mail.db`),
1833
+ (0, import_react8.createElement)("dt", null, "\u63D2\u4EF6\u7248\u672C"),
1834
+ (0, import_react8.createElement)("dd", null, state.version)
1718
1835
  ),
1719
- (0, import_react7.createElement)(
1836
+ (0, import_react8.createElement)(
1720
1837
  "div",
1721
1838
  { style: { display: "flex", gap: "8px", flexWrap: "wrap" } },
1722
- account === null ? null : (0, import_react7.createElement)(
1839
+ account === null ? null : (0, import_react8.createElement)(
1723
1840
  "button",
1724
1841
  {
1725
1842
  className: "ghost",
@@ -1754,19 +1871,19 @@ function AccountRow({
1754
1871
  onSave,
1755
1872
  onRemove
1756
1873
  }) {
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)(() => {
1874
+ const [password, setPassword] = (0, import_react8.useState)("");
1875
+ const [remember, setRemember] = (0, import_react8.useState)(true);
1876
+ const [label, setLabel] = (0, import_react8.useState)(account.label);
1877
+ const [username, setUsername] = (0, import_react8.useState)(account.username);
1878
+ const [imapHost, setImapHost] = (0, import_react8.useState)(account.imap.host);
1879
+ const [imapPort, setImapPort] = (0, import_react8.useState)(String(account.imap.port));
1880
+ const [imapSecure, setImapSecure] = (0, import_react8.useState)(account.imap.secure);
1881
+ const [smtpHost, setSmtpHost] = (0, import_react8.useState)(account.smtp.host);
1882
+ const [smtpPort, setSmtpPort] = (0, import_react8.useState)(String(account.smtp.port));
1883
+ const [smtpSecure, setSmtpSecure] = (0, import_react8.useState)(account.smtp.secure);
1884
+ const [fromName, setFromName] = (0, import_react8.useState)(account.smtp.fromName);
1885
+ const [busy, setBusy] = (0, import_react8.useState)(false);
1886
+ (0, import_react8.useEffect)(() => {
1770
1887
  setLabel(account.label);
1771
1888
  setUsername(account.username);
1772
1889
  setImapHost(account.imap.host);
@@ -1785,103 +1902,103 @@ function AccountRow({
1785
1902
  setBusy(false);
1786
1903
  }
1787
1904
  };
1788
- return (0, import_react7.createElement)(
1905
+ return (0, import_react8.createElement)(
1789
1906
  "div",
1790
1907
  { className: "mailharbor-card", style: { background: "var(--m-bg-1)" } },
1791
- (0, import_react7.createElement)(
1908
+ (0, import_react8.createElement)(
1792
1909
  "div",
1793
1910
  { className: "mailharbor-account-row" },
1794
- (0, import_react7.createElement)(Avatar, { email: account.email, size: 30 }),
1795
- (0, import_react7.createElement)(
1911
+ (0, import_react8.createElement)(Avatar, { email: account.email, size: 30 }),
1912
+ (0, import_react8.createElement)(
1796
1913
  "div",
1797
1914
  { 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)
1915
+ (0, import_react8.createElement)("strong", null, account.label),
1916
+ (0, import_react8.createElement)("span", { className: "small muted" }, account.email)
1800
1917
  ),
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")
1918
+ active ? (0, import_react8.createElement)("span", { className: "badge ok" }, "\u5F53\u524D\u8D26\u53F7") : null,
1919
+ loggedIn === false ? (0, import_react8.createElement)("span", { className: "badge warn" }, "\u672A\u767B\u5F55") : null,
1920
+ (0, import_react8.createElement)("span", { className: "spacer" }),
1921
+ active ? null : (0, import_react8.createElement)("button", { className: "ghost small", onClick: () => void wrap(onActivate) }, "\u8BBE\u4E3A\u5F53\u524D"),
1922
+ (0, import_react8.createElement)("button", { className: "ghost small", onClick: () => void wrap(onCheck) }, "\u68C0\u67E5\u8FDE\u63A5"),
1923
+ (0, import_react8.createElement)("button", { className: "ghost small", onClick: onToggleEdit }, editing ? "\u6536\u8D77" : "\u7F16\u8F91")
1807
1924
  ),
1808
- editing ? (0, import_react7.createElement)(
1925
+ editing ? (0, import_react8.createElement)(
1809
1926
  "div",
1810
1927
  { style: { display: "flex", flexDirection: "column", gap: "10px" } },
1811
- (0, import_react7.createElement)(
1928
+ (0, import_react8.createElement)(
1812
1929
  "div",
1813
1930
  { className: "mailharbor-grid" },
1814
- (0, import_react7.createElement)(
1931
+ (0, import_react8.createElement)(
1815
1932
  Field,
1816
1933
  { label: "\u663E\u793A\u540D\u79F0" },
1817
- (0, import_react7.createElement)("input", {
1934
+ (0, import_react8.createElement)("input", {
1818
1935
  value: label,
1819
1936
  onChange: (event) => setLabel(event.target.value)
1820
1937
  })
1821
1938
  ),
1822
- (0, import_react7.createElement)(
1939
+ (0, import_react8.createElement)(
1823
1940
  Field,
1824
1941
  { label: "\u767B\u5F55\u7528\u6237\u540D" },
1825
- (0, import_react7.createElement)("input", {
1942
+ (0, import_react8.createElement)("input", {
1826
1943
  value: username,
1827
1944
  onChange: (event) => setUsername(event.target.value)
1828
1945
  })
1829
1946
  )
1830
1947
  ),
1831
- (0, import_react7.createElement)(
1948
+ (0, import_react8.createElement)(
1832
1949
  "div",
1833
1950
  { className: "mailharbor-grid three" },
1834
- (0, import_react7.createElement)(
1951
+ (0, import_react8.createElement)(
1835
1952
  Field,
1836
1953
  { label: "IMAP \u4E3B\u673A" },
1837
- (0, import_react7.createElement)("input", {
1954
+ (0, import_react8.createElement)("input", {
1838
1955
  value: imapHost,
1839
1956
  onChange: (event) => setImapHost(event.target.value)
1840
1957
  })
1841
1958
  ),
1842
- (0, import_react7.createElement)(
1959
+ (0, import_react8.createElement)(
1843
1960
  Field,
1844
1961
  { label: "\u7AEF\u53E3" },
1845
- (0, import_react7.createElement)("input", {
1962
+ (0, import_react8.createElement)("input", {
1846
1963
  value: imapPort,
1847
1964
  onChange: (event) => setImapPort(event.target.value)
1848
1965
  })
1849
1966
  ),
1850
- (0, import_react7.createElement)(Toggle, { checked: imapSecure, onChange: setImapSecure, label: "TLS" })
1967
+ (0, import_react8.createElement)(Toggle, { checked: imapSecure, onChange: setImapSecure, label: "TLS" })
1851
1968
  ),
1852
- (0, import_react7.createElement)(
1969
+ (0, import_react8.createElement)(
1853
1970
  "div",
1854
1971
  { className: "mailharbor-grid three" },
1855
- (0, import_react7.createElement)(
1972
+ (0, import_react8.createElement)(
1856
1973
  Field,
1857
1974
  { label: "SMTP \u4E3B\u673A" },
1858
- (0, import_react7.createElement)("input", {
1975
+ (0, import_react8.createElement)("input", {
1859
1976
  value: smtpHost,
1860
1977
  onChange: (event) => setSmtpHost(event.target.value)
1861
1978
  })
1862
1979
  ),
1863
- (0, import_react7.createElement)(
1980
+ (0, import_react8.createElement)(
1864
1981
  Field,
1865
1982
  { label: "\u7AEF\u53E3" },
1866
- (0, import_react7.createElement)("input", {
1983
+ (0, import_react8.createElement)("input", {
1867
1984
  value: smtpPort,
1868
1985
  onChange: (event) => setSmtpPort(event.target.value)
1869
1986
  })
1870
1987
  ),
1871
- (0, import_react7.createElement)(Toggle, { checked: smtpSecure, onChange: setSmtpSecure, label: "TLS" })
1988
+ (0, import_react8.createElement)(Toggle, { checked: smtpSecure, onChange: setSmtpSecure, label: "TLS" })
1872
1989
  ),
1873
- (0, import_react7.createElement)(
1990
+ (0, import_react8.createElement)(
1874
1991
  Field,
1875
1992
  { label: "\u53D1\u4EF6\u4EBA\u540D\u79F0" },
1876
- (0, import_react7.createElement)("input", {
1993
+ (0, import_react8.createElement)("input", {
1877
1994
  value: fromName,
1878
1995
  onChange: (event) => setFromName(event.target.value)
1879
1996
  })
1880
1997
  ),
1881
- (0, import_react7.createElement)(
1998
+ (0, import_react8.createElement)(
1882
1999
  "div",
1883
2000
  { style: { display: "flex", gap: "8px", alignItems: "center", flexWrap: "wrap" } },
1884
- (0, import_react7.createElement)(
2001
+ (0, import_react8.createElement)(
1885
2002
  "button",
1886
2003
  {
1887
2004
  className: "primary small",
@@ -1897,7 +2014,7 @@ function AccountRow({
1897
2014
  },
1898
2015
  "\u4FDD\u5B58\u8D26\u53F7"
1899
2016
  ),
1900
- (0, import_react7.createElement)(
2017
+ (0, import_react8.createElement)(
1901
2018
  "button",
1902
2019
  {
1903
2020
  className: "ghost small danger",
@@ -1906,21 +2023,21 @@ function AccountRow({
1906
2023
  "\u79FB\u9664\u8D26\u53F7"
1907
2024
  )
1908
2025
  ),
1909
- (0, import_react7.createElement)("hr", { style: { border: 0, borderTop: "1px solid var(--m-line)", width: "100%" } }),
1910
- (0, import_react7.createElement)(
2026
+ (0, import_react8.createElement)("hr", { style: { border: 0, borderTop: "1px solid var(--m-line)", width: "100%" } }),
2027
+ (0, import_react8.createElement)(
1911
2028
  Field,
1912
2029
  { label: "\u5BC6\u7801 / \u5E94\u7528\u4E13\u7528\u5BC6\u7801\uFF08\u4E0D\u5199\u5165\u914D\u7F6E\u6587\u4EF6\uFF09" },
1913
- (0, import_react7.createElement)("input", {
2030
+ (0, import_react8.createElement)("input", {
1914
2031
  type: "password",
1915
2032
  value: password,
1916
2033
  onChange: (event) => setPassword(event.target.value)
1917
2034
  })
1918
2035
  ),
1919
- (0, import_react7.createElement)(
2036
+ (0, import_react8.createElement)(
1920
2037
  "div",
1921
2038
  { 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)(
2039
+ (0, import_react8.createElement)(Toggle, { checked: remember, onChange: setRemember, label: "\u8BB0\u4F4F\u5BC6\u7801" }),
2040
+ (0, import_react8.createElement)(
1924
2041
  "button",
1925
2042
  {
1926
2043
  className: "primary small",
@@ -1932,15 +2049,15 @@ function AccountRow({
1932
2049
  },
1933
2050
  "\u767B\u5F55"
1934
2051
  ),
1935
- (0, import_react7.createElement)("button", { className: "ghost small", onClick: () => void wrap(onLogout) }, "\u9000\u51FA\u767B\u5F55")
2052
+ (0, import_react8.createElement)("button", { className: "ghost small", onClick: () => void wrap(onLogout) }, "\u9000\u51FA\u767B\u5F55")
1936
2053
  ),
1937
- checkResult === "" ? null : (0, import_react7.createElement)("div", { className: "small muted" }, checkResult)
2054
+ checkResult === "" ? null : (0, import_react8.createElement)("div", { className: "small muted" }, checkResult)
1938
2055
  ) : null
1939
2056
  );
1940
2057
  }
1941
2058
 
1942
2059
  // src/client/index.tsx
1943
- var VERSION = "0.1.0";
2060
+ var VERSION = "0.2.0";
1944
2061
  var inject = ["slots"];
1945
2062
  var PANEL_ID = "mailharbor";
1946
2063
  var STYLE_ID = "mailharbor-style";