Auto-growing name box for the new-project tile

Replace the plain <input> with a rows=1 <textarea> that grows to fit
its content on input, so a long or wrapped name stays fully visible
instead of scrolling. Enter still submits rather than adding a
newline, and the box resets to one row after a successful create.

Also make the tile's background transparent (dashed border stays) and
drop its 'Create a project' title, keeping just the Name field --
accessible label moved to aria-label since the placeholder now stands
alone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 20:03:18 +01:00
co-authored by Claude Sonnet 5
parent 47429daaa6
commit 49c10673d2
2 changed files with 44 additions and 4 deletions
+35 -3
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { computed, nextTick, onMounted, ref } from 'vue'
import { RouterLink } from 'vue-router'
import { ApiError } from '../lib/api'
import { MAX_PROJECTS, useProjectsStore } from '../stores/projects'
@@ -11,6 +11,25 @@ const loadError = ref<string | null>(null)
const title = ref('')
const createError = ref<ApiError | null>(null)
const submitting = ref(false)
const titleInput = ref<HTMLTextAreaElement | null>(null)
// Grows the textarea to fit its content instead of scrolling, so a name
// that wraps stays fully visible.
function resizeTitleInput() {
const el = titleInput.value
if (!el) return
el.style.height = 'auto'
el.style.height = `${el.scrollHeight}px`
}
// Matches a plain <input>'s behaviour: Enter submits rather than inserting
// a newline (the box only grows from wrapping, e.g. a long pasted name).
function onTitleKeydown(e: KeyboardEvent) {
if (e.key === 'Enter') {
e.preventDefault()
onCreate()
}
}
const atLimit = computed(() => projects.projects.length >= MAX_PROJECTS)
@@ -31,6 +50,8 @@ async function onCreate() {
try {
await projects.createProject(title.value)
title.value = ''
await nextTick()
resizeTitleInput()
} catch (e) {
createError.value = e instanceof ApiError ? e : new ApiError('Could not create the project.', 0)
} finally {
@@ -59,8 +80,19 @@ async function onCreate() {
<form class="project-card project-card--new" @submit.prevent="onCreate">
<label>
<span class="project-card__title">Create a project</span>
<input v-model="title" type="text" maxlength="255" placeholder="Name" required :disabled="atLimit" />
<textarea
ref="titleInput"
v-model="title"
class="project-card__name-input"
rows="1"
maxlength="255"
placeholder="Name"
aria-label="Name"
required
:disabled="atLimit"
@input="resizeTitleInput"
@keydown="onTitleKeydown"
></textarea>
<small v-if="createError?.fieldError('title')" class="field-error">
{{ createError.fieldError('title') }}
</small>