mirror of
https://github.com/ghostersk/gowebmail.git
synced 2026-04-17 16:46:01 +01:00
252 lines
15 KiB
HTML
252 lines
15 KiB
HTML
{{template "base" .}}
|
|
{{define "title"}}GoMail{{end}}
|
|
{{define "body_class"}}app-page{{end}}
|
|
|
|
{{define "body"}}
|
|
<div class="app">
|
|
<!-- Sidebar -->
|
|
<aside class="sidebar">
|
|
<div class="sidebar-header">
|
|
<div class="logo">
|
|
<div class="logo-icon"><svg viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg></div>
|
|
<span class="logo-text">GoMail</span>
|
|
</div>
|
|
<button class="compose-btn" onclick="openCompose()">+ Compose</button>
|
|
</div>
|
|
|
|
<div class="accounts-section">
|
|
<div class="section-label">Accounts</div>
|
|
<div id="accounts-list"></div>
|
|
<div class="add-account-btn" onclick="openModal('add-account-modal')">
|
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
|
Connect account
|
|
</div>
|
|
</div>
|
|
|
|
<div class="nav-section">
|
|
<div class="nav-item active" id="nav-unified" onclick="selectFolder('unified','Unified Inbox')">
|
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg>
|
|
Unified Inbox
|
|
<span class="unread-badge" id="unread-total" style="display:none"></span>
|
|
</div>
|
|
<div class="nav-item" id="nav-starred" onclick="selectFolder('starred','Starred')">
|
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>
|
|
Starred
|
|
</div>
|
|
<div id="folders-by-account"></div>
|
|
</div>
|
|
|
|
<div class="sidebar-footer">
|
|
<div class="user-info">
|
|
<span class="user-name" id="user-display">...</span>
|
|
<a href="/admin" id="admin-link" style="display:none;font-size:11px;color:var(--accent);text-decoration:none">Admin</a>
|
|
</div>
|
|
<div class="footer-actions">
|
|
<button class="icon-btn" onclick="openSettings()" title="Settings">
|
|
<svg viewBox="0 0 24 24"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>
|
|
</button>
|
|
<button class="icon-btn" onclick="doLogout()" title="Sign out">
|
|
<svg viewBox="0 0 24 24"><path d="M17 7l-1.41 1.41L18.17 11H8v2h10.17l-2.58 2.58L17 17l5-5zM4 5h8V3H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h8v-2H4V5z"/></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Message list -->
|
|
<div class="message-list-panel">
|
|
<div class="panel-header">
|
|
<span class="panel-title" id="panel-title">Unified Inbox</span>
|
|
<span class="panel-count" id="panel-count"></span>
|
|
</div>
|
|
<div class="search-bar">
|
|
<div class="search-wrap">
|
|
<svg viewBox="0 0 24 24"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
|
|
<input class="search-input" type="text" id="search-input" placeholder="Search emails..." oninput="handleSearch(this.value)">
|
|
</div>
|
|
</div>
|
|
<div class="message-list" id="message-list">
|
|
<div class="spinner" style="margin-top:60px"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Message detail -->
|
|
<main class="message-detail" id="message-detail">
|
|
<div class="no-message">
|
|
<svg viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg>
|
|
<h3>Select a message</h3>
|
|
<p>Choose a message from the list to read it</p>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Compose window -->
|
|
<div class="compose-overlay" id="compose-overlay">
|
|
<div class="compose-window" id="compose-window">
|
|
<div id="compose-resize-handle"></div>
|
|
<div class="compose-header">
|
|
<span class="compose-title" id="compose-title">New Message</span>
|
|
<button class="compose-close" onclick="closeCompose()">×</button>
|
|
</div>
|
|
<div class="compose-field"><label>From</label><select id="compose-from"></select></div>
|
|
<div class="compose-field compose-tag-field"><label>To</label><div id="compose-to" class="tag-container"></div></div>
|
|
<div class="compose-field compose-tag-field" id="cc-row" style="display:none"><label>CC</label><div id="compose-cc-tags" class="tag-container"></div></div>
|
|
<div class="compose-field compose-tag-field" id="bcc-row" style="display:none"><label>BCC</label><div id="compose-bcc-tags" class="tag-container"></div></div>
|
|
<div class="compose-field"><label>Subject</label><input type="text" id="compose-subject" oninput="S.draftDirty=true"></div>
|
|
<div class="compose-toolbar">
|
|
<button class="fmt-btn" title="Bold" onclick="execFmt('bold')"><b>B</b></button>
|
|
<button class="fmt-btn" title="Italic" onclick="execFmt('italic')"><i>I</i></button>
|
|
<button class="fmt-btn" title="Underline" onclick="execFmt('underline')"><u>U</u></button>
|
|
<span class="fmt-sep"></span>
|
|
<button class="fmt-btn" title="Bullets" onclick="execFmt('insertUnorderedList')">•—</button>
|
|
<button class="fmt-btn" title="Numbers" onclick="execFmt('insertOrderedList')">1—</button>
|
|
<span class="fmt-sep"></span>
|
|
<button class="fmt-btn" title="Link" onclick="insertLink()">🔗</button>
|
|
<button class="fmt-btn" title="Clear format" onclick="execFmt('removeFormat')">T⃗</button>
|
|
</div>
|
|
<div id="compose-editor" contenteditable="true" class="compose-editor" placeholder="Write your message..."></div>
|
|
<div id="compose-attach-list" class="compose-attach-list"></div>
|
|
<div class="compose-footer">
|
|
<button class="send-btn" id="send-btn" onclick="sendMessage()">Send</button>
|
|
<div style="display:flex;gap:6px;margin-left:4px">
|
|
<button class="btn-secondary" style="font-size:12px" onclick="document.getElementById('cc-row').style.display='flex'">+CC</button>
|
|
<button class="btn-secondary" style="font-size:12px" onclick="document.getElementById('bcc-row').style.display='flex'">+BCC</button>
|
|
<button class="btn-secondary" style="font-size:12px" onclick="triggerAttach()">📎 Attach</button>
|
|
<button class="btn-secondary" style="font-size:12px" onclick="saveDraft()">✎ Draft</button>
|
|
</div>
|
|
<input type="file" id="compose-attach-input" multiple style="display:none" onchange="handleAttachFiles(this)">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Account Modal -->
|
|
<div class="modal-overlay" id="add-account-modal">
|
|
<div class="modal">
|
|
<h2>Connect an account</h2>
|
|
<p>Connect Gmail or Outlook via OAuth, or any email via IMAP/SMTP.</p>
|
|
<div class="provider-btns">
|
|
<button class="provider-btn" id="btn-gmail" onclick="connectOAuth('gmail')">
|
|
<svg viewBox="0 0 24 24" width="18" height="18"><path fill="#EA4335" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#4285F4" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>
|
|
Gmail
|
|
</button>
|
|
<button class="provider-btn" id="btn-outlook" onclick="connectOAuth('outlook')">
|
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="#0078D4"><path d="M21.179 4.781H11.25V12h9.929V4.781zM11.25 19.219h9.929V12H11.25v7.219zM2.821 12H11.25V4.781H2.821V12zm0 7.219H11.25V12H2.821v7.219z"/></svg>
|
|
Outlook
|
|
</button>
|
|
</div>
|
|
<div class="modal-divider"><span>or add IMAP account</span></div>
|
|
<div class="modal-field"><label>Email Address</label><input type="email" id="imap-email" placeholder="you@example.com"></div>
|
|
<div class="modal-field"><label>Display Name</label><input type="text" id="imap-name" placeholder="Your Name"></div>
|
|
<div class="modal-field"><label>Password / App Password</label><input type="password" id="imap-password"></div>
|
|
<div class="modal-row">
|
|
<div class="modal-field"><label>IMAP Host</label><input type="text" id="imap-host" placeholder="imap.example.com"></div>
|
|
<div class="modal-field"><label>IMAP Port</label><input type="number" id="imap-port" value="993"></div>
|
|
</div>
|
|
<div class="modal-row">
|
|
<div class="modal-field"><label>SMTP Host</label><input type="text" id="smtp-host" placeholder="smtp.example.com"></div>
|
|
<div class="modal-field"><label>SMTP Port</label><input type="number" id="smtp-port" value="587"></div>
|
|
</div>
|
|
<div class="test-result" id="test-result"></div>
|
|
<div class="modal-actions">
|
|
<button class="modal-cancel" onclick="closeModal('add-account-modal')">Cancel</button>
|
|
<button class="btn-secondary" onclick="testNewConnection()" id="test-btn">Test Connection</button>
|
|
<button class="modal-submit" onclick="addIMAPAccount()" id="save-acct-btn">Connect</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Account Modal -->
|
|
<div class="modal-overlay" id="edit-account-modal">
|
|
<div class="modal">
|
|
<h2>Account Settings</h2>
|
|
<p id="edit-account-email" style="font-weight:500;color:var(--text);margin-bottom:16px"></p>
|
|
<input type="hidden" id="edit-account-id">
|
|
<div class="modal-field"><label>Display Name</label><input type="text" id="edit-name"></div>
|
|
<div class="modal-field"><label>New Password (leave blank to keep current)</label><input type="password" id="edit-password"></div>
|
|
<div class="modal-row">
|
|
<div class="modal-field"><label>IMAP Host</label><input type="text" id="edit-imap-host"></div>
|
|
<div class="modal-field"><label>IMAP Port</label><input type="number" id="edit-imap-port"></div>
|
|
</div>
|
|
<div class="modal-row">
|
|
<div class="modal-field"><label>SMTP Host</label><input type="text" id="edit-smtp-host"></div>
|
|
<div class="modal-field"><label>SMTP Port</label><input type="number" id="edit-smtp-port"></div>
|
|
</div>
|
|
<div class="settings-group-title" style="margin:16px 0 8px">Sync Settings</div>
|
|
<div class="modal-field">
|
|
<label>Import mode</label>
|
|
<select id="edit-sync-mode" onchange="toggleSyncDaysField()" style="padding:8px 10px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;outline:none">
|
|
<option value="days">Last N days</option>
|
|
<option value="all">Full mailbox (all email)</option>
|
|
</select>
|
|
</div>
|
|
<div class="modal-row" id="edit-sync-days-row">
|
|
<div class="modal-field"><label>Days to fetch</label><input type="number" id="edit-sync-days" value="30" min="1" max="3650"></div>
|
|
</div>
|
|
<div id="edit-conn-result" class="test-result" style="display:none"></div>
|
|
<div id="edit-last-error" style="display:none" class="alert error"></div>
|
|
<div class="modal-actions">
|
|
<button class="modal-cancel" onclick="closeModal('edit-account-modal')">Cancel</button>
|
|
<button class="btn-secondary" id="edit-test-btn" onclick="testEditConnection()">Test Connection</button>
|
|
<button class="modal-submit" onclick="saveAccountEdit()">Save</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings Modal -->
|
|
<div class="modal-overlay" id="settings-modal">
|
|
<div class="modal" style="width:520px">
|
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:22px">
|
|
<h2 style="margin-bottom:0">Settings</h2>
|
|
<button onclick="closeModal('settings-modal')" class="icon-btn"><svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg></button>
|
|
</div>
|
|
|
|
<div class="settings-group">
|
|
<div class="settings-group-title">Email Sync</div>
|
|
<div style="font-size:13px;color:var(--muted);margin-bottom:12px">How often to automatically check all your accounts for new mail.</div>
|
|
<div style="display:flex;gap:10px;align-items:center">
|
|
<select id="sync-interval-select" style="flex:1;padding:8px 10px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-family:'DM Sans',sans-serif;font-size:13px;outline:none">
|
|
<option value="0">Manual only</option>
|
|
<option value="1">Every 1 minute</option>
|
|
<option value="5">Every 5 minutes</option>
|
|
<option value="10">Every 10 minutes</option>
|
|
<option value="15">Every 15 minutes (default)</option>
|
|
<option value="30">Every 30 minutes</option>
|
|
<option value="60">Every 60 minutes</option>
|
|
</select>
|
|
<button class="btn-primary" onclick="saveSyncInterval()">Save</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-group">
|
|
<div class="settings-group-title">Compose Window</div>
|
|
<div style="font-size:13px;color:var(--muted);margin-bottom:12px">Open new message as an in-page panel (default) or a separate popup window.</div>
|
|
<label style="display:flex;align-items:center;gap:10px;font-size:13px;cursor:pointer">
|
|
<input type="checkbox" id="compose-popup-toggle" onchange="saveComposePopupPref()">
|
|
Open compose in new popup window
|
|
</label>
|
|
</div>
|
|
|
|
<div class="settings-group">
|
|
<div class="settings-group-title">Change Password</div>
|
|
<div class="modal-field"><label>Current Password</label><input type="password" id="cur-pw"></div>
|
|
<div class="modal-field"><label>New Password</label><input type="password" id="new-pw" placeholder="Min. 8 characters"></div>
|
|
<button class="btn-primary" onclick="changePassword()">Update Password</button>
|
|
</div>
|
|
|
|
<div class="settings-group">
|
|
<div class="settings-group-title" style="display:flex;align-items:center;gap:10px">
|
|
Two-Factor Authentication <span id="mfa-badge"></span>
|
|
</div>
|
|
<div id="mfa-panel">Loading...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Context menu -->
|
|
<div class="ctx-menu" id="ctx-menu"></div>
|
|
<div class="toast-container" id="toast-container"></div>
|
|
{{end}}
|
|
|
|
{{define "scripts"}}
|
|
<script src="/static/js/app.js"></script>
|
|
{{end}}
|