Skip to content

Commit

Permalink
chore(node): improved label editable
Browse files Browse the repository at this point in the history
  • Loading branch information
heristop committed Sep 20, 2024
1 parent 0eaf03f commit 268db62
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 55 deletions.
77 changes: 77 additions & 0 deletions app/components/EditableLabel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
const props = defineProps<{
value: string
isEditing: boolean
}>()
const emit = defineEmits<{
(e: 'update:value', value: string): void
(e: 'update:isEditing', value: boolean): void
}>()
const inputRef = ref<HTMLInputElement | null>(null)
const inputValue = ref(props.value)
onMounted(() => {
if (props.isEditing) {
nextTick(() => {
inputRef.value?.focus()
inputRef.value?.select()
})
}
})
const finishEditing = () => {
emit('update:value', inputValue.value)
emit('update:isEditing', false)
}
</script>

<template>
<input
v-if="isEditing"
ref="inputRef"
v-model="inputValue"
class="edit-input"
@blur="finishEditing"
@keyup.enter="finishEditing"
@keyup.esc="finishEditing"
>
<span
v-else
class="node-text cursor-text"
@click="$emit('update:isEditing', true)"
>
{{ value }}
</span>
</template>

<style scoped>
.edit-input {
text-align: center;
background: rgba(255, 255, 255, 0.1);
border: none;
border-bottom: 1px solid white;
color: white;
outline: none;
transition: all 0.3s;
padding: 2px 4px;
border-radius: 2px;
}
.edit-input:focus {
background: rgba(255, 255, 255, 0.2);
border-bottom: 2px solid white;
outline: none;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.node-text {
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
59 changes: 25 additions & 34 deletions app/components/TreeNode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ watch(() => props.node, (newNode) => {
const displayContent = computed({
get: () => store.displayLabel === 'key' ? localKey.value : localName.value,
set: (value) => {
set: (value: string) => {
if (store.displayLabel === 'key') {
localKey.value = value
updateSectionKey(props.node.key, value)
Expand Down Expand Up @@ -122,21 +122,6 @@ const addSiblingNode = (event: MouseEvent) => {
}
}
const startEditing = (event: MouseEvent) => {
event.stopPropagation()
isEditing.value = true
nextTick(() => {
const input = event.target as HTMLInputElement
input.focus()
input.select()
})
}
const finishEditing = () => {
isEditing.value = false
}
const deleteNode = (event: MouseEvent) => {
event.stopPropagation()
deleteSection(props.node.key)
Expand Down Expand Up @@ -165,6 +150,19 @@ const handleDragOver = (event: DragEvent) => {
event.preventDefault()
}
const handleLabelUpdate = (newValue: string) => {
if (store.displayLabel === 'key') {
updateSectionKey(props.node.key, newValue)
}
else {
updateSectionName(props.node.key, newValue)
}
}
const handleTitleClick = (event: MouseEvent) => {
event.stopPropagation()
}
watch(() => [props.node.status, store.statuses], () => {
nodeStatus.value = props.node.status || store.statuses[0]?.name || ''
checkIfSuccessNode(props.node)
Expand Down Expand Up @@ -243,7 +241,10 @@ const applySuccessAnimation = (node: Section) => {
@dragover="handleDragOver"
@click="handleClick"
>
<div :class="['node-title', { 'center-title': !node.children || !node.children.length }]">
<div
:class="['node-title', { 'center-title': !node.children || !node.children.length }]"
@click="handleTitleClick"
>
<span
v-if="node.children && node.children.length"
class="collapse-icon"
Expand Down Expand Up @@ -284,22 +285,12 @@ const applySuccessAnimation = (node: Section) => {
</svg>
</span>

<input
v-if="isEditing"
v-model="displayContent"
class="edit-input"
@click.stop
@blur="finishEditing"
@keyup.enter="finishEditing"
>

<span
v-else
class="node-text cursor-text"
@click="startEditing"
>
{{ displayContent }}
</span>
<EditableLabel
:value="displayContent"
:is-editing="isEditing"
@update:value="handleLabelUpdate"
@update:is-editing="isEditing = $event"
/>

<div
v-if="store.isEditingMode && !isEditing"
Expand Down Expand Up @@ -465,7 +456,7 @@ const applySuccessAnimation = (node: Section) => {
font-size: 0.875rem;
font-weight: bold;
color: white;
background-color: rgba(0, 0, 0, 0.25);
background-color: rgba(0, 0, 0, 0.15);
pointer-events: auto;
padding: 8px;
margin: 2px;
Expand Down
60 changes: 48 additions & 12 deletions app/components/ui/TButton.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,70 @@
<script setup lang="ts">
withDefaults(defineProps<{
import { computed } from 'vue'
interface ButtonProps {
isActive?: boolean
size?: 'sm' | 'md' | 'lg'
fullWidth?: boolean
ariaLabel?: string
}>(), {
disabled?: boolean
type?: 'button' | 'submit' | 'reset'
}
const props = withDefaults(defineProps<ButtonProps>(), {
isActive: false,
size: 'md',
fullWidth: false,
ariaLabel: '',
disabled: false,
type: 'button',
})
const emit = defineEmits<{
(e: 'click', event: MouseEvent): void
}>()
const sizeClasses = computed(() => ({
sm: 'px-2 py-1 text-xs',
md: 'px-4 py-2 text-sm',
lg: 'px-6 py-3 text-base',
}[props.size]))
const stateClasses = computed(() => {
if (props.disabled) {
return 'bg-stone-300 text-stone-500 cursor-not-allowed dark:bg-stone-600 dark:text-stone-400 border-stone-400 dark:border-stone-500'
}
return props.isActive
? 'bg-stone-500 dark:bg-stone-100 text-white dark:text-stone-500 border-stone-600 dark:border-stone-300'
: 'bg-stone-200 hover:bg-stone-300 border-stone-200 text-stone-700 dark:bg-stone-500 dark:hover:bg-stone-600 dark:text-stone-200 dark:border-stone-400 hover:border-stone-400 dark:hover:border-stone-300'
})
defineEmits(['click'])
const handleClick = (event: MouseEvent) => {
if (!props.disabled) {
emit('click', event)
}
}
</script>

<template>
<button
:class="[
'flex items-center justify-center rounded shadow transition-colors duration-200',
'border-2 border-opacity-45',
size === 'sm' ? 'px-2 py-2 text-xs' : size === 'md' ? 'px-4 py-2 text-sm' : 'px-6 py-3 text-base',
isActive
? 'bg-stone-500 dark:bg-stone-100 text-white dark:text-stone-500 border-stone-600 dark:border-stone-300'
: 'bg-stone-200 hover:bg-stone-300 border-stone-300 text-stone-700 dark:bg-stone-500 dark:hover:bg-stone-600 dark:text-stone-200 dark:border-stone-400 hover:border-stone-400 dark:hover:border-stone-400',
fullWidth ? 'w-full' : '',
'flex items-center justify-center rounded shadow transition-all duration-200',
'border-2 border-opacity-45 focus:shadow-md',
sizeClasses,
stateClasses,
{ 'w-full': fullWidth },
]"
:aria-label="ariaLabel"
@click="$emit('click')"
:disabled="disabled"
:type="type"
@click="handleClick"
>
<slot name="icon" />
<span
v-if="$slots.icon"
class="mr-2 transition-transform duration-200 ease-in-out group-hover:scale-110"
>
<slot name="icon" />
</span>
<slot />
</button>
</template>
18 changes: 9 additions & 9 deletions app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ onMounted(() => {
<template>
<div
:class="{ dark: darkMode }"
class="relative w-full min-h-screen overflow-auto bg-stone-50 dark:bg-stone-900 text-stone-900 dark:text-stone-50"
class="relative w-full min-h-screen overflow-auto bg-stone-200 dark:bg-stone-900 text-stone-900 dark:text-stone-50"
>
<DarkModeToggle
fixed
Expand Down Expand Up @@ -207,7 +207,7 @@ onMounted(() => {
>
<TButton
:is-active="false"
class="bg-stone-300 hover:bg-stone-400 border-stone-400 text-stone-800 hover:text-stone-200"
class="bg-stone-300/40 hover:bg-stone-400/40 border-stone-400"
aria-label="View My Projects"
@click="() => navigateToLastCreatedProject()"
>
Expand Down Expand Up @@ -270,7 +270,7 @@ onMounted(() => {
<div class="flex flex-col w-full md:w-fit md:flex-row md:space-x-4 text-center space-y-6 md:space-y-0">
<TButton
:is-active="false"
class="bg-stone-300 hover:bg-stone-400 border-stone-400 text-stone-800 hover:text-stone-200"
class="bg-stone-300/40 hover:bg-stone-400/40 border-stone-400"
aria-label="Load Project Project"
@click="loadConfigFromApi('blank')"
>
Expand All @@ -296,7 +296,7 @@ onMounted(() => {

<TButton
:is-active="false"
class="bg-stone-300 hover:bg-stone-400 border-stone-400 text-stone-800 hover:text-stone-200"
class="bg-stone-300/40 hover:bg-stone-400/40 border-stone-400"
aria-label="Load Project Migration Data"
@click="loadConfigFromApi('ecom-migration')"
>
Expand All @@ -323,7 +323,7 @@ onMounted(() => {

<TButton
:is-active="false"
class="bg-stone-300 hover:bg-stone-400 border-stone-400 text-stone-800 hover:text-stone-200"
class="bg-stone-300/40 hover:bg-stone-400/40 border-stone-400"
aria-label="Load Bug Tracking Data"
@click="loadConfigFromApi('bug-tracking')"
>
Expand All @@ -350,7 +350,7 @@ onMounted(() => {

<TButton
:is-active="false"
class="bg-stone-300 hover:bg-stone-400 border-stone-400 text-stone-800 hover:text-stone-200"
class="bg-stone-300/40 hover:bg-stone-400/40 border-stone-400"
aria-label="Load Recruitment Data"
@click="loadConfigFromApi('recruitment')"
>
Expand Down Expand Up @@ -392,7 +392,7 @@ onMounted(() => {
<div class="flex flex-col w-full md:w-fit md:flex-row md:space-x-4 space-y-6 md:space-y-0">
<TButton
:is-active="false"
class="bg-stone-300 hover:bg-stone-400 border-stone-400 text-stone-800 hover:text-stone-200"
class="bg-stone-300/40 hover:bg-stone-400/40 border-stone-400"
aria-label="Upload File"
@click="($refs.fileInput as HTMLInputElement).click()"
>
Expand Down Expand Up @@ -429,7 +429,7 @@ onMounted(() => {
<TButton
:is-active="false"
:disabled="!url"
class="bg-stone-300 hover:bg-stone-400 border-stone-400 text-stone-800 hover:text-stone-200"
class="bg-stone-300/40 hover:bg-stone-400/40 border-stone-400"
aria-label="Load Configuration from URL"
@click="loadConfigFromUrl(url)"
>
Expand Down Expand Up @@ -489,7 +489,7 @@ onMounted(() => {
<TButton
:is-active="false"
full-width
class="bg-stone-300 hover:bg-stone-400 border-stone-400 text-stone-800 hover:text-stone-200 mt-4"
class="bg-stone-300/40 hover:bg-stone-400/40 border-stone-400 mt-4"
aria-label="Load Sample Data"
@click="loadConfigFromUserInput"
>
Expand Down

0 comments on commit 268db62

Please sign in to comment.