All checks were successful
Test and deploy staging / staging (push) Successful in 11m52s
123 lines
4.3 KiB
Svelte
Executable File
123 lines
4.3 KiB
Svelte
Executable File
<script lang="ts">
|
||
import { resolve } from '$app/paths';
|
||
import { Button } from '$lib/components/ui/button/index.js';
|
||
import { Badge } from '$lib/components/ui/badge/index.js';
|
||
import { Input } from '$lib/components/ui/input/index.js';
|
||
import { Label } from '$lib/components/ui/label/index.js';
|
||
import { Textarea } from '$lib/components/ui/textarea/index.js';
|
||
import * as Card from '$lib/components/ui/card/index.js';
|
||
import ProgressBar from '$lib/components/ProgressBar.svelte';
|
||
import type { PageProps } from './$types';
|
||
|
||
let { data }: PageProps = $props();
|
||
</script>
|
||
|
||
<div class="mx-auto max-w-4xl space-y-6 px-4 py-12 sm:px-6">
|
||
<Button href={resolve('/projects/progress')} variant="ghost" size="sm">← All tasks</Button>
|
||
{#if data.task}
|
||
<header>
|
||
<h1 class="text-4xl font-semibold tracking-tight">{data.task.name}</h1>
|
||
<p class="mt-2 text-muted-foreground">
|
||
{data.task.currentPoints}/{data.task.totalPoints} points
|
||
</p>
|
||
</header>
|
||
<ProgressBar
|
||
value={data.task.currentPoints}
|
||
max={data.task.totalPoints}
|
||
label={`Progress on ${data.task.name}`}
|
||
/>
|
||
<Card.Root
|
||
><Card.Header><Card.Title>Topics</Card.Title></Card.Header><Card.Content class="space-y-4">
|
||
<div class="flex flex-wrap gap-2">
|
||
{#each data.task.tasksToTopics as relation (relation.topicId)}
|
||
{#if relation.topic}
|
||
<div class="flex items-center gap-1">
|
||
<a
|
||
href={resolve('/projects/progress/topics/[id]', {
|
||
id: String(relation.topic.id)
|
||
})}><Badge variant="secondary">{relation.topic.name}</Badge></a
|
||
>
|
||
{#if data.editable}<form method="POST" action="?/removeTopic">
|
||
<input type="hidden" name="topic-id" value={relation.topic.id} /><Button
|
||
type="submit"
|
||
variant="ghost"
|
||
size="icon-xs"
|
||
aria-label={`Remove ${relation.topic.name}`}>×</Button
|
||
>
|
||
</form>{/if}
|
||
</div>
|
||
{/if}
|
||
{/each}
|
||
</div>
|
||
{#if data.editable}
|
||
<form method="POST" action="?/addTopic" class="flex flex-wrap items-end gap-2">
|
||
<div class="min-w-48 flex-1 space-y-2">
|
||
<Label for="topic-id">Add existing topic</Label><select
|
||
id="topic-id"
|
||
name="topic-id"
|
||
required
|
||
class="h-9 w-full rounded-md border border-input bg-background px-2.5 text-sm"
|
||
><option value="">Choose a topic</option
|
||
>{#each data.topics as topic (topic.id)}<option value={topic.id}
|
||
>{topic.name}</option
|
||
>{/each}</select
|
||
>
|
||
</div>
|
||
<Button type="submit" variant="outline">Add</Button>
|
||
</form>
|
||
<form method="POST" action="?/createTopic" class="flex flex-wrap items-end gap-2">
|
||
<div class="min-w-48 flex-1 space-y-2">
|
||
<Label for="new-topic">New topic</Label><Input id="new-topic" name="name" required />
|
||
</div>
|
||
<Button type="submit" variant="outline">Create</Button>
|
||
</form>
|
||
{/if}
|
||
</Card.Content></Card.Root
|
||
>
|
||
<Card.Root
|
||
><Card.Header><Card.Title>Progress</Card.Title></Card.Header><Card.Content>
|
||
<form method="POST" action="?/updateProgress" class="flex flex-wrap items-end gap-3">
|
||
<div class="space-y-2">
|
||
<Label for="current-points">Current</Label><Input
|
||
id="current-points"
|
||
type="number"
|
||
name="currentPoints"
|
||
min={0}
|
||
value={data.task.currentPoints}
|
||
readonly={!data.editable}
|
||
class="w-28"
|
||
/>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="total-points">Total</Label><Input
|
||
id="total-points"
|
||
type="number"
|
||
name="totalPoints"
|
||
min={1}
|
||
value={data.task.totalPoints}
|
||
readonly={!data.editable}
|
||
class="w-28"
|
||
/>
|
||
</div>
|
||
{#if data.editable}<Button type="submit">Save progress</Button>{/if}
|
||
</form>
|
||
</Card.Content></Card.Root
|
||
>
|
||
<Card.Root
|
||
><Card.Header><Card.Title>Notes</Card.Title></Card.Header><Card.Content
|
||
><form method="POST" action="?/updateNotes" class="space-y-3">
|
||
<Label for="task-notes" class="sr-only">Notes</Label><Textarea
|
||
id="task-notes"
|
||
name="notes"
|
||
value={data.task.notes ?? ''}
|
||
readonly={!data.editable}
|
||
class="min-h-36"
|
||
/>{#if data.editable}<Button type="submit">Save notes</Button>{/if}
|
||
</form></Card.Content
|
||
></Card.Root
|
||
>
|
||
{:else}
|
||
<p class="text-muted-foreground">Task not found.</p>
|
||
{/if}
|
||
</div>
|