112 lines
2.7 KiB
Vue
112 lines
2.7 KiB
Vue
<script setup lang="ts">
|
|
import { reactive, watch } from 'vue'
|
|
import type { Task } from '../types'
|
|
import { t } from '../i18n'
|
|
|
|
const props = defineProps<{
|
|
modelValue: boolean
|
|
editingTask?: Task | null
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
'update:modelValue': [boolean]
|
|
submit: [payload: Partial<Task>]
|
|
}>()
|
|
|
|
const form = reactive({
|
|
title: '',
|
|
description: '',
|
|
due_at: '',
|
|
priority: 2,
|
|
tags: '',
|
|
})
|
|
|
|
watch(
|
|
() => props.editingTask,
|
|
(task) => {
|
|
form.title = task?.title ?? ''
|
|
form.description = task?.description ?? ''
|
|
form.due_at = toLocal(task?.due_at ?? '')
|
|
form.priority = task?.priority ?? 2
|
|
form.tags = task?.tags?.join(', ') ?? ''
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
|
|
watch(
|
|
() => props.modelValue,
|
|
(open) => {
|
|
if (!open && !props.editingTask) {
|
|
form.title = ''
|
|
form.description = ''
|
|
form.due_at = ''
|
|
form.priority = 2
|
|
form.tags = ''
|
|
}
|
|
},
|
|
)
|
|
|
|
function close() {
|
|
emit('update:modelValue', false)
|
|
}
|
|
|
|
function save() {
|
|
emit('submit', {
|
|
title: form.title,
|
|
description: form.description,
|
|
due_at: form.due_at ? new Date(form.due_at).toISOString() : '',
|
|
priority: Number(form.priority),
|
|
tags: form.tags
|
|
.split(',')
|
|
.map((v) => v.trim())
|
|
.filter(Boolean),
|
|
})
|
|
}
|
|
|
|
function toLocal(v: string) {
|
|
if (!v) return ''
|
|
const d = new Date(v)
|
|
if (Number.isNaN(d.getTime())) return ''
|
|
const offset = d.getTimezoneOffset() * 60000
|
|
return new Date(d.getTime() - offset).toISOString().slice(0, 16)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="modelValue" class="modal-mask" @click.self="close">
|
|
<section class="modal">
|
|
<header>
|
|
<h3>{{ editingTask ? t('edit_todo') : t('create_todo') }}</h3>
|
|
</header>
|
|
<label>
|
|
{{ t('title') }}
|
|
<input v-model="form.title" type="text" required />
|
|
</label>
|
|
<label>
|
|
{{ t('due_at') }}
|
|
<input v-model="form.due_at" type="datetime-local" />
|
|
</label>
|
|
<label>
|
|
{{ t('priority') }}
|
|
<select v-model="form.priority">
|
|
<option :value="1">{{ t('high') }}</option>
|
|
<option :value="2">{{ t('medium') }}</option>
|
|
<option :value="3">{{ t('low') }}</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
{{ t('tags') }}
|
|
<input v-model="form.tags" type="text" :placeholder="t('tags_placeholder')" />
|
|
</label>
|
|
<label>
|
|
{{ t('description') }}
|
|
<textarea v-model="form.description" rows="4"></textarea>
|
|
</label>
|
|
<div class="modal-actions">
|
|
<button class="btn" @click="close">{{ t('cancel') }}</button>
|
|
<button class="btn primary" @click="save">{{ t('save') }}</button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</template>
|