Files
FiDA_Front/src/views/home/components/input/InputEditor.vue
2026-04-30 14:18:19 +08:00

232 lines
4.0 KiB
Vue

<template>
<div class="editor-wrapper" :class="{ agent: isAgentMode }">
<div v-if="showPlaceholder" class="editor-placeholder">
{{ placeholder }}
</div>
<div
ref="editorRef"
class="editor"
contenteditable="true"
@input="emit('input')"
@paste="emit('paste', $event)"
@keydown="emit('keydown', $event)"
></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
withDefaults(
defineProps<{
showPlaceholder?: boolean
placeholder: string
isAgentMode?: boolean
}>(),
{
showPlaceholder: false,
isAgentMode: false
}
)
const emit = defineEmits<{
(e: 'ready', element: HTMLDivElement | null): void
(e: 'input'): void
(e: 'paste', event: ClipboardEvent): void
(e: 'keydown', event: KeyboardEvent): void
}>()
const editorRef = ref<HTMLDivElement | null>(null)
const focus = () => {
editorRef.value?.focus()
}
onMounted(() => {
emit('ready', editorRef.value)
})
defineExpose({
editorRef,
focus
})
</script>
<style lang="less" scoped>
.editor-wrapper {
flex: 1;
display: flex;
flex-direction: column;
position: relative;
min-height: 0;
.editor-placeholder {
position: absolute;
z-index: 0;
pointer-events: none;
top: 0;
left: 0;
padding: 0 1.4rem 1.4rem;
font-size: 2rem;
font-family: 'InterRegular';
font-weight: 400;
color: #999;
white-space: pre-wrap;
word-wrap: break-word;
width: calc(100% - 2.8rem);
box-sizing: border-box;
}
.editor {
width: 100%;
flex: 1;
border: none;
outline: none;
padding: 0 1.4rem 1.4rem;
font-size: 1.8rem;
font-family: 'InterRegular';
font-weight: 400;
color: #000000;
overflow-y: auto;
overflow-x: hidden;
line-height: 2.8rem;
white-space: pre-wrap;
word-wrap: break-word;
&::-webkit-scrollbar {
width: 0;
display: none;
}
&::-webkit-scrollbar-thumb,
&::-webkit-scrollbar-track {
display: none;
}
&:empty::before {
content: attr(placeholder);
color: #999;
pointer-events: none;
}
}
&.agent {
.editor {
font-family: 'Regular';
font-weight: 400;
font-size: 1.4rem;
min-height: 5rem;
max-height: initial;
padding: 0;
height: 100%;
line-height: 1.4rem;
}
.editor-placeholder {
font-family: 'Regular';
font-size: 1.4rem;
padding: 0;
line-height: 1.4rem;
}
}
}
</style>
<style lang="less">
.assist-input-wrapper .editor .editor-tag {
width: 15.6rem;
height: 3.1rem;
display: inline-flex;
border: 1px solid #0000001a;
font-weight: 500;
font-size: 1.3rem;
column-gap: 0;
margin: 0 0.5rem;
vertical-align: middle;
border-radius: 2.2rem;
&.restore {
width: auto;
max-width: 100%;
display: inline-flex;
border: none;
border-radius: 0.4rem;
background-color: rgba(0, 0, 0, 0.05);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
align-items: center;
justify-content: space-between;
padding: 0 0.9rem 0 0.7rem;
box-sizing: border-box;
}
&.option-tag {
width: auto;
max-width: 24rem;
height: 3.4rem;
padding: 0 1rem;
box-sizing: border-box;
align-items: center;
column-gap: 0.8rem;
color: #0d0d0d;
.option-tag-icon {
width: 1.2rem;
height: 1.2rem;
flex-shrink: 0;
}
.option-tag-text {
margin: 0;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.option-close {
width: 0.7rem;
height: 0.7rem;
margin-left: 0.2rem;
}
}
span {
margin: 0 0.7rem 0 1.2rem;
&.restore-text {
flex: 1;
min-width: 0;
max-width: 52rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.light-icon {
width: 0.9rem;
height: 1.2rem;
flex-shrink: 0;
}
.close-icon {
width: 0.9rem;
height: 0.9rem;
cursor: pointer;
flex-shrink: 0;
&.restore {
width: 0.5rem;
height: 0.5rem;
}
}
.restore-icon {
width: 1.2rem;
height: 1.2rem;
}
}
</style>