Merge branch 'main' into massive-relayout

# Conflicts:
#	assets/styles/root/050_ruby_controls.css
#	layouts/partials/ruby_controls.html
This commit is contained in:
Eryn Wells 2023-10-14 15:00:00 -07:00
commit d45ad449a5
12 changed files with 269 additions and 70 deletions

View file

@ -0,0 +1,169 @@
// Eryn Wells <eryn@erynwells.me>
class RubySwitch extends HTMLElement {
static controlSizeInPixels = 32;
static thumbTransitionDuration = 0.1;
static settings = [
{
id: "ruby-switch-none",
value: "none",
label: "あ"
},
{
id: "ruby-switch-both",
value: "both",
label: "<ruby>あ<rt>a</rt></ruby>",
default: true
},
{
id: "ruby-switch-hidden",
value: "hidden",
label: "ab"
},
];
#root;
#thumb;
constructor() {
super();
this.#updateValue(RubySwitch.settings.find(obj => obj.default).value);
this.addEventListener("RubyStyleChanged", event => {
this.#updateValue(event.detail.style);
});
this.#root = this.attachShadow({ mode: "closed" });
this.#buildShadowDOM();
this.#updateThumbPosition(this.#root.querySelector(".control[data-default]"));
}
#updateValue(style) {
this.setAttribute("value", style);
}
get #stylesheet() {
const controlSize = RubySwitch.controlSizeInPixels;
const halfControlSize = controlSize / 2;
return `
#ruby-controls {
box-sizing: border-box;
display: inline-block;
position: relative;
}
#controls {
border: none;
box-sizing: border-box;
display: inline grid;
grid-template-columns: repeat(3, ${controlSize}px);
margin: 0;
overflow: none;
padding: 0;
}
#thumb {
box-sizing: border-box;
box-shadow: 2px 2px 6px #ccc;
border: 0.5px solid #aaa;
border-radius: ${halfControlSize}px;
position: absolute;
top: 0;
height: ${controlSize}px;
width: ${controlSize}px;
z-index: 50;
transition: left ${RubySwitch.thumbTransitionDuration}s;
}
.control {
aspect-ratio: 1;
display: flex;
justify-content: center;
align-items: center;
height: ${controlSize}px;
width: ${controlSize}px;
}
b {
font-weight: normal;
cursor: pointer;
}
label {
z-index: 2;
text-align: center;
}
#ruby-switch-both {
}
`;
}
#buildShadowDOM() {
const root = this.#root;
const style = document.createElement("style");
style.textContent = this.#stylesheet;
root.appendChild(style);
let container = document.createElement("div");
container.id = "ruby-controls";
root.appendChild(container);
let controls = document.createElement("div");
controls.id = "controls";
container.appendChild(controls);
for (const desc of RubySwitch.settings) {
let control = document.createElement("div");
control.classList.add("control")
control.id = desc.id;
control.dataset.value = desc.value;
if (desc.default) {
control.dataset.default = "";
}
controls.appendChild(control);
control.addEventListener("click", event => {
event.stopPropagation();
event.preventDefault();
this.#updateThumbPosition(event.currentTarget);
this.#root.dispatchEvent(new CustomEvent("RubyStyleChanged", {
bubbles: true,
composed: true,
detail: {
style: control.dataset.value,
},
}));
}, { capture: true });
const label = document.createElement("b");
label.innerHTML = desc.label;
control.appendChild(label);
}
const thumb = document.createElement("div");
this.#thumb = thumb;
thumb.id = "thumb";
container.appendChild(thumb);
}
#updateThumbPosition(selectedControl) {
const controls = this.#root.querySelector("#controls");
const trackBoundingRect = controls.getBoundingClientRect();
const controlBoundingRect = selectedControl.getBoundingClientRect();
const offset = controlBoundingRect.left - trackBoundingRect.left;
this.#thumb.style.left = `${offset}px`;
}
}
customElements.define("ruby-switch", RubySwitch);

View file

@ -1,35 +1,25 @@
@layer root {
#ruby-controls {
align-items: baseline;
display: flex;
padding: calc(var(--body-item-spacing) / 2);
body:has(ruby-switch[value=none]) rt {
display: none;
}
body:has(#ruby-controls > input[value=NONE]:checked) rt { display: none; }
/* When the ruby switch is set to "hidden", hide the ruby base and only show the <rt>. */
body:has(ruby-switch[value=hidden]) ruby > span {
display: none;
}
/* When ruby-controls is set to hidden, hide the ruby base and only show the <rt> */
body:has(#ruby-controls > input[value=HIDDEN]:checked) ruby > span { display: none; }
body:has(#ruby-controls > input[value=HIDDEN]:checked) rt {
body:has(ruby-switch[value=hidden]) rt {
color: inherit;
display: inline;
font-size: inherit;
white-space: inherit;
}
body:has(#ruby-controls > input[value=HIDDEN]:checked) :is(h1, h2, h3, h4, h5, h6) rt {
body:has(ruby-switch[value=hidden]) :is(h1, h2, h3, h4, h5, h6) rt {
font-family: var(--font-family-heading);
font-weight: bold;
}
fieldset#ruby-controls input[type=radio]:not(:last-child) {
margin-inline-end: 0.5rem;
}
fieldset#ruby-controls label:not(:last-child) {
margin-inline-end: 2rem;
}
rt { transition: color 0.3s; }
ruby:hover rt { transition: color 0.3s; }
}