botserver/web/desktop/account.html

1074 lines
23 KiB
HTML
Raw Normal View History

<div class="account-layout" x-data="accountApp()" x-cloak>
<!-- Header -->
<div class="account-header">
<h1>Account Settings</h1>
<p class="subtitle">Manage your email accounts, preferences, and profile</h1></p>
</div>
<!-- Navigation Tabs -->
<div class="tabs">
<button
class="tab"
:class="{ active: currentTab === 'profile' }"
@click="currentTab = 'profile'">
👤 Profile
</button>
<button
class="tab"
:class="{ active: currentTab === 'email' }"
@click="currentTab = 'email'">
📧 Email Accounts
</button>
<button
class="tab"
:class="{ active: currentTab === 'drive' }"
@click="currentTab = 'drive'">
💾 Drive Settings
</button>
<button
class="tab"
:class="{ active: currentTab === 'security' }"
@click="currentTab = 'security'">
🔒 Security
</button>
</div>
<!-- Content Panels -->
<div class="tab-content">
<!-- Profile Tab -->
<template x-if="currentTab === 'profile'">
<div class="panel-content">
<h2>Profile Information</h2>
<form @submit.prevent="saveProfile" class="form">
<div class="form-group">
<label for="username">Username</label>
<input
type="text"
id="username"
x-model="profile.username"
placeholder="Enter username"
disabled>
</div>
<div class="form-group">
<label for="email">Email Address</label>
<input
type="email"
id="email"
x-model="profile.email"
placeholder="Enter email"
disabled>
</div>
<div class="form-group">
<label for="displayName">Display Name</label>
<input
type="text"
id="displayName"
x-model="profile.displayName"
placeholder="Enter display name">
</div>
<div class="form-group">
<label for="phone">Phone Number</label>
<input
type="tel"
id="phone"
x-model="profile.phone"
placeholder="Enter phone number">
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary" :disabled="saving">
<span x-show="!saving">💾 Save Changes</span>
<span x-show="saving">⏳ Saving...</span>
</button>
</div>
</form>
</div>
</template>
<!-- Email Accounts Tab -->
<template x-if="currentTab === 'email'">
<div class="panel-content">
<div class="section-header">
<h2>Email Accounts</h2>
<button class="btn btn-primary" @click="showAddAccount = true">
Add Account
</button>
</div>
<!-- Email Accounts List -->
<div class="accounts-list">
<template x-if="emailAccounts.length === 0">
<div class="empty-state">
<div class="empty-icon">📧</div>
<h3>No email accounts</h3>
<p>Add your first email account to start using the mail client</p>
<button class="btn btn-primary" @click="showAddAccount = true">
Add Email Account
</button>
</div>
</template>
<template x-for="account in emailAccounts" :key="account.id">
<div class="account-card">
<div class="account-info">
<div class="account-icon">📧</div>
<div class="account-details">
<h3 x-text="account.display_name || account.email"></h3>
<p class="account-email" x-text="account.email"></p>
<div class="account-meta">
<span x-text="`${account.imap_server}:${account.imap_port}`"></span>
<span x-show="account.is_primary" class="badge badge-primary">Primary</span>
<span x-show="account.is_active" class="badge badge-success">Active</span>
</div>
</div>
</div>
<div class="account-actions">
<button
class="btn btn-sm btn-secondary"
@click="testAccount(account)"
:disabled="testingAccount === account.id">
<span x-show="testingAccount !== account.id">🔌 Test</span>
<span x-show="testingAccount === account.id"></span>
</button>
<button
class="btn btn-sm btn-secondary"
@click="editAccount(account)">
✏️ Edit
</button>
<button
class="btn btn-sm btn-danger"
@click="deleteAccount(account.id)">
🗑️ Delete
</button>
</div>
</div>
</template>
</div>
</div>
</template>
<!-- Drive Settings Tab -->
<template x-if="currentTab === 'drive'">
<div class="panel-content">
<h2>Drive Storage Settings</h2>
<div class="storage-info">
<div class="storage-usage">
<h3>Storage Usage</h3>
<div class="progress-bar">
<div
class="progress-fill"
:style="`width: ${storageUsagePercent}%`">
</div>
</div>
<p x-text="`${storageUsed} of ${storageTotal} used`"></p>
</div>
</div>
<form @submit.prevent="saveDriveSettings" class="form">
<div class="form-group">
<label for="driveServer">Drive Server</label>
<input
type="text"
id="driveServer"
x-model="driveSettings.server"
placeholder="e.g., drive.example.com"
readonly>
</div>
<div class="form-group">
<label>
<input type="checkbox" x-model="driveSettings.autoSync">
Enable automatic file synchronization
</label>
</div>
<div class="form-group">
<label>
<input type="checkbox" x-model="driveSettings.offlineMode">
Enable offline mode
</label>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
💾 Save Settings
</button>
</div>
</form>
</div>
</template>
<!-- Security Tab -->
<template x-if="currentTab === 'security'">
<div class="panel-content">
<h2>Security Settings</h2>
<div class="security-section">
<h3>Change Password</h3>
<form @submit.prevent="changePassword" class="form">
<div class="form-group">
<label for="currentPassword">Current Password</label>
<input
type="password"
id="currentPassword"
x-model="security.currentPassword"
placeholder="Enter current password">
</div>
<div class="form-group">
<label for="newPassword">New Password</label>
<input
type="password"
id="newPassword"
x-model="security.newPassword"
placeholder="Enter new password">
</div>
<div class="form-group">
<label for="confirmPassword">Confirm New Password</label>
<input
type="password"
id="confirmPassword"
x-model="security.confirmPassword"
placeholder="Confirm new password">
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
🔒 Change Password
</button>
</div>
</form>
</div>
<div class="security-section">
<h3>Active Sessions</h3>
<div class="sessions-list">
<template x-for="session in activeSessions" :key="session.id">
<div class="session-card">
<div class="session-info">
<h4 x-text="session.device"></h4>
<p x-text="`Last active: ${session.lastActive}`"></p>
<p x-text="`IP: ${session.ip}`"></p>
</div>
<button
class="btn btn-sm btn-danger"
@click="revokeSession(session.id)">
❌ Revoke
</button>
</div>
</template>
</div>
</div>
</div>
</template>
</div>
<!-- Add Email Account Modal -->
<template x-if="showAddAccount">
<div class="modal-overlay" @click.self="showAddAccount = false">
<div class="modal">
<div class="modal-header">
<h2>Add Email Account</h2>
<button class="close-btn" @click="showAddAccount = false"></button>
</div>
<div class="modal-body">
<form @submit.prevent="addEmailAccount" class="form">
<div class="form-group">
<label for="newEmail">Email Address *</label>
<input
type="email"
id="newEmail"
x-model="newAccount.email"
placeholder="user@example.com"
required>
</div>
<div class="form-group">
<label for="newDisplayName">Display Name</label>
<input
type="text"
id="newDisplayName"
x-model="newAccount.displayName"
placeholder="Your Name">
</div>
<div class="form-row">
<div class="form-group">
<label for="newImapServer">IMAP Server *</label>
<input
type="text"
id="newImapServer"
x-model="newAccount.imapServer"
placeholder="imap.gmail.com"
required>
</div>
<div class="form-group">
<label for="newImapPort">IMAP Port *</label>
<input
type="number"
id="newImapPort"
x-model="newAccount.imapPort"
placeholder="993"
required>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="newSmtpServer">SMTP Server *</label>
<input
type="text"
id="newSmtpServer"
x-model="newAccount.smtpServer"
placeholder="smtp.gmail.com"
required>
</div>
<div class="form-group">
<label for="newSmtpPort">SMTP Port *</label>
<input
type="number"
id="newSmtpPort"
x-model="newAccount.smtpPort"
placeholder="587"
required>
</div>
</div>
<div class="form-group">
<label for="newUsername">Username *</label>
<input
type="text"
id="newUsername"
x-model="newAccount.username"
placeholder="username or email"
required>
</div>
<div class="form-group">
<label for="newPassword">Password *</label>
<input
type="password"
id="newPassword"
x-model="newAccount.password"
placeholder="Enter password"
required>
</div>
<div class="form-group">
<label>
<input type="checkbox" x-model="newAccount.isPrimary">
Set as primary email account
</label>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" @click="showAddAccount = false">
Cancel
</button>
<button type="submit" class="btn btn-primary" :disabled="addingAccount">
<span x-show="!addingAccount"> Add Account</span>
<span x-show="addingAccount">⏳ Adding...</span>
</button>
</div>
</form>
<div class="help-text">
<h4>Common IMAP/SMTP Settings:</h4>
<ul>
<li><strong>Gmail:</strong> imap.gmail.com:993, smtp.gmail.com:587</li>
<li><strong>Outlook:</strong> outlook.office365.com:993, smtp.office365.com:587</li>
<li><strong>Yahoo:</strong> imap.mail.yahoo.com:993, smtp.mail.yahoo.com:587</li>
</ul>
<p><strong>Note:</strong> You may need to enable "Less secure app access" or use app-specific passwords for some providers.</p>
</div>
</div>
</div>
</div>
</template>
</div>
<style>
.account-layout {
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.account-header {
margin-bottom: 2rem;
}
.account-header h1 {
font-size: 2rem;
font-weight: 600;
margin: 0 0 0.5rem 0;
color: #202124;
}
[data-theme="dark"] .account-header h1 {
color: #e8eaed;
}
.subtitle {
color: #5f6368;
margin: 0;
}
[data-theme="dark"] .subtitle {
color: #9aa0a6;
}
/* Tabs */
.tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 2rem;
border-bottom: 2px solid #e0e0e0;
}
[data-theme="dark"] .tabs {
border-bottom-color: #3c4043;
}
.tab {
padding: 1rem 1.5rem;
background: none;
border: none;
border-bottom: 3px solid transparent;
color: #5f6368;
font-size: 0.95rem;
cursor: pointer;
transition: all 0.2s;
margin-bottom: -2px;
}
.tab:hover {
color: #1a73e8;
background: rgba(26, 115, 232, 0.04);
}
.tab.active {
color: #1a73e8;
border-bottom-color: #1a73e8;
font-weight: 500;
}
[data-theme="dark"] .tab {
color: #9aa0a6;
}
[data-theme="dark"] .tab:hover {
color: #8ab4f8;
background: rgba(138, 180, 248, 0.08);
}
[data-theme="dark"] .tab.active {
color: #8ab4f8;
border-bottom-color: #8ab4f8;
}
/* Panel Content */
.panel-content {
background: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 12px;
padding: 2rem;
}
[data-theme="dark"] .panel-content {
background: #202124;
border-color: #3c4043;
}
.panel-content h2 {
font-size: 1.5rem;
font-weight: 500;
margin: 0 0 1.5rem 0;
color: #202124;
}
[data-theme="dark"] .panel-content h2 {
color: #e8eaed;
}
/* Forms */
.form {
max-width: 600px;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #202124;
}
[data-theme="dark"] .form-group label {
color: #e8eaed;
}
.form-group input[type="text"],
.form-group input[type="email"],
.form-group input[type="tel"],
.form-group input[type="password"],
.form-group input[type="number"] {
width: 100%;
padding: 0.75rem;
border: 1px solid #dadce0;
border-radius: 8px;
font-size: 0.95rem;
background: #ffffff;
color: #202124;
transition: all 0.2s;
}
[data-theme="dark"] .form-group input[type="text"],
[data-theme="dark"] .form-group input[type="email"],
[data-theme="dark"] .form-group input[type="tel"],
[data-theme="dark"] .form-group input[type="password"],
[data-theme="dark"] .form-group input[type="number"] {
background: #292a2d;
border-color: #5f6368;
color: #e8eaed;
}
.form-group input:focus {
outline: none;
border-color: #1a73e8;
box-shadow: 0 0 0 3px rgba(26, 115, 232, 0.1);
}
[data-theme="dark"] .form-group input:focus {
border-color: #8ab4f8;
box-shadow: 0 0 0 3px rgba(138, 180, 248, 0.1);
}
.form-group input:disabled,
.form-group input[readonly] {
background: #f8f9fa;
color: #5f6368;
cursor: not-allowed;
}
[data-theme="dark"] .form-group input:disabled,
[data-theme="dark"] .form-group input[readonly] {
background: #1a1a1a;
color: #9aa0a6;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.form-actions {
margin-top: 2rem;
display: flex;
gap: 1rem;
}
/* Buttons */
.btn {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 8px;
font-size: 0.95rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.btn-primary {
background: #1a73e8;
color: white;
}
.btn-primary:hover:not(:disabled) {
background: #1557b0;
}
.btn-secondary {
background: #f1f3f4;
color: #202124;
}
[data-theme="dark"] .btn-secondary {
background: #3c4043;
color: #e8eaed;
}
.btn-secondary:hover:not(:disabled) {
background: #e8eaed;
}
[data-theme="dark"] .btn-secondary:hover:not(:disabled) {
background: #5f6368;
}
.btn-danger {
background: #d93025;
color: white;
}
.btn-danger:hover:not(:disabled) {
background: #b31412;
}
.btn-sm {
padding: 0.5rem 1rem;
font-size: 0.875rem;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Section Header */
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.section-header h2 {
margin: 0;
}
/* Accounts List */
.accounts-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.account-card {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem;
background: #f8f9fa;
border: 1px solid #e0e0e0;
border-radius: 12px;
transition: all 0.2s;
}
[data-theme="dark"] .account-card {
background: #292a2d;
border-color: #3c4043;
}
.account-card:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.account-info {
display: flex;
gap: 1rem;
flex: 1;
}
.account-icon {
font-size: 2rem;
width: 3rem;
height: 3rem;
display: flex;
align-items: center;
justify-content: center;
background: #e8f0fe;
border-radius: 50%;
}
[data-theme="dark"] .account-icon {
background: #1e3a5f;
}
.account-details h3 {
margin: 0 0 0.25rem 0;
font-size: 1.1rem;
font-weight: 500;
color: #202124;
}
[data-theme="dark"] .account-details h3 {
color: #e8eaed;
}
.account-email {
margin: 0 0 0.5rem 0;
color: #5f6368;
font-size: 0.9rem;
}
[data-theme="dark"] .account-email {
color: #9aa0a6;
}
.account-meta {
display: flex;
gap: 0.5rem;
font-size: 0.85rem;
color: #5f6368;
}
[data-theme="dark"] .account-meta {
color: #9aa0a6;
}
.account-actions {
display: flex;
gap: 0.5rem;
}
/* Badges */
.badge {
padding: 0.25rem 0.75rem;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 500;
}
.badge-primary {
background: #e8f0fe;
color: #1a73e8;
}
[data-theme="dark"] .badge-primary {
background: #1e3a5f;
color: #8ab4f8;
}
.badge-success {
background: #e6f4ea;
color: #1e8e3e;
}
[data-theme="dark"] .badge-success {
background: #1e3a2e;
color: #81c995;
}
/* Empty State */
.empty-state {
text-align: center;
padding: 3rem;
color: #5f6368;
}
[data-theme="dark"] .empty-state {
color: #9aa0a6;
}
.empty-icon {
font-size: 4rem;
margin-bottom: 1rem;
}
.empty-state h3 {
font-size: 1.25rem;
margin: 0 0 0.5rem 0;
color: #202124;
}
[data-theme="dark"] .empty-state h3 {
color: #e8eaed;
}
.empty-state p {
margin: 0 0 1.5rem 0;
}
/* Modal */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 2rem;
}
.modal {
background: #ffffff;
border-radius: 12px;
max-width: 600px;
width: 100%;
max-height: 90vh;
overflow-y: auto;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
[data-theme="dark"] .modal {
background: #202124;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem;
border-bottom: 1px solid #e0e0e0;
}
[data-theme="dark"] .modal-header {
border-bottom-color: #3c4043;
}
.modal-header h2 {
margin: 0;
font-size: 1.5rem;
color: #202124;
}
[data-theme="dark"] .modal-header h2 {
color: #e8eaed;
}
.close-btn {
background: none;
border: none;
font-size: 1.5rem;
color: #5f6368;
cursor: pointer;
padding: 0.5rem;
line-height: 1;
transition: color 0.2s;
}
.close-btn:hover {
color: #202124;
}
[data-theme="dark"] .close-btn {
color: #9aa0a6;
}
[data-theme="dark"] .close-btn:hover {
color: #e8eaed;
}
.modal-body {
padding: 1.5rem;
}
.help-text {
margin-top: 2rem;
padding: 1rem;
background: #f8f9fa;
border-radius: 8px;
font-size: 0.875rem;
}
[data-theme="dark"] .help-text {
background: #292a2d;
}
.help-text h4 {
margin: 0 0 0.5rem 0;
font-size: 0.95rem;
color: #202124;
}
[data-theme="dark"] .help-text h4 {
color: #e8eaed;
}
.help-text ul {
margin: 0.5rem 0;
padding-left: 1.5rem;
color: #5f6368;
}
[data-theme="dark"] .help-text ul {
color: #9aa0a6;
}
.help-text p {
margin: 0.5rem 0 0 0;
color: #5f6368;
}
[data-theme="dark"] .help-text p {
color: #9aa0a6;
}
/* Storage Info */
.storage-info {
margin-bottom: 2rem;
}
.storage-usage {
padding: 1.5rem;
background: #f8f9fa;
border-radius: 12px;
}
[data-theme="dark"] .storage-usage {
background: #292a2d;
}
.storage-usage h3 {
margin: 0 0 1rem 0;
font-size: 1.1rem;
color: #202124;
}
[data-theme="dark"] .storage-usage h3 {
color: #e8eaed;
}
.progress-bar {
height: 12px;
background: #e0e0e0;
border-radius: 6px;
overflow: hidden;
margin-bottom: 0.5rem;
}
[data-theme="dark"] .progress-bar {
background: #3c4043;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #1a73e8, #34a853);
transition: width 0.3s;
}
.storage-usage p {
margin: 0;
color: #5f6368;
font-size: 0.9rem;
}
[data-theme="dark"] .storage-usage p {
color: #9aa0a6;
}
/* Security Section */
.security-section {
margin-bottom: 3rem;
}
.security-section h3 {
font-size: 1.25rem;
margin: 0 0 1.5rem 0;
color: #202124;
}
[data-theme="dark"] .security-section h3 {
color: #e8eaed;
}
.sessions-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.session-card {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background: #f8f9fa;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
[data-theme="dark"] .session-card {
background: #292a2d;
border-color: #3c4043;
}
.session-info h4 {
margin: 0 0 0.25rem 0;
font-size: 1rem;
color: #202124;
}
[data-theme="dark"] .session-info h4 {
color: #e8eaed;
}
.session-info p {
margin: 0;
font-size: 0.875rem;
color: #5f6368;
}
[data-theme="dark"] .session-info p {
color: #9aa0a6;
}
/* Alpine cloak */
[x-cloak] {
display: none !important;
}
/* Responsive */
@media (max-width: 768px) {
.account-layout {
padding: 1rem;
}
.tabs {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.tab {
padding: 0.75rem 1rem;
white-space: nowrap;
}
.panel-content {
padding: 1.5rem;
}
.form-row {
grid-template-columns: 1fr;
}
.account-card {
flex-direction: column;
gap: 1rem;
}
.account-actions {
width: 100%;
justify-content: flex-end;
}
.section-header {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
.modal-overlay {
padding: 1rem;
}
}
</style>