started impl of task ui
This commit is contained in:
parent
b0b6557464
commit
2911f05dcd
|
|
@ -0,0 +1,99 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
|
|
||||||
|
let { checked = $bindable(), ...props} = $props()
|
||||||
|
|
||||||
|
let loaded = $state(false)
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
loaded = true
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="shell" class:loaded={loaded}>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" bind:checked/>
|
||||||
|
<svg width="10px" height="10px" viewBox="0 0 12 9">
|
||||||
|
<polyline points="1,5 4,8 11,1" fill="none"></polyline>
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateY(-50%) translateX(-50%);
|
||||||
|
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
label:hover {
|
||||||
|
border-color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
label:has(>input:checked) {
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
.loaded label:has(>input:checked) {
|
||||||
|
animation: pop 0.6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loaded label::before {
|
||||||
|
content: "";
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
|
||||||
|
background: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
transform: scale(0);
|
||||||
|
transition-delay: 0.2s;
|
||||||
|
}
|
||||||
|
.loaded label:has(>input:checked)::before {
|
||||||
|
transform: scale(2.2);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pop {
|
||||||
|
50% {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 3px;
|
||||||
|
stroke: white;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
stroke-dasharray: 16px;
|
||||||
|
stroke-dashoffset: 16px;
|
||||||
|
}
|
||||||
|
.loaded svg {
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
label:has(> input:checked) > svg {
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
<script module>
|
||||||
|
|
||||||
|
import type { Task } from "@prisma/client"
|
||||||
|
|
||||||
|
import Checkbox from "./checkbox.svelte"
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
|
export interface TaskComponentProps {
|
||||||
|
task: Task
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
const { task }: TaskComponentProps = $props()
|
||||||
|
|
||||||
|
let loaded = $state(false)
|
||||||
|
onMount(() => { loaded = true })
|
||||||
|
|
||||||
|
let checked = $state(task.checked)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="main-task">
|
||||||
|
<div class="checkbox">
|
||||||
|
<Checkbox bind:checked={checked}/>
|
||||||
|
</div>
|
||||||
|
<div class="taskheader">
|
||||||
|
<div><h2 class="taskheader">{task.content}</h2></div>
|
||||||
|
</div>
|
||||||
|
{#if true}
|
||||||
|
<div class="taskcontent">{@html [task.content, "<br>"].join().repeat(5)}</div>
|
||||||
|
{/if}
|
||||||
|
<div class="due">
|
||||||
|
Due: <br/>
|
||||||
|
{new Date(task.created_at).toLocaleDateString()} <br/>
|
||||||
|
{new Date(task.created_at).toLocaleTimeString()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: var(--width, 100%);
|
||||||
|
min-height: var(--min-height, 50px);
|
||||||
|
|
||||||
|
margin: 2px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid gray;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
justify-items: center;
|
||||||
|
justify-content: stretch;
|
||||||
|
align-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-task {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 25px auto fit-content(11ch);
|
||||||
|
grid-template-areas:
|
||||||
|
'checkboxArea headerArea dueArea';
|
||||||
|
|
||||||
|
column-gap: 10px;
|
||||||
|
|
||||||
|
align-content: stretch;
|
||||||
|
}
|
||||||
|
.main-task:has(.taskcontent) {
|
||||||
|
grid-template-areas:
|
||||||
|
'checkboxArea headerArea dueArea'
|
||||||
|
'. contentArea dueArea';
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
grid-area: checkboxArea;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskheader {
|
||||||
|
grid-area: headerArea;
|
||||||
|
width: fit-content;
|
||||||
|
transform: translateY(0.075em);
|
||||||
|
}
|
||||||
|
.taskheader h2 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.taskcontent {
|
||||||
|
grid-area: contentArea;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.due {
|
||||||
|
grid-area: dueArea;
|
||||||
|
min-width: 11ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loaded {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
.loaded.checked {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import type { Actions, PageServerLoad } from "./$types"
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ locals, fetch }) => {
|
||||||
|
|
||||||
|
const response = await fetch("/api/users/tasks", {
|
||||||
|
method: "GET"
|
||||||
|
})
|
||||||
|
|
||||||
|
return { tasks: await response.json() }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
create: async ({ request, fetch }) => {
|
||||||
|
|
||||||
|
const data = await request.formData()
|
||||||
|
|
||||||
|
const response = await fetch("/api/users/tasks/create", {
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
|
||||||
|
return { }
|
||||||
|
}
|
||||||
|
} satisfies Actions
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms'
|
||||||
|
import Task from '$lib/components/task.svelte'
|
||||||
|
|
||||||
|
const { data } = $props()
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Tasks</h1>
|
||||||
|
|
||||||
|
<div class="task">
|
||||||
|
<form method="POST" action="?/create" use:enhance>
|
||||||
|
<input name="content" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#each data.tasks as task}
|
||||||
|
<Task task={task} --width="75%" />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task {
|
||||||
|
width: 75%;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
--primary-bg-color: white;
|
||||||
|
--primary-text-color: black;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
background-color: var(--primary-bg-color, white);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
color: var(--primary-text-color, black);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue