ptitlutins/app/components/molecules/EditableTitle.vue
2026-06-15 23:34:49 +02:00

119 lines
2.4 KiB
Vue

<script setup lang="ts">
import type { Node } from "~/types"
const props = defineProps<{
node: Node
}>()
const emit = defineEmits<{
rename: [title: string]
}>()
const editing = ref(false)
const val = ref(props.node.event.title)
const inputRef = ref<HTMLInputElement | null>(null)
watch(
() => [props.node.id, props.node.event.title],
() => {
val.value = props.node.event.title
}
)
const commit = () => {
// Enter submits the form AND triggers blur as the input unmounts — guard the
// re-entry, and only emit when the title actually changed (no no-op rename).
if (!editing.value) return
editing.value = false
const v = val.value.trim()
if (v && v !== props.node.event.title) emit("rename", v)
else val.value = props.node.event.title
}
const cancel = () => {
val.value = props.node.event.title
editing.value = false
}
const startEditing = async () => {
editing.value = true
await nextTick()
inputRef.value?.focus()
}
</script>
<template>
<form v-if="editing" class="title-form" @submit.prevent="commit">
<input
ref="inputRef"
v-model="val"
class="title-input"
@blur="commit"
@keydown.esc="cancel"
>
</form>
<button
v-else
type="button"
class="title-edit"
:title="$t('voyage.node.rename')"
@click="startEditing"
>
<span class="title-text">{{ node.event.title }}</span>
<Icon name="carbon:edit" size="1rem" class="title-pen" />
</button>
</template>
<style scoped>
.title-form {
display: contents;
}
.title-input,
.title-edit {
font-family: var(--font-display);
font-weight: var(--weight-semibold);
font-size: 1.85rem;
line-height: 1.05;
color: var(--primary-color);
text-align: center;
}
.title-input {
width: 100%;
box-sizing: border-box;
background: var(--surface-input);
border: 2px solid var(--color-6);
border-radius: var(--radius-md);
padding: 2px 10px;
outline: none;
}
.title-edit {
display: inline-flex;
align-items: center;
gap: 7px;
max-width: 100%;
border: 2px solid transparent;
border-radius: var(--radius-md);
background: transparent;
cursor: text;
padding: 2px 10px;
}
.title-text {
text-shadow: 0 0 8px var(--neutral-0);
overflow-wrap: anywhere;
}
.title-pen {
color: var(--neutral-40);
flex-shrink: 0;
opacity: 0;
transition: opacity 140ms ease;
}
.title-edit:hover .title-pen {
opacity: 1;
}
</style>