Tabs and loadings
This commit is contained in:
parent
9ab5c6816b
commit
33affe9b8b
6 changed files with 195 additions and 35 deletions
56
assets/images/speen.svg
Normal file
56
assets/images/speen.svg
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg
|
||||
width="100vmin"
|
||||
height="100vmin
|
||||
"
|
||||
viewBox="0 0 340 340"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:space="preserve"
|
||||
xmlns:serif="http://www.serif.com/"
|
||||
style="
|
||||
fill-rule: evenodd;
|
||||
clip-rule: evenodd;
|
||||
stroke-linejoin: round;
|
||||
stroke-miterlimit: 2;
|
||||
"
|
||||
>
|
||||
<style>
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
#circleboi {
|
||||
transform-origin: 50% 50%;
|
||||
animation-name: rotate;
|
||||
animation-duration: 6s;
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
</style>
|
||||
<path
|
||||
id="text"
|
||||
d="M104.26,279.309L104.26,92.146L71.496,92.146L71.496,66.804L159.14,66.804L159.14,92.144L126.376,92.146L126.376,279.309M205.817,279.309C195.943,279.309 188.452,276.504 183.552,270.972C178.469,265.237 175.892,256.426 175.892,244.783L175.892,101.33C175.892,89.687 178.469,80.876 183.552,75.14C188.45,69.61 195.942,66.806 205.816,66.806L238.58,66.806C258.435,66.806 268.504,78.42 268.504,101.33L268.504,129.131L247.379,129.131L247.379,109.174C247.379,98.671 241.346,92.147 231.631,92.147L213.759,92.147C203.899,92.147 198.009,98.512 198.009,109.174L198.009,236.938C198.009,247.601 203.899,253.966 213.759,253.966L231.629,253.966C241.491,253.966 247.379,247.601 247.379,236.939L247.379,193.575L230.499,193.575L230.499,168.23L268.503,168.23L268.503,244.785C268.503,267.695 258.435,279.309 238.579,279.309L205.815,279.309L205.817,279.309Z"
|
||||
style="fill-rule: nonzero;" fill="#a4b4c596"
|
||||
/>
|
||||
<g mask="url(#textmask)" fill="#a4b4c596">
|
||||
<path
|
||||
id="circleboi"
|
||||
d="M52.637,76.985L18.344,100.266L21.88,141.563L2.335,178.114L24.655,213.037L24.334,254.481L60.327,275.033L79.305,311.88L120.727,313.353L154.653,337.161L192.017,319.211L233.12,324.528L257.861,291.272L296.727,276.871L303.177,235.932L330.903,205.122L317.587,165.871L327.817,125.706L297.788,97.137L288.18,56.819L248.314,45.477L221.07,14.243L180.501,22.728L141.862,7.731L109.881,34.098L68.701,38.776L52.636,76.985L52.637,76.985ZM216.761,280.742L233.774,257.052L261.937,246.736L266.17,217.095L286.412,194.913L276.395,166.806L284.078,137.84L262.106,117.706L255.471,88.592L226.577,81.044L207.143,58.451L177.947,65.218L150.167,54.321L127.357,73.853L97.594,77.15L86.396,104.972L61.469,121.707L64.448,151.446L50.067,177.785L66.541,202.627L66.007,232.209L78.356,239.26L92.195,246.791L105.376,272.936L118.069,273.388L118.261,273.589L135.534,273.821L159.847,291.067L186.628,277.524L216.245,281.435L216.761,280.742Z"
|
||||
/>
|
||||
</g>
|
||||
<mask id="textmask">
|
||||
<rect x="0" y="0" width="340" height="340" style="fill: white;" />
|
||||
<path
|
||||
d="M274.325,244.784C274.325,271.12 261.665,285.129 238.581,285.129L205.817,285.129C197.487,285.129 190.939,282.647 185.081,279.839C170.502,272.852 169.064,241.181 169.064,241.181L132.196,241.181L132.196,280.645C132.196,283.725 130.956,285.127 128.224,285.127L102.413,285.127C99.931,285.127 98.441,283.727 98.441,280.645L98.441,249.868L98.131,249.373L98.655,97.966L69.646,97.966C67.164,97.966 65.674,96.284 65.674,93.483L65.674,65.464C65.674,62.664 67.164,60.984 69.647,60.984L131.251,60.984L158.546,60.923C163.315,60.54 164.919,62.86 164.619,66.804L164.619,91.422L170.619,91.422C172.787,71.547 185.831,60.108 208.749,60.983L238.581,60.983C261.666,60.983 274.325,74.991 274.325,101.328L274.325,118.878L274.326,202.76L274.326,244.782L274.325,244.784Z"
|
||||
style="fill-rule: nonzero;"
|
||||
fill="black"
|
||||
/>
|
||||
</mask>
|
||||
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
16
lib/App.tsx
16
lib/App.tsx
|
@ -1,15 +1,21 @@
|
|||
import * as React from "react";
|
||||
import TabItem from "./components/TabItem";
|
||||
import WikiPage from "./components/WikiPage";
|
||||
import TabList, { TabListItem } from "./components/TabList";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function App() {
|
||||
const [tabs, setTabs] = useState<TabListItem[]>([
|
||||
{ page: "Guide_to_medicine" },
|
||||
// { page: "Guide_to_chemistry" },
|
||||
]);
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
return (
|
||||
<React.Fragment>
|
||||
<nav id="tablist">
|
||||
<TabItem name="test" />
|
||||
</nav>
|
||||
<TabList tabs={tabs} active={activeTab} />
|
||||
<section id="tabs">
|
||||
<WikiPage page="Guide_to_medicine" />
|
||||
{tabs.map((tab, i) => (
|
||||
<WikiPage page={tab.page} visible={activeTab == i} />
|
||||
))}
|
||||
</section>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import * as React from "react";
|
||||
|
||||
export default function TabItem({ name }) {
|
||||
return <p>{name}</p>;
|
||||
}
|
28
lib/components/TabList.tsx
Normal file
28
lib/components/TabList.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import * as React from "react";
|
||||
|
||||
export interface TabListItem {
|
||||
page: string;
|
||||
}
|
||||
|
||||
export interface TabListProps {
|
||||
tabs: TabListItem[];
|
||||
active: number;
|
||||
}
|
||||
|
||||
function TabItem({ name, active }) {
|
||||
return (
|
||||
<div className={active ? "tab active" : "tab"}>
|
||||
{name.replace(/_/gi, " ")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TabList({ tabs, active }: TabListProps) {
|
||||
return (
|
||||
<nav className="tab-list">
|
||||
{tabs.map((tab, i) => (
|
||||
<TabItem name={tab.page} active={i == active} />
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
}
|
|
@ -3,6 +3,7 @@ import { darken, ColorFmt, lighten } from "../darkmode";
|
|||
import * as React from "react";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import userscript from "../userscript";
|
||||
import speen from "~/assets/images/speen.svg";
|
||||
|
||||
function fixup(html: string): string {
|
||||
// Convert relative links to absolute
|
||||
|
@ -27,19 +28,12 @@ function fixup(html: string): string {
|
|||
td.setAttribute("bgcolor", darken(bgcolor, ColorFmt.HEX).slice(1));
|
||||
});
|
||||
node.querySelectorAll("*[style]").forEach((td: HTMLElement) => {
|
||||
const inlineCSS = td.getAttribute("style");
|
||||
let bgcolor = null;
|
||||
if (inlineCSS.includes("background-color:")) {
|
||||
bgcolor = td.style.backgroundColor;
|
||||
} else if (inlineCSS.includes("background:")) {
|
||||
bgcolor = td.style.background;
|
||||
} else {
|
||||
return;
|
||||
if (td.style.backgroundColor != "") {
|
||||
td.style.backgroundColor = darken(td.style.backgroundColor, ColorFmt.RGB);
|
||||
}
|
||||
if (td.style.background != "") {
|
||||
td.style.backgroundColor = darken(td.style.background, ColorFmt.RGB);
|
||||
}
|
||||
td.setAttribute(
|
||||
"style",
|
||||
inlineCSS + ";background-color:" + darken(bgcolor, ColorFmt.RGB)
|
||||
);
|
||||
});
|
||||
|
||||
// Lighten fgcolors
|
||||
|
@ -53,13 +47,13 @@ function fixup(html: string): string {
|
|||
|
||||
// Remove fixed widths
|
||||
node.querySelectorAll("table[width]").forEach((td) => {
|
||||
const width = td.getAttribute("width");
|
||||
if (width.includes("%")) {
|
||||
// Leave it alone
|
||||
return;
|
||||
}
|
||||
td.setAttribute("width", "100%");
|
||||
});
|
||||
node.querySelectorAll("table[style]").forEach((td: HTMLTableElement) => {
|
||||
if (td.style.width != "") {
|
||||
td.style.width = "100%";
|
||||
}
|
||||
});
|
||||
|
||||
// Group headers and content so stickies don't overlap
|
||||
node.querySelectorAll("h3,h2").forEach((h3) => {
|
||||
|
@ -92,7 +86,7 @@ function fixup(html: string): string {
|
|||
return node.innerHTML;
|
||||
}
|
||||
|
||||
export default function WikiPage({ page }) {
|
||||
export default function WikiPage({ page, visible }) {
|
||||
const [data, setData] = useState({ loaded: false, html: "" });
|
||||
const containerRef = useRef(null);
|
||||
|
||||
|
@ -108,18 +102,33 @@ export default function WikiPage({ page }) {
|
|||
// 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>;
|
||||
return (
|
||||
<div className="page waiting">
|
||||
<p
|
||||
style={{
|
||||
display: visible ? "block" : "none",
|
||||
}}
|
||||
>
|
||||
You start skimming through the manual...
|
||||
</p>
|
||||
<div className="speen">
|
||||
<img src={speen} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="page"
|
||||
style={{
|
||||
display: visible ? "block" : "none",
|
||||
}}
|
||||
dangerouslySetInnerHTML={{ __html: data.html }}
|
||||
></div>
|
||||
);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
$nanotrasen: #384e68;
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
|
@ -21,8 +23,6 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
$nanotrasen: #384e68;
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
|
@ -40,12 +40,62 @@ $nanotrasen: #384e68;
|
|||
grid-template-rows: 40px 1fr;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 14pt;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
darken($nanotrasen, 0%),
|
||||
darken($nanotrasen, 10%),
|
||||
darken($nanotrasen, 0%)
|
||||
);
|
||||
border: 1px solid lighten($nanotrasen, 10%);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
lighten($nanotrasen, 20%),
|
||||
lighten($nanotrasen, 30%),
|
||||
lighten($nanotrasen, 20%)
|
||||
);
|
||||
border: 1px solid lighten($nanotrasen, 10%);
|
||||
}
|
||||
|
||||
#tabs {
|
||||
grid-row: 2;
|
||||
padding: 10pt;
|
||||
overflow-y: scroll;
|
||||
z-index: 1;
|
||||
padding-top: 10pt;
|
||||
.page {
|
||||
&.waiting {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.speen {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
img {
|
||||
flex: 1;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
padding-left: 10pt;
|
||||
padding-right: 10pt;
|
||||
}
|
||||
a[href] {
|
||||
color: white;
|
||||
}
|
||||
|
@ -56,7 +106,7 @@ $nanotrasen: #384e68;
|
|||
position: sticky;
|
||||
top: -10pt;
|
||||
background: $nanotrasen;
|
||||
padding: 5px 10px;
|
||||
padding: 10px;
|
||||
z-index: 999;
|
||||
}
|
||||
#toctitle h2 {
|
||||
|
@ -69,6 +119,22 @@ $nanotrasen: #384e68;
|
|||
}
|
||||
}
|
||||
|
||||
#tablist {
|
||||
$tab-active: lighten($nanotrasen, 10%);
|
||||
|
||||
.tab-list {
|
||||
grid-row: 1;
|
||||
display: flex;
|
||||
border-bottom: 2px solid $tab-active;
|
||||
|
||||
.tab {
|
||||
max-width: 200px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.active {
|
||||
background-color: $tab-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue