78 lines
1.8 KiB
Vue
78 lines
1.8 KiB
Vue
<template>
|
|
<div class="flex flex-col flex-1">
|
|
<div
|
|
class="sticky top-0 z-10 flex items-center justify-between pl-4 border-b bg-primary border-dividerLight"
|
|
>
|
|
<label for="log" class="py-2 font-semibold text-secondaryLight">
|
|
{{ title }}
|
|
</label>
|
|
</div>
|
|
<div ref="logsRef" name="log" class="realtime-log">
|
|
<span v-if="log" class="space-y-2">
|
|
<span
|
|
v-for="(entry, index) in log"
|
|
:key="`entry-${index}`"
|
|
:style="{ color: entry.color }"
|
|
class="font-mono"
|
|
>{{ entry.ts }}{{ source(entry.source) }}{{ entry.payload }}</span
|
|
>
|
|
</span>
|
|
<span v-else>{{ t("response.waiting_for_connection") }}</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { nextTick, ref, watch } from "@nuxtjs/composition-api"
|
|
import { getSourcePrefix as source } from "~/helpers/utils/string"
|
|
import { useI18n } from "~/helpers/utils/composables"
|
|
|
|
const t = useI18n()
|
|
|
|
const props = defineProps({
|
|
log: { type: Array, default: () => [] },
|
|
title: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
})
|
|
|
|
const logsRef = ref<any | null>(null)
|
|
const BOTTOM_SCROLL_DIST_INACCURACY = 5
|
|
|
|
watch(
|
|
() => props.log,
|
|
() => {
|
|
if (!logsRef.value) return
|
|
const distToBottom =
|
|
logsRef.value.scrollHeight -
|
|
logsRef.value.scrollTop -
|
|
logsRef.value.clientHeight
|
|
if (distToBottom < BOTTOM_SCROLL_DIST_INACCURACY) {
|
|
nextTick(() => (logsRef.value.scrollTop = logsRef.value.scrollHeight))
|
|
}
|
|
}
|
|
)
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.realtime-log {
|
|
@apply p-4;
|
|
@apply bg-transparent;
|
|
@apply text-secondary;
|
|
@apply overflow-auto;
|
|
|
|
height: 256px;
|
|
|
|
&,
|
|
span {
|
|
@apply select-text;
|
|
}
|
|
|
|
span {
|
|
@apply block;
|
|
@apply break-words break-all;
|
|
}
|
|
}
|
|
</style>
|