CSS cleanups and preparations
This commit is contained in:
parent
72bddf3c9f
commit
0269ed5c60
18 changed files with 66 additions and 529 deletions
|
@ -1,31 +0,0 @@
|
|||
// Emoji zoom-in functionality.
|
||||
|
||||
import { addSpell } from "treehouse/spells.js";
|
||||
import { attachTooltip, Tooltip } from "treehouse/overlay.js";
|
||||
|
||||
function createEmojiTooltip(emoji, element) {
|
||||
let tooltip = new Tooltip(element, "bottom");
|
||||
tooltip.classList.add("tooltip-emoji");
|
||||
|
||||
let img = tooltip.appendChild(new Image());
|
||||
img.src = element.src;
|
||||
|
||||
let description = tooltip.appendChild(document.createElement("p"));
|
||||
description.textContent = emoji.emojiName;
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
class Emoji {
|
||||
constructor(element) {
|
||||
this.emojiName = element.title;
|
||||
|
||||
// title makes the browser add a tooltip. We replace browser tooltips with our own,
|
||||
// so remove the title.
|
||||
element.title = "";
|
||||
|
||||
attachTooltip(element, () => createEmojiTooltip(this, element)).showOnHover();
|
||||
}
|
||||
}
|
||||
|
||||
addSpell("emoji", Emoji);
|
|
@ -1,116 +0,0 @@
|
|||
export class Overlay extends HTMLElement {}
|
||||
|
||||
/** @type Overlays */
|
||||
export let overlays = null;
|
||||
|
||||
export class Overlays extends HTMLElement {
|
||||
overlays = new Set();
|
||||
|
||||
connectedCallback() {
|
||||
overlays = this;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
overlays = null;
|
||||
}
|
||||
|
||||
open(overlay) {
|
||||
this.appendChild(overlay);
|
||||
this.overlays.add(overlay);
|
||||
return overlay;
|
||||
}
|
||||
|
||||
close(overlay) {
|
||||
this.removeChild(overlay);
|
||||
this.overlays.delete(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("th-overlays", Overlays);
|
||||
|
||||
export class Tooltip extends Overlay {
|
||||
constructor(element, side) {
|
||||
super();
|
||||
|
||||
this.element = element;
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.role = "tooltip";
|
||||
this.setAttribute("th-side", this.side);
|
||||
|
||||
let bb = this.element.getBoundingClientRect();
|
||||
switch (this.side) {
|
||||
// NOTE: The elements are positioned directly at (width / 2) or (height / 2), because
|
||||
// they are transformed to the centre over on the CSS side.
|
||||
|
||||
case "bottom":
|
||||
this.style.left = `${bb.left + bb.width / 2}px`;
|
||||
this.style.top = `${bb.bottom}px`;
|
||||
break;
|
||||
|
||||
case "left":
|
||||
this.style.left = `${bb.left}px`;
|
||||
this.style.top = `${bb.top + bb.height / 2}px`;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error(`th-tooltip: unknown attachment side ${this.side}`);
|
||||
break;
|
||||
}
|
||||
|
||||
this.addEventListener("transitionend", (event) => {
|
||||
if (event.propertyName == "opacity") {
|
||||
let style = getComputedStyle(this);
|
||||
if (style.opacity < 0.01) {
|
||||
this.dispatchEvent(new Event(".close"));
|
||||
}
|
||||
}
|
||||
});
|
||||
// Timeout is zero because we just want to execute this later, to be definitely sure
|
||||
// the transition plays out.
|
||||
setTimeout(() => this.classList.add("transitioned-in"), 0);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.classList.remove("transitioned-in");
|
||||
|
||||
// NOTE: In case there is no transition, we may need to trigger the close event immediately.
|
||||
let style = getComputedStyle(this);
|
||||
if (style.opacity < 0.01) {
|
||||
this.dispatchEvent(new Event(".close"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("th-tooltip", Tooltip);
|
||||
|
||||
export function attachTooltip(element, makeTooltip) {
|
||||
let show = () => {
|
||||
let tooltip = overlays.open(makeTooltip(element));
|
||||
let abortController = new AbortController();
|
||||
|
||||
tooltip.addEventListener(".close", () => {
|
||||
overlays.close(tooltip);
|
||||
abortController.abort();
|
||||
console.log("closing tooltip");
|
||||
});
|
||||
|
||||
window.addEventListener("wheel", () => tooltip.close(), {
|
||||
signal: abortController.signal,
|
||||
passive: true,
|
||||
});
|
||||
element.addEventListener("mouseleave", () => tooltip.close(), {
|
||||
signal: abortController.signal,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
show,
|
||||
showOnHover() {
|
||||
element.addEventListener("mouseenter", show);
|
||||
return this;
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
import { addSpell } from "treehouse/spells.js";
|
||||
|
||||
const settingsKey = "treehouse.settings";
|
||||
const settings = JSON.parse(localStorage.getItem(settingsKey)) || {};
|
||||
|
||||
const defaultSettingValues = {
|
||||
showNewPostIndicator: true,
|
||||
};
|
||||
|
||||
function saveSettings() {
|
||||
localStorage.setItem(settingsKey, JSON.stringify(settings));
|
||||
}
|
||||
|
||||
export function getSettingValue(setting) {
|
||||
return settings[setting] ?? defaultSettingValues[setting];
|
||||
}
|
||||
|
||||
class SettingCheckbox {
|
||||
constructor(element) {
|
||||
element.checked = getSettingValue(element.id);
|
||||
|
||||
element.addEventListener("change", () => {
|
||||
settings[element.id] = element.checked;
|
||||
saveSettings();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addSpell("setting-checkbox", SettingCheckbox);
|
|
@ -1,9 +0,0 @@
|
|||
// Bits and pieces to make the treehouse just a bit more easy to explore.
|
||||
|
||||
// We want to let the user have a selection on collapsible blocks without collapsing them when
|
||||
// the user finishes marking their selection.
|
||||
document.addEventListener("click", event => {
|
||||
if (getSelection().type == "Range") {
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue