Files
project-manager/web/src/views/ProjectExploreView.vue
T

73 lines
2.0 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import { computed, ref } from 'vue'
import CardRow from '../components/CardRow.vue'
import { ApiError } from '../lib/api'
import { useCardsStore } from '../stores/cards'
// The project's cards, flat and sorted by name -- ProjectView (the parent
// layout) has already loaded them into this store, keyed to the current
// project, so there's nothing to fetch here.
const cards = useCardsStore()
const actionError = ref<string | null>(null)
const newText = ref('')
const submitting = ref(false)
const summary = computed(() => {
const total = cards.cards.length
if (total === 0) return 'No cards yet.'
return `${total} card${total === 1 ? '' : 's'}.`
})
// No manual order here -- sort by name, case-insensitively.
const sortedCards = computed(() =>
[...cards.cards].sort((a, b) => a.text.localeCompare(b.text, undefined, { sensitivity: 'base' })),
)
async function onCreate() {
submitting.value = true
actionError.value = null
try {
await cards.add(newText.value)
newText.value = ''
} catch (e) {
actionError.value = e instanceof ApiError ? e.message : 'Could not add the card.'
} finally {
submitting.value = false
}
}
</script>
<template>
<div>
<p v-if="actionError" class="form-error">{{ actionError }}</p>
<p class="muted">{{ summary }}</p>
<p v-if="cards.loading && !cards.loaded" class="muted">Loading</p>
<ul v-else-if="sortedCards.length" class="cards">
<CardRow v-for="card in sortedCards" :key="card.id" :card="card" />
</ul>
<form class="kanban__new form--new-card" @submit.prevent="onCreate">
<input
v-model="newText"
class="field field--compact"
type="text"
maxlength="1000"
required
placeholder="New card"
aria-label="New card"
/>
<button
type="submit"
class="btn-icon"
:disabled="submitting"
:title="submitting ? 'Adding…' : 'Add card'"
:aria-label="submitting ? 'Adding…' : 'Add card'"
>+</button>
</form>
</div>
</template>