* Settings in WIP * Updates some styles * Removes unused import * Adds version and switcher * Adds ionicons instead of fontawesome * Fixes ionicon for vuejs * Updates modules * Adds buefy * Adds search filter as settings * Adds localstorage * Fixes tests * Adds settings for menu width * Changes copy
114 lines
2.3 KiB
Vue
114 lines
2.3 KiB
Vue
<template lang="html">
|
|
<ul class="events" :class="settings.size">
|
|
<li v-for="item in filtered" :key="item.key">
|
|
<span class="date">{{ item.date | relativeTime }}</span>
|
|
<span class="text" v-html="colorize(item.message)"></span>
|
|
</li>
|
|
</ul>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapActions, mapGetters, mapState } from "vuex";
|
|
import { formatRelative } from "date-fns";
|
|
import AnsiConvertor from "ansi-to-html";
|
|
|
|
const ansiConvertor = new AnsiConvertor({ escapeXML: true });
|
|
|
|
export default {
|
|
props: ["messages"],
|
|
name: "LogViewer",
|
|
components: {},
|
|
data() {
|
|
return {
|
|
showSearch: false
|
|
};
|
|
},
|
|
methods: {
|
|
colorize: function(value) {
|
|
return ansiConvertor
|
|
.toHtml(value)
|
|
.replace("<mark>", "<mark>")
|
|
.replace("</mark>", "</mark>");
|
|
}
|
|
},
|
|
computed: {
|
|
...mapState(["searchFilter", "settings"]),
|
|
filtered() {
|
|
const { searchFilter, messages } = this;
|
|
if (searchFilter) {
|
|
const isSmartCase = searchFilter === searchFilter.toLowerCase();
|
|
try {
|
|
const regex = isSmartCase ? new RegExp(searchFilter, "i") : new RegExp(searchFilter);
|
|
return messages
|
|
.filter(d => d.message.match(regex))
|
|
.map(d => ({
|
|
...d,
|
|
message: d.message.replace(regex, "<mark>$&</mark>")
|
|
}));
|
|
} catch (e) {
|
|
if (e instanceof SyntaxError) {
|
|
console.info(`Ignoring SytaxError from search.`, e);
|
|
return messages;
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
return messages;
|
|
}
|
|
},
|
|
filters: {
|
|
relativeTime(date) {
|
|
return formatRelative(date, new Date());
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
<style scoped lang="scss">
|
|
.events {
|
|
padding: 10px;
|
|
font-family: "Roboto Mono", monaco, monospace;
|
|
|
|
& > li {
|
|
word-wrap: break-word;
|
|
line-height: 130%;
|
|
}
|
|
|
|
&.small {
|
|
font-size: 60%;
|
|
}
|
|
|
|
&.medium {
|
|
font-size: 80%;
|
|
}
|
|
|
|
&.large {
|
|
font-size: 120%;
|
|
}
|
|
}
|
|
|
|
.date {
|
|
background-color: #262626;
|
|
color: #258ccd;
|
|
}
|
|
|
|
.text {
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
::v-deep mark {
|
|
border-radius: 2px;
|
|
background-color: #ffdd57;
|
|
animation: pops 0.2s ease-out;
|
|
display: inline-block;
|
|
}
|
|
|
|
@keyframes pops {
|
|
0% {
|
|
transform: scale(1.5);
|
|
}
|
|
100% {
|
|
transform: scale(1.05);
|
|
}
|
|
}
|
|
</style>
|