JSFiddle - React, Tailwind, and code Playground
by Scott Kaye
HTML
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicin doloribus?</p>
<p>Lorem ipsum dolor sit amet.</p>
<p>Lorem ipsum dolor sit amet.</p>
</div>
SCSS
#kHighlighter {
width: 100%;
background: #eee;
border-top: 1px solid #ccc;
font-family: Segoe UI;
font-size: 0.85em;
position: fixed;
bottom: 0;
left: 0;
.highlighter-thumb {
-webkit-user-select: none;
cursor: pointer;
display: inline-block;
width: 30px;
text-align: right;
box-shadow: inset 5px 0 0 rgba(0,0,0,0.1);
margin: 0 2px;
padding: 2px 5px;
background: #ccc;
color: #000;
position: relative;
&.selected {
font-weight: 700;
box-shadow: inset 5px 0 0 rgba(0,0,0,0.1), 0 -5px 0;
}
}
}
JavaScript
const $highlighter = Symbol("highlighter");
const $isHighlighter = Symbol("is-highlighter");
function getTreePath(el) {
let parent = el;
let path = [];
let limit = 0;
while(!parent.isSameNode(document.documentElement) && ++limit < 100) {
path.unshift([...parent.parentNode.childNodes].indexOf(parent));
parent = parent.parentNode;
}
return path;
}
let selectedHighlighter = null;
class kHighlighter {
constructor(parent) {
this.element = this.create(parent);
document.body.addEventListener("mouseup", kHighlighter.documentMouseUp, false);
// Load saved highlights
let saved = new Map(JSON.parse(localStorage["kHighlighter"] || "[]"));
for (let [path, h] of saved) {
path = JSON.parse(path);
let el = document.documentElement;
path.forEach(i => {
if (!el || !el.childNodes) return;
el = el.childNodes[i];
});
if (el) {
new Highlighter(h.bg, h.fg).highlightNode(el, false);
}
}
}
handleSelect(el) {
if (selectedHighlighter) {
selectedHighlighter.classList.remove("selected");
}
if (selectedHighlighter === el) {
el.classList.remove("selected");
selectedHighlighter = null;
this.exitHighlightMode();
return;
}
selectedHighlighter = el;
el.classList.add("selected");
this.enterHighlightMode();
}
enterHighlightMode() {
let style = document.querySelector("#kHighlighter-style") || document.createElement("style");
style.innerText = `*::selection {
background: ${selectedHighlighter[$highlighter].bg};
color: ${selectedHighlighter[$highlighter].fg}
}`;
style.id = "kHighlighter-style";
document.body.appendChild(style);
}
exitHighlightMode() {
document.body.removeChild(document.querySelector("#kHighlighter-style"));
selectedHighlighter = null;
}
static documentMouseUp(e) {
if (!selectedHighlighter) return;
if (!e.target || e.target[$isHighlighter]) {
return;
}
selectedHighlighter[$highlighter].highlightNode(e.target);
}
create(parent)...