92 lines
1.9 KiB
Vue
92 lines
1.9 KiB
Vue
<template>
|
|
<div
|
|
class="parsed-log relative flex h-8 w-full items-center overflow-hidden rounded-lg px-6"
|
|
@mouseenter="checkOverflow"
|
|
@touchstart="checkOverflow"
|
|
>
|
|
<div ref="logContent" class="log-content flex-1 truncate whitespace-pre">
|
|
<span v-html="sanitizedLog"></span>
|
|
</div>
|
|
<button
|
|
v-if="isOverflowing"
|
|
class="ml-2 flex h-6 items-center rounded-md bg-bg px-2 text-xs text-contrast opacity-50 transition-opacity hover:opacity-100"
|
|
type="button"
|
|
@click.stop="$emit('show-full-log', props.log)"
|
|
>
|
|
...
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import Convert from 'ansi-to-html'
|
|
import DOMPurify from 'dompurify'
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
|
|
const props = defineProps<{
|
|
log: string
|
|
}>()
|
|
|
|
defineEmits<{
|
|
'show-full-log': [log: string]
|
|
}>()
|
|
|
|
const logContent = ref<HTMLElement | null>(null)
|
|
const isOverflowing = ref(false)
|
|
|
|
const checkOverflow = () => {
|
|
if (logContent.value && !isOverflowing.value) {
|
|
isOverflowing.value = logContent.value.scrollWidth > logContent.value.clientWidth
|
|
}
|
|
}
|
|
|
|
const convert = new Convert({
|
|
fg: '#FFF',
|
|
bg: '#000',
|
|
newline: false,
|
|
escapeXML: true,
|
|
stream: false,
|
|
})
|
|
|
|
const sanitizedLog = computed(() =>
|
|
DOMPurify.sanitize(convert.toHtml(props.log), {
|
|
ALLOWED_TAGS: ['span'],
|
|
ALLOWED_ATTR: ['style'],
|
|
USE_PROFILES: { html: true },
|
|
}),
|
|
)
|
|
|
|
const preventSelection = (e: MouseEvent) => {
|
|
e.preventDefault()
|
|
}
|
|
|
|
onMounted(() => {
|
|
logContent.value?.addEventListener('mousedown', preventSelection)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
logContent.value?.removeEventListener('mousedown', preventSelection)
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.parsed-log {
|
|
background: transparent;
|
|
transition: background-color 0.1s;
|
|
}
|
|
|
|
.parsed-log:hover {
|
|
background: rgba(128, 128, 128, 0.25);
|
|
transition: 0s;
|
|
}
|
|
|
|
.log-content > span {
|
|
user-select: none;
|
|
white-space: pre;
|
|
}
|
|
|
|
.log-content {
|
|
white-space: pre;
|
|
}
|
|
</style>
|