Skip to content

Instantly share code, notes, and snippets.

@kulmann
Created April 13, 2022 08:39
Show Gist options
  • Save kulmann/555ae7f7424d049b5f8ff4a8f5d360b7 to your computer and use it in GitHub Desktop.
Save kulmann/555ae7f7424d049b5f8ff4a8f5d360b7 to your computer and use it in GitHub Desktop.
<template>
<span :is="tag">
<template v-for="(fragments, lineIndex) in lines">
<template v-for="(fragment, fragmentIndex) in fragments">
<span
:is="fragment.tag"
:key="'line-' + lineIndex + '-fragment-' + fragmentIndex"
:style="{
'--background-color': highlightedColor,
display: fragment.value.startsWith(' ') || fragment.value.endsWith(' ') ? 'inline' : 'inline-block'
}"
:class="{ highlighted: fragment.highlighted }"
>
{{ fragment.value }}
</span>
</template>
<br v-if="lineIndex < lines.length - 1" :key="'line-' + lineIndex + '-br'" />
</template>
</span>
</template>
<script>
import split from "lodash/split";
import map from "lodash/map";
import filter from "lodash/filter";
export default {
props: {
tag: {
type: String,
default: "span"
},
fragmentTag: {
type: String,
default: "span",
validator: function (value) {
return ["span", "i", "b"].includes(value);
}
},
value: {
type: String,
required: true
},
highlighted: {
type: String,
default: null
},
highlightedColor: {
type: String,
default: "yellow"
}
},
computed: {
lines() {
const regex = new RegExp("\\n");
const lines = split(this.value, regex);
return map(
filter(lines, (line, index) => {
// note: split creates an empty first and last element. this removes those.
return !((index === 0 || index === lines.length - 1) && line.length === 0);
}),
line => this.buildFragments(line)
);
}
},
methods: {
buildFragments(line) {
if (this.highlighted) {
const regex = new RegExp("(" + this.highlighted + ")", "gi");
const textFragments = split(line, regex);
if (textFragments.length > 1) {
return map(textFragments, fragment => {
if (fragment.match(regex)) {
return {
tag: this.fragmentTag,
value: fragment,
highlighted: true
};
} else {
return {
tag: this.fragmentTag,
value: fragment,
highlighted: false
};
}
});
}
}
// if not highlighting or no matches found (i.e. result = whole value), return a single fragment
return [
{
tag: this.fragmentTag,
value: line,
highlighted: false
}
];
}
}
};
</script>
<style lang="scss" scoped>
.highlighted {
background-color: var(--background-color);
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment