Merge branch 'ruby-switch'
This commit is contained in:
commit
bf37618430
5 changed files with 187 additions and 23 deletions
169
assets/scripts/ruby_switch.js
Normal file
169
assets/scripts/ruby_switch.js
Normal 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);
|
|
@ -1,29 +1,25 @@
|
|||
@layer root {
|
||||
body:has(fieldset#ruby-controls > input[value=NONE]:checked) rt { display: none; }
|
||||
body:has(ruby-switch[value=none]) rt {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* When ruby-controls is set to hidden, hide the ruby base and only show the <rt> */
|
||||
body:has(fieldset#ruby-controls > input[value=HIDDEN]:checked) ruby > span { 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;
|
||||
}
|
||||
|
||||
body:has(fieldset#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(fieldset#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] {
|
||||
margin-inline-end: calc(var(--body-item-spacing) / 6);
|
||||
}
|
||||
|
||||
fieldset#ruby-controls label {
|
||||
margin-inline-end: calc(var(--body-item-spacing));
|
||||
}
|
||||
|
||||
rt { transition: color 0.3s; }
|
||||
ruby:hover rt { transition: color 0.3s; }
|
||||
}
|
||||
|
|
|
@ -30,6 +30,11 @@
|
|||
{{ block "scripts" . }}{{ end }}
|
||||
|
||||
{{- with partial "resources/site_js.html" . -}}
|
||||
<script type="module" src="{{ .RelPermalink }}"></script>
|
||||
<script type="module" src="{{ .Permalink }}"></script>
|
||||
{{ end }}
|
||||
{{ if .HasShortcode "ruby" }}
|
||||
{{ with partial "resources/script.html" "ruby_switch" }}
|
||||
<script type="module" src="{{ .Permalink }}"></script>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</html>
|
||||
|
|
2
layouts/partials/resources/script.html
Normal file
2
layouts/partials/resources/script.html
Normal file
|
@ -0,0 +1,2 @@
|
|||
{{ $script := resources.Get (printf "scripts/%s.js" .) | fingerprint "md5" }}
|
||||
{{ return $script }}
|
|
@ -1,13 +1,5 @@
|
|||
{{ if .HasShortcode "ruby" -}}
|
||||
<aside>
|
||||
<fieldset id="ruby-controls">
|
||||
<legend>Ruby</legend>
|
||||
<input id="none" type="radio" name="ruby-controls" value="NONE">
|
||||
<label for="none">Japanese Only</label>
|
||||
<input id="both" type="radio" name="ruby-controls" value="BOTH" checked>
|
||||
<label for="both">Both</label>
|
||||
<input id=hidden type=radio name=ruby-controls value=HIDDEN>
|
||||
<label for=hidden>English Only</label>
|
||||
</fieldset>
|
||||
<ruby-switch>
|
||||
</aside>
|
||||
{{- end }}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue