diff --git a/docker-compose.yml b/docker-compose.yml index 31eab39..cd71eb6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,11 @@ services: oikos: -# image: ghcr.io/ulsklyc/oikos:latest + image: ghcr.io/ulsklyc/oikos:latest build: . # optional: use --build to build locally instead container_name: oikos restart: unless-stopped ports: - - "0.0.0.0:3100:3000" + - "0.0.0.0:3000:3000" volumes: - oikos_data:/data env_file: @@ -19,7 +19,7 @@ services: # Direct HTTP access (no reverse proxy): - SESSION_SECURE=false healthcheck: - test: ["CMD", "node", "-e", "require('http').get('http://localhost:3100/health', r => process.exit(r.statusCode === 200 ? 0 : 1))"] + test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', r => process.exit(r.statusCode === 200 ? 0 : 1))"] interval: 30s timeout: 10s retries: 3 diff --git a/public/pages/birthdays.js b/public/pages/birthdays.js index 8ec7284..7f20434 100644 --- a/public/pages/birthdays.js +++ b/public/pages/birthdays.js @@ -65,11 +65,12 @@ function renderSuggestions() { const items = suggestions(); if (!items.length) { dropdown.hidden = true; - dropdown.innerHTML = ''; + dropdown.replaceChildren(); return; } dropdown.hidden = false; - dropdown.innerHTML = items.map((birthday, idx) => ` + dropdown.replaceChildren(); + dropdown.insertAdjacentHTML('beforeend', items.map((birthday, idx) => ` - `).join(''); + `).join('')); } function renderUpcoming() { const host = _container.querySelector('#birthdays-upcoming'); if (!host) return; if (!state.upcoming.length) { - host.innerHTML = `
+ host.replaceChildren(); + host.insertAdjacentHTML('beforeend', `
${t('birthdays.emptyTitle')}
${t('birthdays.emptyDescription')}
-
`; +
`); return; } - host.innerHTML = state.upcoming.map((birthday) => ` + host.replaceChildren(); + host.insertAdjacentHTML('beforeend', state.upcoming.map((birthday) => `
${photoAvatar(birthday)}
@@ -106,7 +109,7 @@ function renderUpcoming() {
${esc(ageNote(birthday))}
- `).join(''); + `).join('')); } function renderList() { @@ -114,14 +117,16 @@ function renderList() { if (!host) return; const list = filteredBirthdays(); if (!list.length) { - host.innerHTML = `
+ host.replaceChildren(); + host.insertAdjacentHTML('beforeend', `
${t('birthdays.emptyTitle')}
${t('birthdays.emptyDescription')}
-
`; +
`); return; } - host.innerHTML = list.map((birthday) => ` + host.replaceChildren(); + host.insertAdjacentHTML('beforeend', list.map((birthday) => `
${photoAvatar(birthday)}
@@ -142,14 +147,15 @@ function renderList() {
- `).join(''); + `).join('')); if (window.lucide) window.lucide.createIcons(); stagger(host.querySelectorAll('.birthday-item')); } function renderPage() { - _container.innerHTML = ` + _container.replaceChildren(); + _container.insertAdjacentHTML('beforeend', `

${t('birthdays.title')}

@@ -194,7 +200,7 @@ function renderPage() {
- `; + `); renderUpcoming(); renderList(); @@ -304,7 +310,8 @@ function openBirthdayModal({ mode, birthday = null }) { const nameInput = panel.querySelector('#bd-name'); const preview = panel.querySelector('#birthday-preview'); const renderPreview = () => { - preview.innerHTML = birthdayPreviewHtml(nameInput.value.trim(), photoData); + preview.replaceChildren(); + preview.insertAdjacentHTML('beforeend', birthdayPreviewHtml(nameInput.value.trim(), photoData)); }; nameInput.addEventListener('input', renderPreview); panel.querySelector('#bd-photo').addEventListener('change', async (e) => { diff --git a/public/pages/dashboard.js b/public/pages/dashboard.js index 8328ddc..6f744c9 100644 --- a/public/pages/dashboard.js +++ b/public/pages/dashboard.js @@ -1061,10 +1061,11 @@ export async function render(container, { user }) { function rebuildDashboard(cfg) { const shell = container.querySelector('#dashboard-shell'); if (!shell) return; - shell.innerHTML = ` + shell.replaceChildren(); + shell.insertAdjacentHTML('beforeend', ` ${renderDashboardOverview(user, stats, weather)} ${renderDashboardLayout(cfg, data, weather, currency)} - `; + `); wireLinks(container, rerender); if (window.lucide) window.lucide.createIcons(); wireWeatherRefresh(container, (updatedWeather) => {