Initial commit

This commit is contained in:
2024-06-15 12:55:41 +07:00
commit 9939364128
35 changed files with 7941 additions and 0 deletions
+195
View File
@@ -0,0 +1,195 @@
<script setup>
import {onBeforeMount, ref} from "vue";
import {invoke} from "@tauri-apps/api";
import {Icon} from "@iconify/vue";
import EditModal from "./components/modals/EditModal.vue";
import CreateModal from "./components/modals/CreateModal.vue";
import { appWindow } from '@tauri-apps/api/window';
import {useDark, useToggle} from "@vueuse/core";
const isDark = useDark();
const toggleDark = useToggle(isDark);
let tasks = ref({});
let pending = ref(true);
let create_modal = ref(false);
let edit_modal = ref(false);
let search_text = ref("");
let to_edit_id = ref("");
let to_edit_name = ref("");
let to_edit_description = ref("");
onBeforeMount(async () => {
await invoke('check_or_create_tasks_file');
await get_tasks();
pending.value = false;
document
.getElementById('titlebar-minimize')
.addEventListener('click', () => appWindow.minimize())
document
.getElementById('titlebar-maximize')
.addEventListener('click', () => appWindow.toggleMaximize())
document
.getElementById('titlebar-close')
.addEventListener('click', () => appWindow.close())
});
async function get_tasks(){
await invoke('get_tasks').then((res) => {
tasks.value = res;
});
}
async function search_tasks(event){
if (event.target.value) {
await invoke('search_tasks', {
value: event.target.value
}).then((res) => {
tasks.value = res;
});
} else{
await get_tasks();
}
}
async function set_task_field(id_task, completed){
let field = "completed"
id_task = id_task.toString();
completed = completed.toString()
if (completed === "false"){
completed = "true"
} else{
completed = "false"
}
await invoke('set_task_field', {
idTask: id_task,
field: field,
value: completed
}).then(async () => {
tasks.value[id_task][field] = completed;
});
}
async function delete_task(id_task){
id_task = id_task.toString();
await invoke('delete_task', {
idTask: id_task
}).then(async () => {
await get_tasks();
});
}
async function edit_task(id_task, name, description){
to_edit_id = id_task;
to_edit_name.value = name;
to_edit_description.value = description;
edit_modal.value = true
}
</script>
<template>
<div data-tauri-drag-region class="titlebar h-[30px] select-none fixed flex justify-end top-0 right-0 left-0 bg-gray-100 dark:bg-zinc-800">
<div class="titlebar-button hover:bg-gray-200 dark:hover:bg-gray-700 justify-center inline-flex w-[30px] h-[30px] items-center dark:text-white" id="titlebar-minimize">
<Icon class="" icon="mdi:window-minimize" width="20" height="20"/>
</div>
<div class="titlebar-button hover:bg-gray-200 dark:hover:bg-gray-700 justify-center inline-flex w-[30px] h-[30px] items-center dark:text-white" id="titlebar-maximize">
<Icon class="" icon="mdi:window-maximize" width="20" height="20"/>
</div>
<div class="titlebar-button hover:bg-gray-200 dark:hover:bg-gray-700 justify-center inline-flex w-[30px] h-[30px] items-center dark:text-white" id="titlebar-close">
<Icon class="" icon="mdi:close" width="26" height="26"/>
</div>
</div>
<div v-if="pending"></div>
<div v-else>
<button class="absolute top-10 right-2" @click="toggleDark()">
<Icon v-if="!isDark" class="group-hover:invert text-yellow-400" icon="flowbite:sun-solid" width="38" height="38"/>
<Icon v-else class="group-hover:invert text-blue-400" icon="ri:moon-fill" width="38" height="38"/>
</button>
<div id="search" class="relative flex h-10 mx-[15vw] lg:mx-[25vw] mt-12">
<div class="!absolute right-1 top-1 z-10">
<button
v-if="search_text !== ''"
@click="search_text = ''; get_tasks()"
class="p-[1px] pt-[1px] pb-[2px] mr-0.5 rounded-lg group text-gray-400 hover:text-gray-500 transition-colors"
type="button"
data-ripple-light="true"
>
<Icon icon="ic:baseline-close" width="26" height="26"/>
</button>
<button
@click="create_modal = !create_modal"
class="p-[1px] pt-[1px] pb-[2px] border-green-400 border-2 rounded-lg group hover:bg-green-400 transition-colors"
type="button"
data-ripple-light="true"
>
<Icon class="group-hover:invert dark:invert" icon="ic:baseline-plus" width="26" height="26"/>
</button>
</div>
<input
v-model="search_text"
type="text"
class="peer h-full w-full rounded-lg border border-blue-gray-200 bg-transparent px-3 py-2.5 pr-20 font-sans text-sm font-normal text-blue-gray-700 dark:text-white dark:border-white outline outline-0 transition-all placeholder-shown:border placeholder-shown:border-blue-gray-200 placeholder-shown:border-t-blue-gray-200 focus:border-2 focus:border-green-400 focus:border-t-transparent focus:outline-0 disabled:border-0 disabled:bg-blue-gray-50"
:class="{'dark:border-t-[rgb(30,30,30)]': search_text.length}"
placeholder=" "
@input="search_tasks"
/>
<label class="text-gray-400 dark:text-gray-300 focus:text-black before:content[' '] after:content[' '] pointer-events-none absolute left-0 -top-1.5 flex h-full w-full select-none text-[11px] font-normal leading-tight text-blue-gray-400 transition-all before:pointer-events-none before:mt-[6.5px] before:mr-1 before:box-border before:block before:h-1.5 before:w-2.5 before:rounded-tl-md before:border-t before:border-l before:border-blue-gray-200 before:transition-all after:pointer-events-none after:mt-[6.5px] after:ml-1 after:box-border after:block after:h-1.5 after:w-2.5 after:flex-grow after:rounded-tr-lg after:border-t after:border-r after:border-blue-gray-200 after:transition-all peer-placeholder-shown:text-sm peer-placeholder-shown:leading-[3.75] peer-placeholder-shown:text-blue-gray-500 peer-placeholder-shown:before:border-transparent peer-placeholder-shown:after:border-transparent peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-green-400 peer-focus:before:border-t-2 peer-focus:before:border-l-2 peer-focus:before:!border-green-400 peer-focus:after:border-t-2 peer-focus:after:border-r-2 peer-focus:after:!border-green-400 peer-disabled:text-transparent peer-disabled:before:border-transparent peer-disabled:after:border-transparent peer-disabled:peer-placeholder-shown:text-blue-gray-500">
Поиск...
</label>
</div>
<div id="list" class="relative mx-[14vw] lg:mx-[22vw] mt-5">
<ul role="list" class="divide-y divide-gray-200 dark:divide-gray-500">
<li v-for="task in tasks" :id="task.id" class="flex justify-between gap-x-6 py-5 group/task">
<div @click="set_task_field(task.id, task.completed)" class="inline-flex items-center space-x-2 min-w-0 gap-x-2 group-hover/task:cursor-pointer">
<p class="text-sm flex-none border rounded-full" :class="[ task.completed === 'true' ? 'border-green-500 group-hover:border-green-400' : 'border-gray-300 group-hover:border-gray-500' ]"><Icon class="m-0.5" :class="[ task.completed === 'true' ? 'text-green-500 group-hover:text-green-400' : 'text-gray-50 group-hover:text-gray-500 dark:text-[rgb(30,30,30)]' ]" icon="material-symbols:check" width="20" height="20"/></p>
<div class="min-w-0 flex-auto">
<p class="truncate sm:text-[2vw] lg:text-[1.5vw] xl:text-[1vw] font-semibold leading-6 decoration-2" :class="[ task.completed === 'true' ? 'line-through text-gray-400' : 'text-gray-900 dark:text-gray-300' ]" >{{task.name}}</p>
<p class="truncate text-xs leading-5 text-gray-500 dark:text-gray-400">{{task.description}}</p>
</div>
</div>
<div class="opacity-0 shrink-0 group-hover/task:opacity-100 transition-all">
<div class="inline-flex items-center gap-x-1">
<p class="mt-0.5 text-xs text-gray-400 mr-2 text-center">{{task.date}}<br>{{task.time}}</p>
<button @click="edit_task(task.id, task.name, task.description)" class="group/button border-2 rounded-lg p-1.5 border-green-400/70 hover:bg-green-400 hover:border-green-400 transition-colors"><Icon class="group-hover/button:invert dark:invert" icon="mdi:pencil" width="24" height="24" style="color: black"/></button>
<button @click="delete_task(task.id)" class="group/button border-2 rounded-lg p-1.5 border-red-400/70 hover:bg-red-500 hover:border-red-500 transition-colors"><Icon class="group-hover/button:invert dark:invert" icon="ic:baseline-delete" width="24" height="24" style="color: black"/></button>
</div>
</div>
</li>
</ul>
</div>
<CreateModal v-if="create_modal" @close="create_modal = !create_modal"/>
<EditModal v-if="edit_modal" :task_id="to_edit_id" :task_name="to_edit_name" :task_description="to_edit_description" @close="edit_modal = !edit_modal"/>
</div>
</template>
<style>
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
background-color: rgb(249 250 251);
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
:root.dark {
background-color: rgb(30, 30, 30);
}
</style>
+89
View File
@@ -0,0 +1,89 @@
<script setup>
import {invoke} from "@tauri-apps/api";
import {ref} from "vue";
let name = "";
let description = "";
let priority = "0";
let error = ref(" ");
async function create_task(){
if (name.replace(/ /g,'') === ""){
error.value = "Название задачи не может быть пустым!";
} else{
let nowDateTime = new Date();
let date = nowDateTime.getFullYear() + "." + ('0' + (nowDateTime.getMonth()+1)).slice(-2) + '.'
+ ('0' + nowDateTime.getDate()).slice(-2);
let time = ('0' + nowDateTime.getHours()).slice(-2) + ":" + ('0' + nowDateTime.getMinutes()).slice(-2);
await invoke('add_task', {
date: date,
time: time,
name: name,
description: description,
priority: priority
});
location.reload();
}
}
</script>
<template>
<div id="create-task-modal" tabindex="-1" aria-hidden="true" class="px-[5vw] md:px-[10vw] lg:px-[15vw] absolute overflow-y-auto overflow-x-hidden w-full top-20 lg:top-24 z-50">
<div class="relative p-4 max-h-full">
<!-- Modal content -->
<form class="relative bg-white rounded-lg shadow dark:bg-[rgb(50,50,50)]" @submit.prevent="create_task">
<!-- Modal header -->
<div class="flex items-center justify-between px-5 py-2 md:py-3 border-b rounded-t">
<h3 class="text-xl font-semibold text-gray-700 dark:text-gray-100">
Новая задача
</h3>
<button type="button" @click="$emit('close')" class="transition-colors text-gray-400 dark:text-gray-300 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center" data-modal-hide="default-modal">
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
</svg>
</button>
</div>
<!-- Modal body -->
<div class="p-4 md:p-5 space-y-4">
<div class="space-y-6">
<div>
<label for="name" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-200">Задача</label>
<div class="mt-2">
<input @input="error=' '" v-model="name" id="name" name="name" type="text" required class="px-2 block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-inset sm:text-sm sm:leading-6" />
</div>
</div>
<div>
<div class="flex items-center justify-between">
<label for="description" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-200">Описание</label>
</div>
<div class="mt-2">
<textarea v-model="description" id="description" name="description" class="px-2 py-1.5 block w-full rounded-md border-0 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-inset sm:text-sm sm:leading-6" />
</div>
</div>
<div>
<div class="flex items-center justify-between">
<label for="priority" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-200">Приоритет</label>
</div>
<div class="mt-2">
<input v-model="priority" type="number" required min="0" max="10" step="1" id="priority" name="priority" class="px-2 py-1.5 block w-48 rounded-md border-0 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-inset sm:text-sm sm:leading-6" />
</div>
</div>
</div>
</div>
<!-- Modal footer -->
<div class="flex items-center py-3 px-5 md:p-3 border-t border-gray-200 rounded-b">
<input type="submit" class="text-white bg-green-500 hover:bg-green-600 transition-colors font-medium rounded-lg text-sm px-5 py-2.5 text-center" value="Создать">
<p class="ml-3 text-red-500">{{error}}</p>
</div>
</form>
</div>
</div>
</template>
<style scoped>
</style>
+69
View File
@@ -0,0 +1,69 @@
<script setup>
import {invoke} from "@tauri-apps/api";
const props = defineProps({
task_id: String,
task_name: String,
task_description: String
})
let name = props.task_name
let description = props.task_description
async function send_edited_task(){
await invoke('edit_task', {
idTask: props.task_id,
name: name,
description: description
}).then(() => location.reload());
}
</script>
<template>
<div id="create-task-modal" tabindex="-1" aria-hidden="true" class="px-[5vw] md:px-[10vw] lg:px-[15vw] absolute overflow-y-auto overflow-x-hidden w-full top-20 lg:top-24 z-50">
<div class="relative p-4 max-h-full">
<!-- Modal content -->
<form class="relative bg-white rounded-lg shadow dark:bg-[rgb(50,50,50)]" @submit.prevent="send_edited_task">
<!-- Modal header -->
<div class="flex items-center justify-between px-5 py-2 md:py-3 border-b rounded-t">
<h3 class="text-xl font-semibold text-gray-700 dark:text-gray-100">
Новая задача
</h3>
<button type="button" @click="$emit('close')" class="transition-colors text-gray-400 dark:text-gray-300 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center" data-modal-hide="default-modal">
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
</svg>
</button>
</div>
<!-- Modal body -->
<div class="p-4 md:p-5 space-y-4">
<div class="space-y-6">
<div>
<label for="name" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-200">Задача</label>
<div class="mt-2">
<input v-model="name" id="name" name="name" type="text" required class="px-2 block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-inset sm:text-sm sm:leading-6" />
</div>
</div>
<div>
<div class="flex items-center justify-between">
<label for="description" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-200">Описание</label>
</div>
<div class="mt-2">
<textarea v-model="description" id="description" name="description" class="px-2 py-1.5 block w-full rounded-md border-0 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-inset sm:text-sm sm:leading-6" />
</div>
</div>
</div>
</div>
<!-- Modal footer -->
<div class="flex items-center py-3 px-5 md:p-3 border-t border-gray-200 rounded-b">
<input type="submit" class="text-white bg-green-500 hover:bg-green-600 transition-colors font-medium rounded-lg text-sm px-5 py-2.5 text-center" value="Создать">
</div>
</form>
</div>
</div>
</template>
<style scoped>
</style>
+4
View File
@@ -0,0 +1,4 @@
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");