`;
+ }
+
+ private renderForwardModal(): string {
+ if (!this._fwdModalOpen) return '';
+
+ let content = '';
+
+ if (this._fwdStatus === 'ready') {
+ content = `
+
+
+
${this.escapeHtml(this._fwdAddress)}
→
${this.escapeHtml(this._fwdTarget)}
-
-
+
Mail sent to your rInbox address will be forwarded to your personal email.
+
+ 🔒 Your email is stored locally with your EncryptID keys — sovereign and encrypted on your device.
+
+
+
+
+
`;
+ } else if (this._fwdStatus === 'enabled') {
+ content = `
+
+
+
+ Forwarding Active
+
+
+
+ ${this.escapeHtml(this._fwdAddress)}
+ →
+ ${this.escapeHtml(this._fwdTarget)}
+
+
+
+ 🔒 Your email is stored locally with your EncryptID keys — sovereign and encrypted on your device.
+
+
+
+
+
+
`;
+ } else if (this._fwdStatus === 'no-email') {
+ content = `
+
+
Connect an email address to receive forwarded mail from your rInbox.
+
+ 🔒 Your email is stored locally with your EncryptID keys — never on a central server. Only you control your contact info.
+
+
+
+
+
+
+
+
+
+
`;
+ } else if (this._fwdStatus === 'error') {
+ content = `
+
+
${this.escapeHtml(this._fwdError)}
+
+
+
+
`;
}
- if (this._fwdStatus === 'no-email') {
- return `
-
-
-
Forward rInbox to your email
-
Add a verified email to your profile to enable forwarding.
-
-
-
`;
- }
-
- if (this._fwdStatus === 'error') {
- return `
-
-
-
${this.escapeHtml(this._fwdError)}
-
-
-
-
-
`;
- }
-
- return '';
+ return `
+
+
+
+
📩 Email Forwarding
+ ${content}
+
+
`;
}
private timeAgo(dateStr: string): string {
@@ -663,31 +732,40 @@ class FolkInboxClient extends HTMLElement {
.sample-banner { padding: 8px 16px; background: rgba(99,102,241,0.12); border: 1px solid rgba(99,102,241,0.25); border-radius: 8px; color: #a5b4fc; font-size: 13px; text-align: center; margin-bottom: 12px; }
- /* Forwarding banner */
- .fwd-banner { display: flex; align-items: center; gap: 1rem; padding: 0.75rem 1rem; border-radius: 10px; margin-bottom: 12px; border: 1px solid; }
- .fwd-banner.fwd-ready { background: rgba(99,102,241,0.08); border-color: rgba(99,102,241,0.25); }
- .fwd-banner.fwd-enabled { background: rgba(34,197,94,0.08); border-color: rgba(34,197,94,0.25); }
- .fwd-banner.fwd-no-email { background: rgba(251,191,36,0.08); border-color: rgba(251,191,36,0.25); }
- .fwd-banner.fwd-error { background: rgba(239,68,68,0.08); border-color: rgba(239,68,68,0.25); }
- .fwd-banner-content { flex: 1; min-width: 0; }
- .fwd-banner-title { font-size: 0.85rem; font-weight: 600; color: var(--rs-text-primary); margin-bottom: 2px; }
- .fwd-banner-desc { font-size: 0.8rem; color: var(--rs-text-secondary); }
- .fwd-banner-route { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
- .fwd-banner-route code { font-size: 0.75rem; color: #818cf8; background: rgba(99,102,241,0.1); padding: 2px 6px; border-radius: 4px; }
- .fwd-enabled .fwd-banner-route code { color: #4ade80; background: rgba(34,197,94,0.1); }
- .fwd-arrow { color: var(--rs-text-muted); font-size: 0.8rem; }
- .fwd-banner-actions { display: flex; gap: 0.5rem; align-items: center; flex-shrink: 0; }
- .fwd-btn-enable { padding: 6px 14px; border-radius: 6px; border: none; background: linear-gradient(135deg, #6366f1, #0891b2); color: white; cursor: pointer; font-size: 0.8rem; font-weight: 600; transition: opacity 0.15s; }
+ /* Forwarding trigger */
+ .fwd-trigger { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; margin-bottom: 12px; cursor: pointer; border-radius: 8px; font-size: 0.8rem; color: var(--rs-text-secondary); transition: background 0.15s; }
+ .fwd-trigger:hover { background: var(--rs-bg-hover); }
+ .fwd-trigger-enabled { color: #4ade80; }
+ .fwd-trigger-enabled code { font-size: 0.75rem; color: #4ade80; background: rgba(34,197,94,0.1); padding: 2px 6px; border-radius: 4px; }
+ .fwd-trigger-icon { font-size: 1rem; }
+ .fwd-trigger-link { color: #818cf8; font-weight: 500; }
+ .fwd-trigger-enabled .fwd-trigger-link { color: rgba(74,222,128,0.7); font-weight: 400; margin-left: auto; }
+ .fwd-trigger-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; }
+ .fwd-dot-active { background: #4ade80; box-shadow: 0 0 6px rgba(74,222,128,0.5); }
+
+ /* Forwarding modal overlay */
+ .fwd-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 10000; display: flex; align-items: center; justify-content: center; padding: 1rem; }
+ .fwd-modal { background: var(--rs-bg-surface-sunken); border: 1px solid var(--rs-border-strong); border-radius: 16px; max-width: 480px; width: 100%; padding: 2rem; position: relative; }
+ .fwd-modal-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 1.25rem; color: var(--rs-text-primary); }
+ .fwd-modal-status { margin-bottom: 1.25rem; }
+ .fwd-modal-status-badge { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.75rem; border-radius: 6px; font-size: 0.85rem; font-weight: 600; margin-bottom: 0.75rem; }
+ .fwd-status-active { background: rgba(34,197,94,0.1); color: #4ade80; }
+ .fwd-modal-route { margin: 0.75rem 0; }
+ .fwd-modal-route-line { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
+ .fwd-modal-route-line code { font-size: 0.8rem; color: #818cf8; background: rgba(99,102,241,0.1); padding: 3px 8px; border-radius: 4px; }
+ .fwd-arrow { color: var(--rs-text-muted); font-size: 0.85rem; }
+ .fwd-modal-desc { font-size: 0.85rem; color: var(--rs-text-secondary); line-height: 1.5; margin: 0.5rem 0; }
+ .fwd-sovereignty { font-size: 0.8rem; color: var(--rs-text-muted); line-height: 1.5; padding: 0.75rem; background: rgba(99,102,241,0.06); border: 1px solid rgba(99,102,241,0.15); border-radius: 8px; margin-top: 0.75rem; }
+ .fwd-modal-error { font-size: 0.85rem; color: #f87171; padding: 0.75rem; background: rgba(239,68,68,0.08); border: 1px solid rgba(239,68,68,0.2); border-radius: 8px; }
+ .fwd-modal-actions { display: flex; gap: 0.5rem; justify-content: flex-end; }
+ .fwd-btn-enable { padding: 8px 18px; border-radius: 8px; border: none; background: linear-gradient(135deg, #6366f1, #0891b2); color: white; cursor: pointer; font-size: 0.85rem; font-weight: 600; transition: opacity 0.15s; }
.fwd-btn-enable:hover { opacity: 0.9; }
.fwd-btn-enable:disabled { opacity: 0.5; cursor: not-allowed; }
- .fwd-btn-disable { padding: 6px 12px; border-radius: 6px; border: 1px solid rgba(34,197,94,0.3); background: transparent; color: #4ade80; cursor: pointer; font-size: 0.75rem; transition: all 0.15s; }
- .fwd-btn-disable:hover { border-color: rgba(34,197,94,0.6); background: rgba(34,197,94,0.1); }
+ .fwd-btn-disable { padding: 8px 18px; border-radius: 8px; border: 1px solid rgba(239,68,68,0.3); background: transparent; color: #f87171; cursor: pointer; font-size: 0.85rem; font-weight: 500; transition: all 0.15s; }
+ .fwd-btn-disable:hover { border-color: rgba(239,68,68,0.5); background: rgba(239,68,68,0.08); }
.fwd-btn-disable:disabled { opacity: 0.5; cursor: not-allowed; }
- .fwd-btn-dismiss { padding: 6px 10px; border-radius: 6px; border: none; background: transparent; color: var(--rs-text-muted); cursor: pointer; font-size: 0.75rem; transition: color 0.15s; }
- .fwd-btn-dismiss:hover { color: var(--rs-text-secondary); }
- .fwd-btn-profile { padding: 6px 14px; border-radius: 6px; border: 1px solid rgba(251,191,36,0.3); background: rgba(251,191,36,0.1); color: #fbbf24; text-decoration: none; font-size: 0.8rem; font-weight: 500; transition: all 0.15s; }
- .fwd-btn-profile:hover { border-color: rgba(251,191,36,0.5); background: rgba(251,191,36,0.15); }
- .fwd-error .fwd-banner-title { color: #f87171; }
+ .fwd-btn-cancel { padding: 8px 18px; border-radius: 8px; border: 1px solid var(--rs-border-strong); background: transparent; color: var(--rs-text-secondary); cursor: pointer; font-size: 0.85rem; transition: all 0.15s; }
+ .fwd-btn-cancel:hover { border-color: var(--rs-border-strong); color: var(--rs-text-primary); }
@media (max-width: 768px) {
.mailbox-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
@@ -695,8 +773,7 @@ class FolkInboxClient extends HTMLElement {
.thread-row { flex-wrap: wrap; gap: 4px; }
}
@media (max-width: 480px) {
- .fwd-banner { flex-direction: column; align-items: stretch; gap: 0.5rem; }
- .fwd-banner-actions { justify-content: flex-end; }
+ .fwd-modal { padding: 1.25rem; }
.rapp-nav { gap: 0.25rem; }
.nav-btn { padding: 4px 8px; font-size: 12px; }
.inbox-header { padding: 0.625rem 0.75rem; gap: 0.5rem; }
@@ -715,9 +792,10 @@ class FolkInboxClient extends HTMLElement {
${this.renderNav()}
${this.showingSampleData ? '
Showing sample data — create a mailbox to get started
' : ''}
- ${this.view === 'mailboxes' ? this.renderForwardBanner() : ''}
+ ${this.view === 'mailboxes' ? this.renderForwardTrigger() : ''}
${this.renderView()}
${this.helpOpen ? this.renderHelp() : ""}
+ ${this.renderForwardModal()}
`;
this.bindEvents();
@@ -1337,10 +1415,24 @@ class FolkInboxClient extends HTMLElement {
helpClose.addEventListener("click", () => { this.helpOpen = false; this.render(); });
}
- // Forwarding banner actions
+ // Forwarding trigger + modal actions
+ this.shadow.querySelector("[data-action='fwd-open']")?.addEventListener("click", () => {
+ this._fwdModalOpen = true; this.render();
+ });
this.shadow.querySelector("[data-action='fwd-enable']")?.addEventListener("click", () => this._enableForwarding());
this.shadow.querySelector("[data-action='fwd-disable']")?.addEventListener("click", () => this._disableForwarding());
- this.shadow.querySelector("[data-action='fwd-dismiss']")?.addEventListener("click", () => this._dismissForwardBanner());
+ this.shadow.querySelector("[data-action='fwd-save-enable']")?.addEventListener("click", () => this._saveEmailAndEnable());
+ this.shadow.querySelectorAll("[data-action='fwd-close']").forEach(btn => {
+ btn.addEventListener("click", () => { this._fwdModalOpen = false; this.render(); });
+ });
+ const fwdOverlay = this.shadow.querySelector("[data-action='fwd-close-overlay']");
+ if (fwdOverlay) {
+ fwdOverlay.addEventListener("click", (e) => {
+ if ((e.target as HTMLElement).dataset.action === "fwd-close-overlay") {
+ this._fwdModalOpen = false; this.render();
+ }
+ });
+ }
// Mailbox click
this.shadow.querySelectorAll("[data-mailbox]").forEach((card) => {