Add chat rooms, channels, sidebar nav, themes, and UI polish
Backend (profiles.py / main.py): - Fix bot startup crash: create active user before start_chat - Fix address-clobbering bug on restart (UserContactLink vs CreatedConnLink) - Add user profile type alongside bots - Channels: create groups with observer links, classify via acceptMemberRole - Chat rooms: get_chat_history + send_to_chat, history/messages/send routes UI: - Chat room view with message bubbles and live polling - Convert top nav to collapsible left sidebar (mobile-friendly off-canvas) - Three-way Users/Bots split; clickable cards; copy-address buttons + links - Add Matrix theme alongside Original Light/Dark - File upload sidebar link; site footer on all pages incl. login - Bot-type descriptions on the Bots page; QR caption on profiles Remove orphaned index.html (superseded by list.html). Ignore downloaded libs/, exploration DBs, and local ai.sh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
153
manager/templates/settings.html
Normal file
153
manager/templates/settings.html
Normal file
@@ -0,0 +1,153 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Settings — SimpleX Manager{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<style>
|
||||
.settings-section { margin-bottom: 32px; }
|
||||
.settings-section h2 { margin-bottom: 16px; }
|
||||
|
||||
.theme-grid { display: flex; gap: 16px; flex-wrap: wrap; }
|
||||
|
||||
.theme-card {
|
||||
flex: 0 0 180px;
|
||||
border: 2px solid var(--border);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
background: var(--card);
|
||||
}
|
||||
.theme-card:hover { border-color: var(--accent); }
|
||||
.theme-card.selected {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 3px rgba(0,83,208,0.18);
|
||||
}
|
||||
[data-theme="original-dark"] .theme-card.selected {
|
||||
box-shadow: 0 0 0 3px rgba(112,240,249,0.2);
|
||||
}
|
||||
[data-theme="matrix"] .theme-card.selected {
|
||||
box-shadow: 0 0 0 3px rgba(0,255,65,0.25);
|
||||
}
|
||||
|
||||
.theme-preview {
|
||||
height: 96px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.preview-bar { border-radius: 4px; height: 14px; }
|
||||
.preview-bar-sm { border-radius: 4px; height: 9px; width: 60%; }
|
||||
.preview-dot { width: 20px; height: 20px; border-radius: 50%; margin-top: auto; }
|
||||
|
||||
.theme-label {
|
||||
padding: 10px 14px;
|
||||
border-top: 1px solid;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.checkmark {
|
||||
width: 18px; height: 18px; border-radius: 50%;
|
||||
background: var(--accent);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 11px;
|
||||
color: var(--btn-light-text);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
.theme-card.selected .checkmark { opacity: 1; }
|
||||
|
||||
/* Original Light preview colors (hardcoded so visible regardless of current theme) */
|
||||
.preview-light { background: #f5f5f7; }
|
||||
.preview-light .preview-bar { background: #ffffff; }
|
||||
.preview-light .preview-bar-sm { background: #e0e0e5; }
|
||||
.preview-light .preview-dot { background: #0053D0; }
|
||||
.preview-light + .theme-label { border-color: #e0e0e5; color: #1d1d1f; background: #fff; }
|
||||
|
||||
/* Original Dark preview colors */
|
||||
.preview-dark { background: #111827; }
|
||||
.preview-dark .preview-bar { background: #0B2A59; }
|
||||
.preview-dark .preview-bar-sm { background: #1e3a5f; }
|
||||
.preview-dark .preview-dot { background: #70F0F9; }
|
||||
.preview-dark + .theme-label { border-color: #1e3a5f; color: #f5f5f7; background: #0B2A59; }
|
||||
|
||||
/* Matrix preview colors */
|
||||
.preview-matrix { background: #000000; }
|
||||
.preview-matrix .preview-bar { background: #062006; }
|
||||
.preview-matrix .preview-bar-sm { background: #0f3d0f; }
|
||||
.preview-matrix .preview-dot { background: #00ff41; box-shadow: 0 0 8px #00ff41; }
|
||||
.preview-matrix + .theme-label { border-color: #0f3d0f; color: #00ff41; background: #050d05;
|
||||
font-family: 'Consolas', monospace; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Settings</h1>
|
||||
|
||||
<div class="card settings-section">
|
||||
<h2>Theme</h2>
|
||||
<div class="theme-grid">
|
||||
|
||||
<div class="theme-card" id="card-original-light" onclick="setTheme('original-light')">
|
||||
<div class="theme-preview preview-light">
|
||||
<div class="preview-bar"></div>
|
||||
<div class="preview-bar-sm"></div>
|
||||
<div class="preview-bar-sm"></div>
|
||||
<div class="preview-dot"></div>
|
||||
</div>
|
||||
<div class="theme-label">
|
||||
<span>Original Light</span>
|
||||
<span class="checkmark">✓</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card" id="card-original-dark" onclick="setTheme('original-dark')">
|
||||
<div class="theme-preview preview-dark">
|
||||
<div class="preview-bar"></div>
|
||||
<div class="preview-bar-sm"></div>
|
||||
<div class="preview-bar-sm"></div>
|
||||
<div class="preview-dot"></div>
|
||||
</div>
|
||||
<div class="theme-label">
|
||||
<span>Original Dark</span>
|
||||
<span class="checkmark">✓</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card" id="card-matrix" onclick="setTheme('matrix')">
|
||||
<div class="theme-preview preview-matrix">
|
||||
<div class="preview-bar"></div>
|
||||
<div class="preview-bar-sm"></div>
|
||||
<div class="preview-bar-sm"></div>
|
||||
<div class="preview-dot"></div>
|
||||
</div>
|
||||
<div class="theme-label">
|
||||
<span>Matrix</span>
|
||||
<span class="checkmark">✓</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function currentTheme() {
|
||||
return localStorage.getItem('theme') ||
|
||||
(window.matchMedia('(prefers-color-scheme:dark)').matches ? 'original-dark' : 'original-light');
|
||||
}
|
||||
|
||||
function setTheme(t) {
|
||||
localStorage.setItem('theme', t);
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
document.querySelectorAll('.theme-card').forEach(c => c.classList.remove('selected'));
|
||||
const card = document.getElementById('card-' + t);
|
||||
if (card) card.classList.add('selected');
|
||||
}
|
||||
|
||||
// Mark current selection on load
|
||||
document.getElementById('card-' + currentTheme())?.classList.add('selected');
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user