aboutsummaryrefslogtreecommitdiff
path: root/src/routes/+page.svelte
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-09-07 11:32:41 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-09-07 11:32:41 +0200
commit18a0f9c874aaa09c0f71252dad853c23f9511ed6 (patch)
tree93103b83f6d0057c40f0bab9c9473bf04292e9c4 /src/routes/+page.svelte
parent113415ce357a9cea1759d0452ebae6352f8fe36b (diff)
Add projects with routines, urgency tracking and health scores
Projects group recurring routines (chores included) with an append-only snapshot table (id, version) so edits never rewrite history; completions reference the exact snapshot. Pure metrics compute due dates, urgency buckets (ok/due/late/veryLate) and 0-100 health scores per routine, project, and globally. Home page lists projects; project dashboard sorts routines most-urgent first with one-tap completion and interval parser inputs (1d/2w/3m/1y).
Diffstat (limited to 'src/routes/+page.svelte')
-rw-r--r--src/routes/+page.svelte144
1 files changed, 140 insertions, 4 deletions
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 5bdee46..4d4777a 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1,4 +1,140 @@
-<p>Accueil — à venir : projets et routines.</p>
-<ul>
- <li><a href="/groceries">Courses</a></li>
-</ul>
+<script lang="ts">
+ import { enhance } from '$app/forms';
+
+ let { data, form } = $props();
+
+ let name = $state('');
+
+ function scoreClass(score: number): string {
+ if (score >= 80) return 'score score--good';
+ if (score >= 50) return 'score score--mid';
+ return 'score score--bad';
+ }
+</script>
+
+<main>
+ <header class="page-header">
+ <h1>Projets</h1>
+ <span class={scoreClass(data.globalScore)}>{data.globalScore}</span>
+ </header>
+
+ <form class="cat-add-bar" method="POST" action="?/addProject" use:enhance>
+ <input
+ class="form-input"
+ type="text"
+ name="name"
+ bind:value={name}
+ placeholder="Nouveau projet..."
+ autocomplete="off"
+ />
+ <button class="btn-accent" type="submit" aria-label="Ajouter">+</button>
+ </form>
+
+ {#if form?.error}
+ <p class="error">{form.error}</p>
+ {/if}
+
+ <ul class="item-list">
+ {#each data.projects as entry (entry.project.id)}
+ <li class="item-row item-row--card project-row">
+ <a class="project-link" href="/projects/{entry.project.id}"
+ >{entry.project.name}</a
+ >
+ <span class={scoreClass(entry.healthScore)}>{entry.healthScore}</span>
+ </li>
+ {/each}
+ </ul>
+
+ {#if data.projects.length === 0}
+ <p class="empty">Aucun projet</p>
+ {/if}
+</main>
+
+<style>
+ .page-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 1.25rem 0;
+ }
+
+ .project-row {
+ padding: 0.875rem 1rem;
+ }
+
+ .project-link {
+ flex-grow: 1;
+ font-weight: 500;
+ color: var(--text);
+ text-decoration: none;
+ }
+
+ .project-link:hover {
+ color: var(--accent);
+ }
+
+ .score {
+ flex-shrink: 0;
+ min-width: 2.75rem;
+ padding: 0.25rem 0.5rem;
+ border-radius: 9999px;
+ text-align: center;
+ font-size: 0.875rem;
+ font-weight: 700;
+ color: var(--white);
+ }
+
+ .score--good {
+ background: var(--success);
+ }
+
+ .score--mid {
+ background: var(--accent);
+ }
+
+ .score--bad {
+ background: var(--danger);
+ }
+
+ .cat-add-bar {
+ display: flex;
+ gap: 0.5rem;
+ padding: 0.75rem 0;
+ }
+
+ .cat-add-bar input {
+ flex: 1;
+ background: var(--surface);
+ }
+
+ .btn-accent {
+ width: 3rem;
+ height: 3rem;
+ flex-shrink: 0;
+ padding: 0;
+ border: none;
+ border-radius: 0.75rem;
+ background: var(--accent);
+ color: var(--white);
+ font-size: 1.25rem;
+ font-weight: 500;
+ font-family: inherit;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.2s ease;
+ box-shadow: 0 1px 2px var(--shadow);
+ }
+
+ .btn-accent:hover {
+ background: var(--accent-hover);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px var(--shadow-accent-lg);
+ }
+
+ .empty {
+ margin-top: 1rem;
+ padding: 2rem;
+ }
+</style>