Switch to nanotrasen blue theme
This commit is contained in:
parent
9a94ccb0a2
commit
9ab5c6816b
6 changed files with 596 additions and 6 deletions
8
assets/images/bg-nanotrasen.svg
Normal file
8
assets/images/bg-nanotrasen.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 425 200" opacity=".33">
|
||||
<path d="m 178.00399,0.03869 -71.20393,0 a 6.7613422,6.0255495 0 0 0 -6.76134,6.02555 l 0,187.87147 a 6.7613422,6.0255495 0 0 0 6.76134,6.02554 l 53.1072,0 a 6.7613422,6.0255495 0 0 0 6.76135,-6.02554 l 0,-101.544018 72.21628,104.699398 a 6.7613422,6.0255495 0 0 0 5.76015,2.87016 l 73.55487,0 a 6.7613422,6.0255495 0 0 0 6.76135,-6.02554 l 0,-187.87147 a 6.7613422,6.0255495 0 0 0 -6.76135,-6.02555 l -54.71644,0 a 6.7613422,6.0255495 0 0 0 -6.76133,6.02555 l 0,102.61935 L 183.76413,2.90886 a 6.7613422,6.0255495 0 0 0 -5.76014,-2.87017 z" />
|
||||
<path d="M 4.8446333,22.10875 A 13.412039,12.501842 0 0 1 13.477588,0.03924 l 66.118315,0 a 5.3648158,5.000737 0 0 1 5.364823,5.00073 l 0,79.87931 z" />
|
||||
<path d="m 420.15535,177.89119 a 13.412038,12.501842 0 0 1 -8.63295,22.06951 l -66.11832,0 a 5.3648152,5.000737 0 0 1 -5.36482,-5.00074 l 0,-79.87931 z" />
|
||||
</svg>
|
||||
<!-- This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. -->
|
||||
<!-- http://creativecommons.org/licenses/by-sa/4.0/ -->
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -8,6 +8,9 @@
|
|||
<title>/tg/ Handbook</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="bgimage">
|
||||
<img src="./assets/images/bg-nanotrasen.svg" />
|
||||
</div>
|
||||
<main id="app"></main>
|
||||
<script src="lib/index.tsx"></script>
|
||||
</body>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { getPageHTML } from "../wiki";
|
||||
import { darken, ColorFmt, lighten } from "../darkmode";
|
||||
import * as React from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import userscript from "../userscript";
|
||||
|
||||
function fixup(html: string): string {
|
||||
// Convert relative links to absolute
|
||||
|
@ -27,9 +28,13 @@ function fixup(html: string): string {
|
|||
});
|
||||
node.querySelectorAll("*[style]").forEach((td: HTMLElement) => {
|
||||
const inlineCSS = td.getAttribute("style");
|
||||
let bgcolor = td.style.background;
|
||||
if (inlineCSS.includes("background-color")) {
|
||||
let bgcolor = null;
|
||||
if (inlineCSS.includes("background-color:")) {
|
||||
bgcolor = td.style.backgroundColor;
|
||||
} else if (inlineCSS.includes("background:")) {
|
||||
bgcolor = td.style.background;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
td.setAttribute(
|
||||
"style",
|
||||
|
@ -56,11 +61,42 @@ function fixup(html: string): string {
|
|||
td.setAttribute("width", "100%");
|
||||
});
|
||||
|
||||
// Group headers and content so stickies don't overlap
|
||||
node.querySelectorAll("h3,h2").forEach((h3) => {
|
||||
const parent = h3.parentNode;
|
||||
const div = document.createElement("div");
|
||||
parent.insertBefore(div, h3);
|
||||
while (h3.nextSibling && !h3.nextSibling.nodeName.startsWith("H")) {
|
||||
const sibling = h3.nextSibling;
|
||||
parent.removeChild(sibling);
|
||||
div.appendChild(sibling);
|
||||
}
|
||||
h3.parentNode.removeChild(h3);
|
||||
div.insertBefore(h3, div.firstChild);
|
||||
div.className = "mw-headline-cont";
|
||||
});
|
||||
|
||||
node.querySelectorAll(".mw-headline").forEach((span: HTMLElement) => {
|
||||
// Find nearest container
|
||||
let parent = span.parentElement;
|
||||
while (parent !== null) {
|
||||
if (parent.classList.contains("mw-headline-cont")) {
|
||||
parent.id = span.id;
|
||||
span.id += "-span";
|
||||
parent.dataset.name = span.innerText;
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
});
|
||||
|
||||
return node.innerHTML;
|
||||
}
|
||||
|
||||
export default function WikiPage({ page }) {
|
||||
const [data, setData] = useState({ loaded: false, html: "" });
|
||||
const containerRef = useRef(null);
|
||||
|
||||
// Fetch page
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let html = await getPageHTML(page);
|
||||
|
@ -68,11 +104,21 @@ export default function WikiPage({ page }) {
|
|||
setData({ loaded: true, html });
|
||||
})();
|
||||
}, []);
|
||||
|
||||
// Page fetched, instance userscript
|
||||
useEffect(() => {
|
||||
if (data.loaded) {
|
||||
console.log("Injecting userscript!");
|
||||
userscript(containerRef.current, page);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
if (!data.loaded) {
|
||||
return <p>You start skimming through the manual...</p>;
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="page"
|
||||
dangerouslySetInnerHTML={{ __html: data.html }}
|
||||
></div>
|
||||
|
|
|
@ -144,7 +144,7 @@ export function darken(color: string, format: ColorFmt): string {
|
|||
const col = parseColor(color);
|
||||
const hsl = rgbToHsv(col);
|
||||
if (hsl.s < 0.15) {
|
||||
hsl.h = 0.1;
|
||||
hsl.h = 0.6;
|
||||
hsl.s = 0.5;
|
||||
hsl.v = Math.max(0.2, 1 - hsl.v);
|
||||
} else {
|
||||
|
|
510
lib/userscript.ts
Normal file
510
lib/userscript.ts
Normal file
|
@ -0,0 +1,510 @@
|
|||
// ==UserScript==
|
||||
// @name Better /tg/ Guides
|
||||
// @namespace https://faulty.equipment
|
||||
// @version 0.2.2
|
||||
// @description Make /tg/station guides better with extra features
|
||||
// @author Hamcha
|
||||
// @collaborator D
|
||||
// @license ISC
|
||||
// @copyright 2020, Hamcha (https://openuserjs.org/users/Hamcha), D
|
||||
// @match https://tgstation13.org/wiki/Guide_to_*
|
||||
// @grant GM_addStyle
|
||||
// ==/UserScript==
|
||||
|
||||
const DEFAULT_OPTS = {
|
||||
alignment: "center",
|
||||
};
|
||||
|
||||
export default function (root: HTMLElement, docname: string) {
|
||||
function GM_addStyle(css) {
|
||||
const style = document.createElement("style");
|
||||
style.innerHTML = css;
|
||||
root.appendChild(style);
|
||||
}
|
||||
|
||||
// Tell user that better chemistry is loading
|
||||
const postbody = root;
|
||||
const statusMessage = document.createElement("div");
|
||||
statusMessage.innerHTML = `
|
||||
<table style="background-color: black; margin-bottom:10px;" width="95%" align="center">
|
||||
<tbody><tr><td align="center">
|
||||
<b>Hang on...</b> Better guides is loading.
|
||||
</td></tr></tbody>
|
||||
</table>`;
|
||||
postbody.insertBefore(statusMessage, postbody.firstChild);
|
||||
|
||||
GM_addStyle(`
|
||||
.bgus_hidden { display: none !important; }
|
||||
.bgus_nobreak { white-space: nowrap; }
|
||||
`);
|
||||
|
||||
// TODO Refactor this mess
|
||||
function searchBox(el, search_candidate, options = DEFAULT_OPTS) {
|
||||
// Fuzzy search box
|
||||
GM_addStyle(
|
||||
`
|
||||
#bgus_fz_searchbox {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 30%;
|
||||
right: 30%;
|
||||
background: rgba(10,10,10,0.8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 9999;
|
||||
color: #fff;
|
||||
}
|
||||
#bgus_fz_searchbox input {
|
||||
font-size: 14pt;
|
||||
padding: 5pt 8pt;
|
||||
border: 1px solid #555;
|
||||
margin: 5px;
|
||||
margin-bottom: 0;
|
||||
background-color: #111;
|
||||
color: #fff;
|
||||
}
|
||||
#bgus_fz_searchbox ul {
|
||||
list-style: none;
|
||||
margin: 5px;
|
||||
padding: 0;
|
||||
}
|
||||
#bgus_fz_searchbox li {
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#bgus_fz_searchbox li:hover {
|
||||
background-color: rgba(100, 100, 100, 0.5);
|
||||
}
|
||||
#bgus_fz_searchbox li.selected {
|
||||
border-left: 3px solid white;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
const resultList = document.createElement("ul");
|
||||
const searchBox = document.createElement("div");
|
||||
let selected_result = null;
|
||||
let results = [];
|
||||
|
||||
const jumpTo = function (id) {
|
||||
el[id].scrollIntoView({
|
||||
block: options.alignment,
|
||||
inline: "nearest",
|
||||
behavior: "auto",
|
||||
});
|
||||
document
|
||||
.querySelectorAll("table.wikitable .bgus_fz_selected")
|
||||
.forEach((el) => el.classList.remove("bgus_fz_selected"));
|
||||
el[id].parentElement.classList.add("bgus_fz_selected");
|
||||
};
|
||||
|
||||
const setSelectedResult = function (i) {
|
||||
selected_result = i;
|
||||
resultList
|
||||
.querySelectorAll(".selected")
|
||||
.forEach((el) => el.classList.remove("selected"));
|
||||
resultList.children[i].classList.add("selected");
|
||||
jumpTo(results[i].id);
|
||||
};
|
||||
|
||||
const search = (str) => {
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
const regex = new RegExp(
|
||||
"^(.*?)([" +
|
||||
str
|
||||
.split("")
|
||||
.map((c) => (c.includes(["\\", "]", "^"]) ? "\\" + c : c))
|
||||
.join("])(.*?)([") +
|
||||
"])(.*?)$",
|
||||
"i"
|
||||
);
|
||||
const arr = search_candidate
|
||||
.map((o) => {
|
||||
o.matches = (o.str.match(regex) || [])
|
||||
.slice(1)
|
||||
.reduce((list, group, i, or) => {
|
||||
// Initialize first placeholder (always empty) and first matching "sections"
|
||||
if (i < 2) {
|
||||
list.push([group]);
|
||||
}
|
||||
// If group is second match in a row join to previous section
|
||||
else if (or[i - 1] === "") {
|
||||
list[list.length - 1].push(group);
|
||||
}
|
||||
// If group is a match create a new section
|
||||
else if (group !== "") {
|
||||
list.push([group]);
|
||||
}
|
||||
return list;
|
||||
}, [])
|
||||
.map((str) => str.join(""));
|
||||
return o;
|
||||
})
|
||||
// Strike non-matching rows
|
||||
.filter((o) => o.matches.length > 0)
|
||||
.sort((oA, oB) => {
|
||||
const iA = oA.id,
|
||||
a = oA.matches;
|
||||
const iB = oB.id,
|
||||
b = oB.matches;
|
||||
|
||||
// Exact match
|
||||
if (a.length === 1 && b.length !== 1) return -1;
|
||||
if (a.length !== 1 && b.length === 1) return 1;
|
||||
|
||||
// Most complete groups (alphanumeric)
|
||||
const clean = (el) => !/[^a-zA-Z0-9]*$/.test(el);
|
||||
const cLen = a.filter(clean).length - b.filter(clean).length;
|
||||
if (cLen !== 0) return cLen;
|
||||
|
||||
// Least distant first gropus
|
||||
for (let i = 0; i < Math.min(a.length, b.length) - 1; i += 2) {
|
||||
const gLen = a[i].length - b[i].length;
|
||||
if (gLen !== 0) return gLen;
|
||||
}
|
||||
|
||||
// Most complete groups (raw)
|
||||
const len = a.length - b.length;
|
||||
if (len !== 0) return len;
|
||||
|
||||
// Make the search stable since ECMAScript doesn't mandate it
|
||||
return iA - iB;
|
||||
});
|
||||
results = arr;
|
||||
window.requestAnimationFrame(() => {
|
||||
resultList.innerHTML = "";
|
||||
arr.forEach(({ matches, id }) => {
|
||||
const li = document.createElement("li");
|
||||
li.innerHTML = matches
|
||||
.map((c, i) => (i % 2 ? "<strong>" + c + "</strong>" : c))
|
||||
.join("");
|
||||
li.addEventListener("click", () => {
|
||||
jumpTo(id);
|
||||
searchBox.classList.add("bgus_hidden");
|
||||
});
|
||||
resultList.appendChild(li);
|
||||
});
|
||||
if (results.length > 0) {
|
||||
setSelectedResult(0);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Create fuzzy search box
|
||||
const sel = document.createElement("input");
|
||||
searchBox.id = "bgus_fz_searchbox";
|
||||
searchBox.classList.add("bgus_hidden");
|
||||
searchBox.appendChild(sel);
|
||||
searchBox.appendChild(resultList);
|
||||
root.appendChild(searchBox);
|
||||
|
||||
// Bind events
|
||||
let oldValue = "";
|
||||
sel.addEventListener("keyup", function (event) {
|
||||
switch (event.keyCode) {
|
||||
case 27: // Escape - Hide bar
|
||||
searchBox.classList.add("bgus_hidden");
|
||||
return;
|
||||
case 13: // Enter - Jump to first result and hide bar
|
||||
if (results.length > 0) {
|
||||
jumpTo(results[selected_result].id);
|
||||
}
|
||||
searchBox.classList.add("bgus_hidden");
|
||||
return;
|
||||
case 40: // Down arrow - Select next result
|
||||
if (selected_result < results.length - 1) {
|
||||
setSelectedResult(selected_result + 1);
|
||||
}
|
||||
return;
|
||||
case 38: // Up arrow - Select previous result
|
||||
if (selected_result > 0) {
|
||||
setSelectedResult(selected_result - 1);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
if (this.value != oldValue) {
|
||||
search(this.value);
|
||||
oldValue = this.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener("keyup", function (ev) {
|
||||
if (ev.keyCode === 83) {
|
||||
sel.focus();
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener("keydown", function (ev) {
|
||||
if (ev.shiftKey) {
|
||||
switch (ev.keyCode) {
|
||||
// SHIFT+S = Fuzzy search
|
||||
case 83: {
|
||||
searchBox.classList.remove("bgus_hidden");
|
||||
sel.value = "";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function betterChemistry() {
|
||||
// Chem styles
|
||||
GM_addStyle(
|
||||
`
|
||||
.bgus_twistie:after {
|
||||
color: red;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-left: .2em;
|
||||
content: '⯆';
|
||||
}
|
||||
.bgus_collapsed > .bgus_nested_element > .bgus_twistie:after{
|
||||
content: '⯈';
|
||||
}
|
||||
:not(.bgus_collapsed) > .bgus_nested_element + .tooltiptext {
|
||||
z-index: unset;
|
||||
visibility: inherit;
|
||||
opacity: 1;
|
||||
position: relative;
|
||||
width: auto;
|
||||
border-left-width: 3px;
|
||||
background: transparent;
|
||||
margin: 5px;
|
||||
margin-right: 0px;
|
||||
font-size: 8pt;
|
||||
padding: 5px 8px;
|
||||
line-height: 10pt;
|
||||
}
|
||||
.bgus_collapsable:not(.bgus_collapsed) + br {
|
||||
display: none;
|
||||
}
|
||||
table.wikitable > tbody > tr > td:nth-child(2) {
|
||||
min-width: 30%;
|
||||
padding: 10px;
|
||||
}
|
||||
.bgus_fz_selected {
|
||||
background-color: #525242;
|
||||
}
|
||||
input[type="checkbox"] + span[data-src] {
|
||||
font-weight: bold;
|
||||
cursor: text;
|
||||
}
|
||||
input[type="checkbox"] + span[data-src]:before {
|
||||
display: inline-block;
|
||||
width: 1.5em; /* Prevent autoscroll with sudden line wraps when revealing checkboxes */
|
||||
text-align: center;
|
||||
}
|
||||
input[type="checkbox"] + span[data-src]:before {
|
||||
content: '•';
|
||||
}
|
||||
.bgus_cbox input[type="checkbox"] + span[data-src]:before {
|
||||
content: '[_]';
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
.bgus_cbox input[type="checkbox"]:checked + span[data-src]:before {
|
||||
content: '[X]';
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
.bgus_cbox input[type="checkbox"]:checked + span[data-src] {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.bgus_cbox input[type="checkbox"] + span[data-src] {
|
||||
cursor: pointer;
|
||||
}
|
||||
.bgus_cbox input[type="checkbox"] + span[data-src] {
|
||||
color: orange;
|
||||
}
|
||||
.bgus_cbox input[type="checkbox"]:checked + span[data-src] {
|
||||
color: green;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
// Fix inconsistencies with <p> on random parts
|
||||
// Ideally I'd like a <p> or something on every part, wrapping it completely, but for now let's just kill 'em
|
||||
new Set(
|
||||
Array.from(
|
||||
root.querySelectorAll(
|
||||
"table.wikitable > tbody > tr:not(:first-child) > td:nth-child(2) p"
|
||||
)
|
||||
).map((p) => p.parentNode)
|
||||
).forEach((parent) => {
|
||||
const tmp = parent.cloneNode();
|
||||
// The cast to Array is necessary because, while childNodes's NodeList technically has a forEach method, it's a live list and operations mess with its lenght in the middle of the loop
|
||||
// Nodes can only have one parent so append removes them from the original NodeList and shifts the following one back into the wrong index
|
||||
Array.from(parent.childNodes).forEach((el) => {
|
||||
if (el.tagName === "P") {
|
||||
tmp.append(...el.childNodes);
|
||||
} else {
|
||||
tmp.append(el);
|
||||
}
|
||||
});
|
||||
parent.parentNode.replaceChild(tmp, parent);
|
||||
});
|
||||
|
||||
// Enrich "x part" with checkboxes and parts
|
||||
Array.from(root.querySelectorAll("td"))
|
||||
.filter((el) => el.innerText.indexOf(" part") >= 0)
|
||||
.map((el) => [el, el.innerHTML])
|
||||
.forEach(([el, innerHTML]) => {
|
||||
el.innerHTML = innerHTML.replace(
|
||||
/((\d+)\s+(?:parts?|units?))(.*?(?:<\s*(\/\s*a|br\s*\/?)\s*>|\n|$))/gi,
|
||||
(match, ...m) =>
|
||||
`<label class="bgus_part ${
|
||||
m[2].includes("</a>") ? "bgus_part_tooltip" : ""
|
||||
}" data-amount="${
|
||||
m[1]
|
||||
}"><input type="checkbox" class='bgus_checkbox bgus_hidden'/> <span class="bgus_part_label" data-src="${
|
||||
m[0]
|
||||
}">${m[0]}</span></label>${m[2].replace(
|
||||
/(<a .+?<\/a>)/gi,
|
||||
'<span class="bgus_nobreak bgus_nested_element">$1<span class="bgus_twistie"></span></span>'
|
||||
)}`
|
||||
);
|
||||
});
|
||||
Array.from(root.querySelectorAll(".bgus_nested_element")).forEach((el) => {
|
||||
el.parentElement.classList.add("bgus_collapsable");
|
||||
});
|
||||
// Add event to autofill child checkboxes
|
||||
document
|
||||
.querySelectorAll(".bgus_part_tooltip > .bgus_checkbox")
|
||||
.forEach((box) => {
|
||||
const tooltip = box.parentElement.nextElementSibling;
|
||||
box.addEventListener("click", function () {
|
||||
tooltip
|
||||
.querySelectorAll(".bgus_checkbox")
|
||||
.forEach((el: HTMLInputElement) => (el.checked = this.checked));
|
||||
});
|
||||
});
|
||||
|
||||
// Add event to collapse subsections
|
||||
root.querySelectorAll(".bgus_nested_element").forEach((twistie) => {
|
||||
twistie.addEventListener("click", function (evt) {
|
||||
twistie.parentElement.classList.toggle("bgus_collapsed");
|
||||
});
|
||||
});
|
||||
|
||||
// Wrap every recipe with extra metadata
|
||||
root.querySelectorAll(".bgus_part").forEach((el: HTMLElement) => {
|
||||
if ("parts" in el.parentElement.dataset) {
|
||||
el.parentElement.dataset.parts = (
|
||||
parseInt(el.parentElement.dataset.parts) + parseInt(el.dataset.amount)
|
||||
).toString();
|
||||
} else {
|
||||
el.parentElement.dataset.parts = el.dataset.amount;
|
||||
}
|
||||
});
|
||||
|
||||
const setPartSize = function (labels, ml) {
|
||||
labels.forEach((el) => {
|
||||
const part = el.parentElement.dataset.amount;
|
||||
const total = el.parentElement.parentElement.dataset.parts;
|
||||
const amt = Math.ceil(ml * (part / total));
|
||||
el.innerHTML = `${amt} ml`;
|
||||
// Lookup tooltips
|
||||
let next = el.parentElement.nextElementSibling;
|
||||
while (next) {
|
||||
if (next.classList.contains("tooltip")) {
|
||||
let sublabels = [];
|
||||
next.querySelector(".tooltiptext").childNodes.forEach((ch) => {
|
||||
if (ch.classList && ch.classList.contains("bgus_part")) {
|
||||
sublabels.push(ch.querySelector(".bgus_part_label"));
|
||||
}
|
||||
});
|
||||
setPartSize(sublabels, amt);
|
||||
}
|
||||
if (next.classList.contains("bgus_part")) {
|
||||
// Done searching
|
||||
break;
|
||||
}
|
||||
next = next.nextElementSibling;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Init fuzzy search with elements
|
||||
const el = Array.from(
|
||||
root.querySelectorAll(
|
||||
"table.wikitable > tbody > tr:not(:first-child) > th"
|
||||
)
|
||||
);
|
||||
const name = el.map((elem) => {
|
||||
let name = "";
|
||||
elem.childNodes.forEach((t) => {
|
||||
if (t instanceof Text) {
|
||||
name += t.textContent;
|
||||
}
|
||||
});
|
||||
return name.trim();
|
||||
});
|
||||
searchBox(
|
||||
el,
|
||||
name.map((e, i) => ({ id: i, str: e }))
|
||||
);
|
||||
|
||||
document.body.addEventListener("keydown", function (ev) {
|
||||
if (ev.shiftKey) {
|
||||
switch (ev.keyCode) {
|
||||
// SHIFT+C = Toggle checkboxes
|
||||
case 67: {
|
||||
root.classList.toggle("bgus_cbox");
|
||||
root
|
||||
.querySelectorAll(".bgus_checkbox:checked")
|
||||
.forEach((el: HTMLInputElement) => {
|
||||
el.checked = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// SHIFT+B = Set whole size (beaker?) for parts/units
|
||||
case 66: {
|
||||
let size = parseInt(prompt("Write target ml (0 to reset)", "90"));
|
||||
if (isNaN(size) || size <= 0) {
|
||||
// Reset to parts/unit
|
||||
root
|
||||
.querySelectorAll(".bgus_part_label")
|
||||
.forEach((el: HTMLElement) => (el.innerHTML = el.dataset.src));
|
||||
return;
|
||||
}
|
||||
setPartSize(
|
||||
root.querySelectorAll("td > .bgus_part > .bgus_part_label"),
|
||||
+size
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function betterGeneric() {
|
||||
const el = Array.from(
|
||||
root.querySelectorAll("div.mw-headline-cont[id][data-name]")
|
||||
);
|
||||
const name = el.map((elem: HTMLDivElement) => elem.dataset.name.trim());
|
||||
|
||||
// Init fuzzy search with headlines
|
||||
searchBox(
|
||||
el,
|
||||
name.map((e, i) => ({ id: i, str: e })),
|
||||
{ alignment: "start" }
|
||||
);
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
switch (docname) {
|
||||
case "Guide_to_chemistry":
|
||||
betterChemistry();
|
||||
break;
|
||||
default:
|
||||
betterGeneric();
|
||||
break;
|
||||
}
|
||||
// Everything is loaded, remove loading bar
|
||||
statusMessage.innerHTML = "";
|
||||
});
|
||||
}
|
|
@ -6,10 +6,31 @@ body {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bgimage {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 0;
|
||||
img {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
$nanotrasen: #384e68;
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
background: linear-gradient(to bottom, hsl(24, 40%, 16%), hsl(44, 63%, 33%));
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
darken($nanotrasen, 20%),
|
||||
darken($nanotrasen, 10%)
|
||||
);
|
||||
background-size: 100% 100%;
|
||||
background-attachment: fixed;
|
||||
color: #fff;
|
||||
|
@ -23,6 +44,7 @@ body {
|
|||
grid-row: 2;
|
||||
padding: 10pt;
|
||||
overflow-y: scroll;
|
||||
z-index: 1;
|
||||
.page {
|
||||
a[href] {
|
||||
color: white;
|
||||
|
@ -33,8 +55,9 @@ body {
|
|||
h3 {
|
||||
position: sticky;
|
||||
top: -10pt;
|
||||
background: hsl(43, 64%, 32%);
|
||||
background: $nanotrasen;
|
||||
padding: 5px 10px;
|
||||
z-index: 999;
|
||||
}
|
||||
#toctitle h2 {
|
||||
margin: 0;
|
||||
|
|
Reference in a new issue