feat: entry template management in settings

This commit is contained in:
Your Name
2026-02-20 15:10:48 +02:00
parent 1e324ef0ca
commit f504241fc9

View File

@@ -799,6 +799,35 @@
</button>
</div>
</div>
<!-- Divider -->
<div class="border-t border-border-subtle" />
<!-- Entry Templates -->
<h3 class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] font-medium">Entry Templates</h3>
<div v-if="entryTemplatesStore.templates.length > 0" class="space-y-2">
<div
v-for="tpl in entryTemplatesStore.templates"
:key="tpl.id"
class="flex items-center justify-between py-2 px-3 bg-bg-inset rounded-lg"
>
<div class="flex-1 min-w-0">
<p class="text-[0.8125rem] text-text-primary truncate">{{ tpl.name }}</p>
<p class="text-[0.6875rem] text-text-tertiary">
{{ getTemplateProjectName(tpl.project_id) }}
<span v-if="tpl.duration"> - {{ formatTemplateDuration(tpl.duration) }}</span>
</p>
</div>
<button
@click="deleteEntryTemplate(tpl.id!)"
class="text-text-tertiary hover:text-status-error transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
:aria-label="'Delete template ' + tpl.name"
>
<Trash2 class="w-3.5 h-3.5" aria-hidden="true" />
</button>
</div>
</div>
<p v-else class="text-[0.75rem] text-text-tertiary">No saved templates. Use "Save as Template" in the Entries view.</p>
</div>
</div>
@@ -1279,6 +1308,7 @@ import { useToastStore } from '../stores/toast'
import { useOnboardingStore } from '../stores/onboarding'
import { useRecurringStore } from '../stores/recurring'
import type { RecurringEntry } from '../stores/recurring'
import { useEntryTemplatesStore } from '../stores/entryTemplates'
import AppNumberInput from '../components/AppNumberInput.vue'
import AppSelect from '../components/AppSelect.vue'
import AppShortcutRecorder from '../components/AppShortcutRecorder.vue'
@@ -1293,6 +1323,7 @@ import type { SoundEvent } from '../utils/audio'
const settingsStore = useSettingsStore()
const toastStore = useToastStore()
const recurringStore = useRecurringStore()
const entryTemplatesStore = useEntryTemplatesStore()
const onboardingStore = useOnboardingStore()
const recurringEntries = computed(() => recurringStore.entries)
@@ -1835,6 +1866,24 @@ function formatDuration(seconds: number): string {
return `${m}m`
}
// Entry template helpers
function getTemplateProjectName(projectId: number): string {
return recProjects.value.find(p => p.id === projectId)?.name || 'Unknown'
}
function formatTemplateDuration(seconds: number): string {
const h = Math.floor(seconds / 3600)
const m = Math.floor((seconds % 3600) / 60)
if (h > 0 && m > 0) return `${h}h ${m}m`
if (h > 0) return `${h}h`
if (m > 0) return `${m}m`
return '0m'
}
async function deleteEntryTemplate(id: number) {
await entryTemplatesStore.deleteTemplate(id)
}
function buildRecurrenceRule(): string {
if (recPattern.value === 'weekly') {
return 'weekly:' + recWeeklyDays.value.join(',')
@@ -2113,6 +2162,9 @@ onMounted(async () => {
await recurringStore.fetchEntries()
recProjects.value = await invoke<Array<{ id: number; name: string; color: string }>>('get_projects')
// Load entry templates
await entryTemplatesStore.fetchTemplates()
// Load calendar sources
await fetchCalendarSources()