Add school name and logo to home screen and admin header

- School name now appears on the student home screen and updates the page title
- Logo can be uploaded in Settings (PNG/JPG/GIF/WebP/SVG, max 2 MB); stored in the data volume so it persists across container restarts
- When a logo is uploaded the text school name is hidden in favour of the logo
- Admin header shows the school name instead of hardcoded "Homeschool", updates live when saved
- New server endpoints: GET /api/logo, POST /api/admin/upload-logo, DELETE /api/admin/logo
- /api/public-settings now includes school_name and has_logo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-08-10 16:46:00 -04:00
1 parent 1eedfc7715
commit 6b7baf7297
6 files changed
+135 -5

No files matched your search

+47
View File
@@ -58,12 +58,17 @@ $('#pin-form').addEventListener('submit', async (e) => {
unlock();
});
function updateAdminHeader() {
$('#admin-school-name').textContent = `🎓 ${appSettings.schoolName || 'Homeschool'}`;
}
async function loadAppSettings() {
try {
const s = await api('/api/admin/app-settings');
appSettings.schoolName = s.school_name || '';
appSettings.passingPct = Number(s.passing_pct) || 80;
appSettings.weekStartDay = s.week_start_day || 'monday';
updateAdminHeader();
} catch {}
}
@@ -2551,8 +2556,49 @@ async function loadSettings() {
const radio = document.querySelector(`input[name="week_start_day"][value="${appSettings.weekStartDay}"]`);
if (radio) radio.checked = true;
$('#setting-show-emoji').checked = s.show_home_emoji !== false;
const pub = await fetch('/api/public-settings').then((r) => r.json()).catch(() => ({}));
setLogoPreview(pub.has_logo);
}
function setLogoPreview(hasLogo) {
const preview = $('#logo-preview');
const noneMsg = $('#logo-none-msg');
const removeBtn = $('#logo-remove-btn');
if (hasLogo) {
preview.src = `/api/logo?v=${Date.now()}`;
preview.hidden = false;
noneMsg.hidden = true;
removeBtn.hidden = false;
} else {
preview.hidden = true;
noneMsg.hidden = false;
removeBtn.hidden = true;
}
}
$('#logo-file-input').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
if (file.size > 2 * 1024 * 1024) { msg('Logo must be under 2 MB.'); e.target.value = ''; return; }
const b64 = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = reject;
reader.readAsDataURL(file);
});
await api('/api/admin/upload-logo', { method: 'POST', body: { base64: b64, mime: file.type } });
e.target.value = '';
setLogoPreview(true);
msg('Logo saved.');
});
$('#logo-remove-btn').addEventListener('click', async () => {
await api('/api/admin/logo', { method: 'DELETE' });
setLogoPreview(false);
msg('Logo removed.');
});
$('#app-settings-form').addEventListener('submit', async (e) => {
e.preventDefault();
const school_name = $('#setting-school-name').value.trim();
@@ -2561,6 +2607,7 @@ $('#app-settings-form').addEventListener('submit', async (e) => {
const show_home_emoji = $('#setting-show-emoji').checked;
await api('/api/admin/app-settings', { method: 'POST', body: { school_name, passing_pct, week_start_day, show_home_emoji } });
appSettings.schoolName = school_name;
updateAdminHeader();
appSettings.passingPct = passing_pct;
if (appSettings.weekStartDay !== week_start_day) {
appSettings.weekStartDay = week_start_day;