feat: birthday tracking, dashboard KPIs, and app name customization (#88)

- Add Birthdays module: CRUD with calendar/reminder auto-sync, photo upload, age notes
- Add DB migration 18 (birthdays table with calendar_event_id, trigger, indexes)
- Add dashboard widgets: birthdays, family participants, budget overview
- Add Settings > General: admins can set a custom app name (reflected in title/sidebar/login)
- Improve service worker: network-first caching for mutable JS/CSS assets
- Add translations for 16 locales (birthday keys)

Fixes applied during integration:
- innerHTML replaced with insertAdjacentHTML/replaceChildren throughout birthdays.js and dashboard.js
- docker-compose.yml personal dev changes reverted

Co-authored-by: Rafael Foster <rafaelgfoster@gmail.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ulas Kalayci
2026-04-27 07:37:09 +02:00
39 changed files with 4026 additions and 156 deletions
+53
View File
@@ -38,6 +38,7 @@
"shopping": "购物",
"notes": "便签",
"contacts": "联系人",
"birthdays": "生日",
"budget": "预算",
"settings": "设置",
"main": "主导航",
@@ -82,6 +83,19 @@
"allDay": "全天",
"shoppingMore": "+{{count}} 更多",
"weather": "天气",
"familyMembers": "家庭成员",
"participantsAdded": "位参与者已添加",
"upcomingBirthdays": "即将到来的生日",
"noBirthdays": "还没有生日",
"daysLeft": "{{count}} 天",
"budgetOverview": "预算概览",
"monthlyIncome": "收入",
"monthlyExpenses": "支出",
"monthlyBalance": "余额",
"savingsRate": "储蓄率",
"topExpense": "最大支出",
"budgetEntries": "记录",
"noBudgetData": "本月没有预算数据。",
"customize": "自定义",
"customizeTitle": "自定义小组件",
"customizeReset": "重置",
@@ -537,6 +551,7 @@
"tabAccount": "账户",
"tabsAriaLabel": "设置类别",
"sectionDesign": "外观",
"sectionAppName": "应用名称",
"sectionShopping": "购物",
"shoppingCategoriesLabel": "购物分类",
"shoppingCategoriesHint": "添加、重命名、删除或排序分类。",
@@ -554,6 +569,16 @@
"sectionCalendarSync": "日历同步",
"sectionFamily": "家庭成员",
"cardAppearance": "外观",
"appNameTitle": "应用名称",
"appNameLabel": "应用名称",
"appNameHint": "此名称会显示在侧边栏、浏览器标题和登录界面中。",
"appNamePlaceholder": "Oikos",
"appNameSavedToast": "应用名称已保存。",
"sectionDate": "日期",
"dateFormatTitle": "日期格式",
"dateFormatLabel": "首选日期格式",
"dateFormatHint": "选择日期在应用中的显示方式。",
"dateFormatSavedToast": "日期格式已保存。",
"themeSystem": "跟随系统",
"themeSysLabel": "使用系统设置",
"themeLight": "浅色",
@@ -760,6 +785,34 @@
"placeholder": "搜索…",
"noResults": "未找到结果。"
},
"birthdays": {
"title": "生日",
"addButton": "添加生日",
"searchPlaceholder": "搜索生日…",
"upcomingTitle": "即将到来的生日",
"upcomingHint": "接下来的生日庆祝,已同步到日历。",
"peopleTitle": "人物",
"peopleHint": "搜索、查看并编辑所有已保存的生日。",
"emptyTitle": "还没有生日",
"emptyDescription": "添加一个生日,让它显示在日历和提醒中。",
"newTitle": "新建生日",
"editTitle": "编辑生日",
"nameLabel": "姓名",
"birthDateLabel": "出生日期",
"photoLabel": "头像",
"removePhoto": "删除照片",
"notesLabel": "备注",
"notesPlaceholder": "礼物想法、最喜欢的蛋糕、家庭备注…",
"calendarHint": "每个生日都会自动添加到日历和提醒系统中。",
"requiredFields": "姓名和出生日期为必填项。",
"createdToast": "生日已保存。",
"updatedToast": "生日已更新。",
"deletedToast": "生日已删除。",
"deleteConfirm": "删除“{{name}}”的生日?",
"ageNoteToday": "今天满 {{age}} 岁。",
"ageNoteTomorrow": "明天满 {{age}} 岁。",
"ageNoteDays": "{{days}} 天后满 {{age}} 岁。"
},
"reminders": {
"sectionTitle": "提醒",
"enableLabel": "设置提醒",