-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(node): improved label editable
- Loading branch information
Showing
4 changed files
with
159 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters