Compare commits
No commits in common. "2911f05dcd011025a2dd8a55106af1155050f862" and "16b5aba457a76dd0cfdae9f02d92364d4bbb8ee6" have entirely different histories.
2911f05dcd
...
16b5aba457
|
|
@ -1,99 +0,0 @@
|
||||||
<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>
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
<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>
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import Bun from "bun"
|
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
|
|
||||||
const to_absolute_path = (p: string): string => {
|
const to_absolute_path = (p: string): string => {
|
||||||
|
|
@ -41,8 +40,6 @@ class Config {
|
||||||
private _session_timeout: number = 15 * 60 * 1000
|
private _session_timeout: number = 15 * 60 * 1000
|
||||||
private _session_refresh_grace: number = 5 * 60 * 1000 // time until expiration
|
private _session_refresh_grace: number = 5 * 60 * 1000 // time until expiration
|
||||||
|
|
||||||
readonly bypass_login = this.is_debug && process.env.BYPASS_LOGIN == "true"
|
|
||||||
|
|
||||||
get log_dir(): string {
|
get log_dir(): string {
|
||||||
return this._log_dir
|
return this._log_dir
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,46 +158,6 @@ class UserMgmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LOGIN_BYPASS_Mgmt extends UserMgmt {
|
const _manager = new UserMgmt()
|
||||||
global_session: SessionData | null = null
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super()
|
|
||||||
|
|
||||||
db.user.findFirst().then((user) => {
|
|
||||||
if (!user) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.global_session = {
|
|
||||||
token: "",
|
|
||||||
user: user,
|
|
||||||
expires: new Date(8640000000000000), // Max Time
|
|
||||||
issued: new Date()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async login(): Promise<SessionData | null> {
|
|
||||||
if (!this.global_session) {
|
|
||||||
const user = await db.user.findFirst()
|
|
||||||
if (user) {
|
|
||||||
this.global_session = {
|
|
||||||
token: "",
|
|
||||||
user: user,
|
|
||||||
expires: new Date(8640000000000000), // Max Time
|
|
||||||
issued: new Date()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.global_session
|
|
||||||
}
|
|
||||||
|
|
||||||
async session_login(): Promise<SessionData | null> {
|
|
||||||
return this.login()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _manager = (Config.is_debug && Config.bypass_login) ? new _LOGIN_BYPASS_Mgmt() : new UserMgmt()
|
|
||||||
|
|
||||||
export default _manager
|
export default _manager
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
<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,31 +0,0 @@
|
||||||
import type { RequestHandler } from "./$types";
|
|
||||||
|
|
||||||
import { json, error } from "@sveltejs/kit"
|
|
||||||
|
|
||||||
import { Error401Cause } from "$lib/errors";
|
|
||||||
|
|
||||||
import db from "$lib/server/database"
|
|
||||||
|
|
||||||
enum StatusFilterValues {
|
|
||||||
all,
|
|
||||||
open,
|
|
||||||
done,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ request, locals, url }) => {
|
|
||||||
|
|
||||||
const filter_param = url.searchParams.get("status")
|
|
||||||
const filter = (filter_param && filter_param in StatusFilterValues)
|
|
||||||
? StatusFilterValues[filter_param as keyof typeof StatusFilterValues]
|
|
||||||
: StatusFilterValues.all
|
|
||||||
|
|
||||||
const tasks = await db.task.findMany({
|
|
||||||
where: {
|
|
||||||
userId: {
|
|
||||||
equals: locals.user.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return json(tasks)
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
import type { RequestHandler } from "./$types";
|
|
||||||
|
|
||||||
import { json, error } from "@sveltejs/kit"
|
|
||||||
|
|
||||||
import db from "$lib/server/database"
|
|
||||||
|
|
||||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
|
||||||
|
|
||||||
const data = await request.formData()
|
|
||||||
|
|
||||||
const content = data.get("content")
|
|
||||||
|
|
||||||
if (!content || typeof content !== "string") {
|
|
||||||
return error(400, { message: "content must be specified" })
|
|
||||||
}
|
|
||||||
|
|
||||||
const task = await db.task.create({
|
|
||||||
data: {
|
|
||||||
content: content,
|
|
||||||
user: {
|
|
||||||
connect: {
|
|
||||||
id: locals.user.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return json(task)
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,3 @@
|
||||||
|
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