Merge pull request #9 from quirinecker/feature/ui-improvements

Feature/UI improvements
This commit is contained in:
2025-07-04 17:09:07 +02:00
committed by GitHub
3 changed files with 55 additions and 55 deletions

View File

@@ -8,6 +8,12 @@ const db = drizzle("file:local.db");
const app = express(); const app = express();
const userId = "Detlef"; const userId = "Detlef";
type Prettify<T> = {
[K in keyof T]: T[K];
} & {};
type TaskResponse = Prettify<Omit<typeof task.$inferSelect, 'done'> & { done: boolean }>
app.use(cors()) app.use(cors())
app.use(express.json()); app.use(express.json());
@@ -15,9 +21,11 @@ app.get('/', (req, res) => {
res.send('Hello World'); res.send('Hello World');
}); });
app.get('/tasks', async(req, res) => { app.get('/tasks', async (req, res) => {
const tasks = await db.select().from(task) const tasks: typeof task.$inferSelect[] = await db.select().from(task)
res.status(200).send(tasks); res.status(200).send(tasks.map<TaskResponse>(task => {
return { ...task, done: task.done === 1 }
}));
}); });
app.get('/events', async(req, res) => { app.get('/events', async(req, res) => {
@@ -130,4 +138,4 @@ app.delete('/event/:id', async(req, res) => {
app.listen(8080, () => { app.listen(8080, () => {
console.log('Listening on port 8080'); console.log('Listening on port 8080');
}); });

View File

@@ -4,24 +4,27 @@ import ListItem from './ListItem.vue';
import Title1 from './Title1.vue'; import Title1 from './Title1.vue';
import type { DropdownMenuItem } from '@nuxt/ui'; import type { DropdownMenuItem } from '@nuxt/ui';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import type { USeparator } from '#components';
const colorMode = useColorMode(); const colorMode = useColorMode();
const currentTheme = ref<'dark' | 'system' | 'light'>(colorMode.preference as 'dark' | 'system' | 'light'); const currentTheme = ref<'dark' | 'system' | 'light'>(colorMode.preference as 'dark' | 'system' | 'light');
const isLight = computed(() => currentTheme.value === 'light'); const date = defineModel<DateTime>('date', { required: true })
const isDark = computed(() => currentTheme.value === 'dark'); const tasks = defineModel<Task[]>('tasks', { required: true })
const isSystem = computed(() => currentTheme.value === 'system');
watch(currentTheme, () => {
console.log(currentTheme.value)
colorMode.preference = currentTheme.value;
})
const emits = defineEmits<{ const emits = defineEmits<{
(e: 'createTask', name: string): void (e: 'createTask', name: string): void
(e: 'deleteTask', id: number): void (e: 'deleteTask', id: number): void
(e: 'editTask', task: Task): void
}>() }>()
const isLight = computed(() => currentTheme.value === 'light');
const isDark = computed(() => currentTheme.value === 'dark');
const isSystem = computed(() => currentTheme.value === 'system');
const doneTasks = computed(() => tasks.value.filter(task => task.done))
const todoTasks = computed(() => tasks.value.filter(task => !task.done))
const dropDownItems = computed<DropdownMenuItem[][]>(() => [ const dropDownItems = computed<DropdownMenuItem[][]>(() => [
[ [
{ label: "Profile", icon: "i-lucide-user" }, { label: "Profile", icon: "i-lucide-user" },
@@ -60,7 +63,6 @@ const dropDownItems = computed<DropdownMenuItem[][]>(() => [
] ]
]) ])
const date = defineModel<DateTime>('date', { required: true })
const selectedDate = computed({ const selectedDate = computed({
get() { get() {
@@ -79,31 +81,26 @@ type Task = {
userid: string userid: string
title: string title: string
description: string description: string
done: number done: boolean
estimated_time: string estimated_time: string
due_date: string due_date: string
created_at: string created_at: string
updated_at: string updated_at: string
} }
defineProps<{
todos: Task[]
}>()
function addTask() {
function addTodo() {
const name = prompt("Todo name:") const name = prompt("Todo name:")
console.log(name) console.log(name)
if (name !== null) { if (name !== null) {
emits('createTask', name) emits('createTask', name)
} }
} }
function deleteTodo(todo: Task) { function deleteTask(todo: Task) {
console.log(todo.id)
emits('deleteTask', todo.id) emits('deleteTask', todo.id)
} }
function editTodo() { function editTask(task: Task) {
emits('editTask', task)
} }
</script> </script>
@@ -119,42 +116,39 @@ function editTodo() {
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<Title1>Todos</Title1> <Title1>Todos</Title1>
<div class="flex gap-2 flex-col"> <div class="flex gap-2 flex-col">
<ListItem v-for="todo in todos"> <ListItem v-for="task in todoTasks">
<div class="flex w-full gap-4 items-center"> <div class="flex w-full gap-4 items-center">
<span class="grow overflow-scroll py-3 overflow-shadow"> <span
{{ todo.title }} class="grow overflow-scroll py-3 overflow-shadow flex flex-row gap-2 items-center">
<UCheckbox v-model="task.done" @change="() => editTask(task)" />{{ task.title }}
</span> </span>
<div class="flex gap-1"> <div class="flex gap-1">
<UButton size="xs" color="neutral" class="flex justify-center" @click="editTodo"> <UButton size="xs" color="neutral" class="flex justify-center" icon="mingcute:pencil-line"
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" @click="() => editTask(task)"/>
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" <UButton size="xs" color="primary" class="flex justify-center" icon="octicon:trashcan-16"
stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pencil"> @click="() => deleteTask(task)" />
<path </div>
d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"> </div>
</path> </ListItem>
<path d="m15 5 4 4"></path> <USeparator label="Done" v-if="todoTasks.length !== 0"/>
</svg> <ListItem v-for="task in doneTasks">
</UButton> <div class="flex w-full gap-4 items-center">
<UButton size="xs" class="flex justify-center" color="primary" <span
@click="() => deleteTodo(todo)"> class="grow overflow-scroll py-3 overflow-shadow flex flex-row gap-2 items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" <UCheckbox v-model="task.done" @change="() => editTask(task)" />{{ task.title }}
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" </span>
stroke-linecap="round" stroke-linejoin="round" <div class="flex gap-1">
class="lucide lucide-trash-2"> <UButton size="xs" color="neutral" class="flex justify-center" icon="mingcute:pencil-line"
<path d="M3 6h18"></path> @click="() => editTask(task)"/>
<path d="M19 6v14c0 1-2 2-2 2H7c-1 0-2-1-2-2V6"></path> <UButton size="xs" color="primary" class="flex justify-center"
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path> @click="() => deleteTask(task)" icon="octicon:trashcan-16"/>
<line x1="10" x2="10" y1="11" y2="17"></line>
<line x1="14" x2="14" y1="11" y2="17"></line>
</svg>
</UButton>
</div> </div>
</div> </div>
</ListItem> </ListItem>
</div> </div>
</div> </div>
<div class="flex"> <div class="flex">
<UButton size="xl" class="w-full flex justify-center" @click="addTodo"> <UButton size="xl" class="w-full flex justify-center" @click="addTask">
+ +
</UButton> </UButton>
</div> </div>
@@ -174,6 +168,4 @@ function editTodo() {
</UCard> </UCard>
</template> </template>
<style scoped> <style scoped></style>
</style>

View File

@@ -23,7 +23,7 @@ type Task = {
userid: string userid: string
title: string title: string
description: string description: string
done: number done: boolean
estimated_time: string estimated_time: string
due_date: string due_date: string
created_at: string created_at: string
@@ -68,7 +68,7 @@ async function deleteTask(id: number) {
<template> <template>
<div class="h-screen w-screen p-4 flex flex-row gap-5"> <div class="h-screen w-screen p-4 flex flex-row gap-5">
<Sidebar v-if="tasks !== null" :todos="tasks" v-model:date="date" @create-task="postTask" <Sidebar v-if="tasks !== null" v-model:tasks="tasks" v-model:date="date" @create-task="postTask"
@delete-task="deleteTask" /> @delete-task="deleteTask" />
<MainContent v-if="events !== null" v-model:events="events" v-model:date="date" @create-event="postEvent" /> <MainContent v-if="events !== null" v-model:events="events" v-model:date="date" @create-event="postEvent" />
</div> </div>