feat: session naming, username/persona rename, help page, contrast fixes

- Session name field: PATCH /sessions/{id} endpoint, inline rename button in UI
- Persona rename: inline ✏ toggle form in settings, POST /settings/persona/rename
- Username rename: inline form in settings, POST /settings/username (renames home dir, forces re-login)
- Help page: dedicated /help route replacing modal, collapsible sections
- Per-persona isolation: files.py and session_store.py now scope to correct user/persona
- Contrast/visibility: muted text bumped to slate-400+, session rename btn at 0.4 opacity

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-23 23:10:12 -04:00
parent 1b425a539f
commit 0cf0d65e9e
10 changed files with 351 additions and 33 deletions

View File

@@ -30,7 +30,7 @@
.back-link {
display: inline-block;
font-size: 0.8rem;
color: #64748b;
color: #94a3b8;
text-decoration: none;
margin-bottom: 1.5rem;
}
@@ -40,7 +40,7 @@
margin-bottom: 1.75rem;
}
.logo h1 { font-size: 1.4rem; font-weight: 700; color: #a78bfa; }
.logo p { font-size: 0.8rem; color: #64748b; margin-top: 0.2rem; }
.logo p { font-size: 0.8rem; color: #94a3b8; margin-top: 0.2rem; }
h2 {
font-size: 0.9rem;
@@ -73,7 +73,7 @@
transition: border-color 0.15s;
}
input:focus { border-color: #7c3aed; }
input[readonly] { color: #64748b; cursor: default; }
input[readonly] { color: #94a3b8; cursor: default; }
.field { margin-bottom: 1rem; }
@@ -109,11 +109,17 @@
.persona-list {
list-style: none;
display: flex;
flex-wrap: wrap;
flex-direction: column;
gap: 0.5rem;
margin-top: 0.5rem;
}
.persona-list li a {
.persona-list li {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.persona-link {
display: inline-block;
padding: 0.3rem 0.75rem;
background: #0f1117;
@@ -124,14 +130,55 @@
text-decoration: none;
transition: border-color 0.15s;
}
.persona-list li a:hover { border-color: #7c3aed; }
.persona-list li em { color: #475569; font-size: 0.85rem; }
.persona-link:hover { border-color: #7c3aed; }
.persona-list li em { color: #94a3b8; font-size: 0.85rem; }
.persona-rename-toggle {
background: none;
border: none;
color: #94a3b8;
font-size: 0.85rem;
cursor: pointer;
padding: 0.2rem 0.4rem;
border-radius: 4px;
opacity: 0.7;
transition: opacity 0.15s, color 0.15s;
}
.persona-rename-toggle:hover { opacity: 1; color: #a78bfa; }
.persona-rename-form { display: flex; align-items: center; gap: 0.4rem; }
.persona-rename-form input[type="text"] {
width: 12rem;
padding: 0.3rem 0.6rem;
background: #0f1117;
border: 1px solid #7c3aed;
border-radius: 6px;
color: #e2e8f0;
font-size: 0.9rem;
outline: none;
}
.persona-rename-form button[type="submit"] {
width: auto;
padding: 0.3rem 0.75rem;
font-size: 0.85rem;
margin-top: 0;
}
.persona-rename-cancel {
background: none;
border: 1px solid #2d3148;
border-radius: 6px;
color: #94a3b8;
font-size: 0.85rem;
padding: 0.3rem 0.6rem;
cursor: pointer;
}
.persona-rename-cancel:hover { border-color: #94a3b8; color: #e2e8f0; }
.add-persona {
display: inline-block;
margin-top: 0.75rem;
font-size: 0.8rem;
color: #64748b;
color: #94a3b8;
text-decoration: none;
}
.add-persona:hover { color: #a78bfa; }
@@ -156,12 +203,33 @@
<label>Username</label>
<input type="text" value="{{ username }}" readonly>
</div>
<button type="button" id="show-rename-user" class="persona-rename-toggle"
style="opacity:0.7; font-size:0.8rem; padding:0.3rem 0.6rem; border:1px solid #2d3148; border-radius:6px; margin-top:0.25rem;">
✏ Change username
</button>
<form id="rename-user-form" method="POST" action="/settings/username"
style="display:none; margin-top:0.75rem;">
<div class="field">
<label for="new_username">New username</label>
<input type="text" id="new_username" name="new_username"
value="{{ username }}"
pattern="[a-z_][a-z0-9_\-]{0,31}" required autofocus>
<p style="font-size:0.75rem; color:#94a3b8; margin-top:0.3rem;">
Lowercase letters, digits, _ or - only. You will be logged out after renaming.
</p>
</div>
<div style="display:flex; gap:0.5rem;">
<button type="submit" style="flex:1; padding:0.5rem; background:#7c3aed; border:none; border-radius:6px; color:#fff; font-size:0.9rem; font-weight:600; cursor:pointer;">Save</button>
<button type="button" id="cancel-rename-user"
style="padding:0.5rem 0.9rem; background:none; border:1px solid #2d3148; border-radius:6px; color:#94a3b8; font-size:0.9rem; cursor:pointer;">Cancel</button>
</div>
</form>
</div>
<!-- Change password -->
<div class="section">
<h2>Change Password</h2>
<form method="POST" action="/settings/password">
<form method="POST" action="/settings/password" id="password-form">
<div class="field">
<label for="current_password">Current password</label>
<input type="password" id="current_password" name="current_password"
@@ -192,7 +260,8 @@
</div>
<script>
document.querySelector('form').addEventListener('submit', e => {
// Password confirmation check
document.getElementById('password-form').addEventListener('submit', e => {
const np = document.getElementById('new_password').value;
const cfm = document.getElementById('confirm_password').value;
if (np !== cfm) {
@@ -200,6 +269,37 @@
alert('New passwords do not match.');
}
});
// Username rename toggle
document.getElementById('show-rename-user').addEventListener('click', () => {
document.getElementById('show-rename-user').style.display = 'none';
document.getElementById('rename-user-form').style.display = 'block';
document.getElementById('new_username').focus();
});
document.getElementById('cancel-rename-user').addEventListener('click', () => {
document.getElementById('rename-user-form').style.display = 'none';
document.getElementById('show-rename-user').style.display = '';
});
// Persona rename toggle
document.querySelectorAll('.persona-rename-toggle').forEach(btn => {
btn.addEventListener('click', () => {
const p = btn.dataset.persona;
const form = document.querySelector(`.persona-rename-form[data-persona="${p}"]`);
btn.style.display = 'none';
form.style.display = 'flex';
form.querySelector('input[type="text"]').focus();
});
});
document.querySelectorAll('.persona-rename-cancel').forEach(btn => {
btn.addEventListener('click', () => {
const form = btn.closest('.persona-rename-form');
const p = form.dataset.persona;
const toggle = document.querySelector(`.persona-rename-toggle[data-persona="${p}"]`);
form.style.display = 'none';
toggle.style.display = '';
});
});
</script>
</body>
</html>