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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user