aboutsummaryrefslogtreecommitdiff
path: root/src/routes/projects
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-09-12 10:58:39 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-09-12 10:58:39 +0200
commit012a1dc35c69cb51ff15b21f8303787b5299a626 (patch)
treed6d39c7259eff637c62126d4739768ea8846647d /src/routes/projects
parentbd2f982c489b15ce1165c051fdedf35af979f784 (diff)
improve projects layout on mobile
Diffstat (limited to 'src/routes/projects')
-rw-r--r--src/routes/projects/[id]/+page.server.ts16
-rw-r--r--src/routes/projects/[id]/+page.svelte135
-rw-r--r--src/routes/projects/[projectId]/routine/[routineId]/+page.server.ts5
-rw-r--r--src/routes/projects/[projectId]/routine/[routineId]/+page.svelte55
4 files changed, 79 insertions, 132 deletions
diff --git a/src/routes/projects/[id]/+page.server.ts b/src/routes/projects/[id]/+page.server.ts
index 19aea9b..3321bcd 100644
--- a/src/routes/projects/[id]/+page.server.ts
+++ b/src/routes/projects/[id]/+page.server.ts
@@ -8,11 +8,7 @@ import {
loadProjectDashboard,
loadArchived,
} from '$lib/server/services/routines';
-import {
- archiveRoutineAction,
- completeRoutineAction,
- editRoutineAction,
-} from '$lib/server/services/routine-actions';
+import { completeRoutineAction } from '$lib/server/services/routine-actions';
import {
numericId,
parseFormString,
@@ -56,21 +52,11 @@ export const actions: Actions = {
return { success: true };
},
- editRoutine: async ({ request }) => {
- const data = await request.formData();
- return editRoutineAction(data, numericId(data.get('id')));
- },
-
complete: async ({ request }) => {
const data = await request.formData();
return completeRoutineAction(data, numericId(data.get('id')));
},
- archiveRoutine: async ({ request }) => {
- const data = await request.formData();
- return archiveRoutineAction(numericId(data.get('id')));
- },
-
archiveProject: async ({ params }) => {
await archiveProject(numericId(params.id));
throw redirect(303, '/');
diff --git a/src/routes/projects/[id]/+page.svelte b/src/routes/projects/[id]/+page.svelte
index 9931f40..8a3561b 100644
--- a/src/routes/projects/[id]/+page.svelte
+++ b/src/routes/projects/[id]/+page.svelte
@@ -15,12 +15,8 @@
let name = $state('');
let frequency = $state('');
- let editingId = $state<number | null>(null);
- let editName = $state('');
- let editFrequency = $state('');
const frequencyDays = $derived(parseIntervalToDays(frequency));
- const editFrequencyDays = $derived(parseIntervalToDays(editFrequency));
let showArchived = $state(false);
let archiveFilter = $state('');
@@ -36,12 +32,6 @@
(a, b) => b.overdueRatio - a.overdueRatio || a.name.localeCompare(b.name),
);
}
-
- function startEdit(routine: RoutineState) {
- editingId = routine.id;
- editName = routine.name;
- editFrequency = `${routine.frequencyDays}d`;
- }
</script>
<main>
@@ -113,94 +103,30 @@
<ul class="item-list">
{#each sorted(data.routines) as routine (routine.id)}
<li class="item-row item-row--card routine-row">
- {#if editingId === routine.id}
- <form
- class="edit-form"
- method="POST"
- action="?/editRoutine"
- use:enhance={() => {
- return async ({ result, update }) => {
- if (result.type === 'failure') {
- // Keep the edit form open so the error is visible.
- await update({ reset: false });
- return;
- }
- editingId = null;
- await update({ reset: false });
- };
- }}
- >
- {#if form?.error}
- <p class="error edit-error">{form.error}</p>
- {/if}
- <input type="hidden" name="id" value={routine.id} />
- <input
- class="form-input"
- type="text"
- name="name"
- bind:value={editName}
- />
- <input
- class="form-input frequency-input"
- class:input-invalid={editFrequency !== '' &&
- editFrequencyDays === null}
- type="text"
- name="frequencyDays"
- bind:value={editFrequency}
- placeholder="2w"
- autocomplete="off"
- aria-label="Intervalle (ex: 1d, 2w, 3m)"
+ <form method="POST" action="?/complete" use:enhance>
+ <input type="hidden" name="id" value={routine.id} />
+ <button type="submit" class="btn-ghost">
+ <StatusBadge
+ status={routine.status}
+ overdueDays={routine.overdueDays}
/>
- <button
- class="btn-primary"
- type="submit"
- disabled={!editName.trim() || editFrequencyDays === null}
- >
- OK
- </button>
- <button
- class="btn-ghost"
- type="button"
- onclick={() => (editingId = null)}>✕</button
- >
- </form>
- {:else}
- <StatusBadge
- status={routine.status}
- overdueDays={routine.overdueDays}
- />
- <div class="routine-info">
- <a
- class="routine-name"
- href="/projects/{data.project.id}/routine/{routine.id}"
- >{routine.name}</a
- >
- <span class="routine-meta">
- {formatFrequency(routine.frequencyDays)}
- {#if routine.lastDoneAt}
- · fait le {formatDayMonth(routine.lastDoneAt)}
- {:else}
- · jamais fait
- {/if}
- </span>
- </div>
- <form method="POST" action="?/complete" use:enhance>
- <input type="hidden" name="id" value={routine.id} />
- <button class="btn-done" type="submit">Fait</button>
- </form>
- <button
- class="btn-ghost"
- type="button"
- aria-label="Modifier"
- onclick={() => startEdit(routine)}>✎</button
+ </button>
+ </form>
+ <div class="routine-info">
+ <a
+ class="routine-name"
+ href="/projects/{data.project.id}/routine/{routine.id}"
+ >{routine.name}</a
>
- <form method="POST" action="?/archiveRoutine" use:enhance>
- <input type="hidden" name="id" value={routine.id} />
- <button class="btn-ghost" type="submit" aria-label="Archiver">
- &times;
- </button>
- </form>
- {/if}
+ <span class="routine-meta">
+ {formatFrequency(routine.frequencyDays)}
+ {#if routine.lastDoneAt}
+ · fait le {formatDayMonth(routine.lastDoneAt)}
+ {:else}
+ · jamais fait
+ {/if}
+ </span>
+ </div>
</li>
{/each}
</ul>
@@ -303,23 +229,6 @@
color: var(--text-secondary);
}
- .edit-form {
- display: flex;
- flex-grow: 1;
- gap: 0.5rem;
- align-items: center;
- flex-wrap: wrap;
- }
-
- .edit-error {
- width: 100%;
- }
-
- .edit-form .form-input {
- flex: 1;
- padding: 0.5rem 0.75rem;
- }
-
.frequency-input {
width: 4.5rem;
flex-shrink: 0;
diff --git a/src/routes/projects/[projectId]/routine/[routineId]/+page.server.ts b/src/routes/projects/[projectId]/routine/[routineId]/+page.server.ts
index bdfa452..891a7b6 100644
--- a/src/routes/projects/[projectId]/routine/[routineId]/+page.server.ts
+++ b/src/routes/projects/[projectId]/routine/[routineId]/+page.server.ts
@@ -2,6 +2,7 @@ import { error } from '@sveltejs/kit';
import { getById } from '$lib/server/services/projects';
import { loadCurrent, loadCompletions } from '$lib/server/services/routines';
import {
+ archiveRoutineAction,
completeRoutineAction,
editRoutineAction,
} from '$lib/server/services/routine-actions';
@@ -49,4 +50,8 @@ export const actions: Actions = {
const data = await request.formData();
return completeRoutineAction(data, numericId(params.routineId));
},
+
+ archive: async ({ params }) => {
+ return archiveRoutineAction(numericId(params.routineId));
+ },
};
diff --git a/src/routes/projects/[projectId]/routine/[routineId]/+page.svelte b/src/routes/projects/[projectId]/routine/[routineId]/+page.svelte
index e593ad1..74880cb 100644
--- a/src/routes/projects/[projectId]/routine/[routineId]/+page.svelte
+++ b/src/routes/projects/[projectId]/routine/[routineId]/+page.svelte
@@ -103,7 +103,7 @@
class="form-input desc"
name="description"
bind:value={description}
- rows={3}
+ rows={6}
placeholder="Pourquoi, comment, quand..."
autocomplete="off"
></textarea>
@@ -112,13 +112,15 @@
<p class="error">Intervalle invalide — ex : 1d, 2w, 3m, 1y</p>
{/if}
<button
- class="btn-primary"
+ class="btn-primary btn-save"
type="submit"
disabled={!name.trim() || frequencyDays === null}
>
- Enregistrer
+ <span class="btn-save-label">Enregistrer</span>
+ <span class="btn-save-check" class:visible={saved} aria-hidden="true"
+ >✓</span
+ >
</button>
- <p class="save-status" class:visible={saved}>✓ Enregistré</p>
</form>
{/if}
@@ -188,6 +190,14 @@
{#if data.completions.length === 0}
<p class="empty">Aucune réalisation pour l'instant.</p>
{/if}
+
+ {#if !data.routine.archived}
+ <footer class="page-footer">
+ <form method="POST" action="?/archive" use:enhance>
+ <button class="btn-archive" type="submit">Archiver la routine</button>
+ </form>
+ </footer>
+ {/if}
</main>
<style>
@@ -268,4 +278,41 @@
font-size: 0.875rem;
color: var(--text-secondary);
}
+
+ .page-footer {
+ margin-top: 2rem;
+ display: flex;
+ justify-content: center;
+ }
+
+ .btn-archive {
+ border: none;
+ background: transparent;
+ color: var(--text-secondary);
+ font-size: 0.875rem;
+ text-decoration: underline;
+ cursor: pointer;
+ }
+
+ .btn-archive:hover {
+ color: var(--danger);
+ }
+
+ .btn-save {
+ position: relative;
+ padding-right: 2.75rem;
+ }
+
+ .btn-save-check {
+ position: absolute;
+ right: 1rem;
+ top: 50%;
+ transform: translateY(-50%);
+ opacity: 0;
+ transition: opacity 0.2s ease;
+ }
+
+ .btn-save-check.visible {
+ opacity: 1;
+ }
</style>