Move the new-project form into the dashboard grid as a tile

It now sits last in .dashboard__grid, styled like a project-card (dashed
border to read as an action rather than a project) instead of as a
separate form below the grid. Relabel it 'Create a project' and add a
'Name' placeholder to the input.

Also drop the now-redundant 'no projects yet' empty-state message --
the grid always renders since the create tile lives inside it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 19:59:03 +01:00
co-authored by Claude Sonnet 5
parent 9d51ecc367
commit 47429daaa6
4 changed files with 46 additions and 31 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ Each user owns **projects**, and each project holds ordered **cards**.
| 8 | Passwordless login — magic-link by default, password login behind a toggle | ✅ done |
| 9 | Per-project card statuses ("To do" / "Doing" / "Done"); status chip, new cards start with none | ✅ done |
| 10 | Project view — full-width, tabbed: alphabetical "All tasks" list + "Kanban" board, per-column drag ordering | ✅ done |
| 11 | Persistent left sidebar (Dashboard link + project dropdown); dashboard = grid of project tiles + new-project form | ✅ done |
| 11 | Persistent left sidebar (Dashboard link + project dropdown); dashboard = grid of project tiles + a "Create a project" tile | ✅ done |
| 12 | Passwordless-only auth — registration and password login removed; a magic link is the sole way in, and creates the account if needed | ✅ done |
| 13 | Global inbox — cards can have no project; moved into the sidebar, drag in/out of any project's kanban columns | ✅ done |
| 14 | New-project form moved to the dashboard; sidebar project list is now a switcher dropdown; Kanban is a project's default tab | ✅ done |
+4 -3
View File
@@ -58,9 +58,10 @@ it also works as a project switcher from anywhere. `<RouterView
projects always does a fresh load.
`/` redirects to `/dashboard` (`DashboardView.vue`): a full-width grid linking
to each project (title + card count), then a **new-project form** directly
below it (creating one stays on the dashboard; the grid and the sidebar
dropdown both pick it up via the shared `projects` store). Signed-out routes
to each project (title + card count), with a **"Create a project" tile**
styled to match sitting last in the same grid (creating one stays on the
dashboard; the grid and the sidebar dropdown both pick it up via the shared
`projects` store). Signed-out routes
(`/login`, `/verify-email`) render without the sidebar.
## Inbox
+19 -1
View File
@@ -360,6 +360,25 @@ h1 {
font-size: 0.85rem;
}
.project-card--new {
border-style: dashed;
}
.project-card--new label {
display: grid;
gap: 0.3rem;
font-size: 0.9rem;
}
.project-card--new input {
padding: 0.55rem 0.7rem;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--bg);
color: var(--text);
font-size: 1rem;
}
/* --- project detail: cards ------------------------------------------ */
.cards {
@@ -743,7 +762,6 @@ h1 {
margin: 1.25rem 0;
}
.form--new-project,
.form--new-card {
margin-top: 1.5rem;
padding-top: 1.25rem;
+4 -8
View File
@@ -43,10 +43,6 @@ async function onCreate() {
<div class="dashboard">
<p v-if="loadError" class="form-error">{{ loadError }}</p>
<p v-else-if="projects.loading && !projects.loaded" class="muted">Loading</p>
<p v-else-if="projects.projects.length === 0" class="muted">
No projects yet create one below. Anything uncategorised lives in the
inbox, in the sidebar.
</p>
<div v-else class="dashboard__grid">
<RouterLink
@@ -60,12 +56,11 @@ async function onCreate() {
{{ project.card_count }} card{{ project.card_count === 1 ? '' : 's' }}
</span>
</RouterLink>
</div>
<form class="form form--new-project" @submit.prevent="onCreate">
<form class="project-card project-card--new" @submit.prevent="onCreate">
<label>
<span>New project title</span>
<input v-model="title" type="text" maxlength="255" required :disabled="atLimit" />
<span class="project-card__title">Create a project</span>
<input v-model="title" type="text" maxlength="255" placeholder="Name" required :disabled="atLimit" />
<small v-if="createError?.fieldError('title')" class="field-error">
{{ createError.fieldError('title') }}
</small>
@@ -84,4 +79,5 @@ async function onCreate() {
</p>
</form>
</div>
</div>
</template>