Compare commits

...
This repository has been archived on 2022-05-10. You can view files and clone it, but cannot push or open issues or pull requests.

13 Commits

Author SHA1 Message Date
Hamcha fb2b5cfa52
Moved to github! 2022-05-10 16:48:02 +02:00
Hamcha ab43ea0cdc
Only build once
continuous-integration/drone/push Build is passing Details
2022-05-10 16:38:16 +02:00
Hamcha 5d1a248134
Update drone [CI SKIP] 2022-05-10 16:36:47 +02:00
Hamcha 1e8b3d6bf7
Fix build commands
continuous-integration/drone/push Build is failing Details
2022-05-10 16:36:08 +02:00
Hamcha 5558ca679c
fix build command for non-root
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2022-05-10 16:28:44 +02:00
Hamcha a8cce4cd05
Fix build issues
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-05-10 16:04:31 +02:00
Hamcha 8b3fedf555
README changes
continuous-integration/drone/push Build is failing Details
continuous-integration/drone/pr Build is failing Details
2022-05-10 15:54:37 +02:00
Hamcha 74d8eb90eb
Update drone 2022-05-10 12:41:36 +02:00
Hamcha 2ce3df0332
Fix lint issues
continuous-integration/drone Build is passing Details
2022-05-10 12:37:34 +02:00
Hamcha db35e9640f
Use Vite
continuous-integration/drone Build is failing Details
2022-05-10 12:27:27 +02:00
Hamcha c9293c59e1
Fix linting issue
continuous-integration/drone/push Build is passing Details
2021-11-17 17:19:15 +01:00
Hamcha e49a3b43fd
Revert "Replace CI badge"
continuous-integration/drone/push Build is failing Details
This reverts commit df651c1f89.
2021-11-17 17:06:05 +01:00
D 1334c96aaa Update processing and add try-catch per page 2021-11-17 16:27:38 +01:00
25 changed files with 10193 additions and 7044 deletions

View File

@ -1,148 +0,0 @@
---
kind: pipeline
name: default
steps:
- name: restore-cache
image: drillster/drone-volume-cache
volumes:
- name: cache
path: /cache
settings:
restore: true
mount:
- ./node_modules
- name: dependencies
image: node
failure: ignore
commands:
- yarn
depends_on:
- restore-cache
- name: lint
image: node
commands:
- yarn lint
depends_on:
- dependencies
- name: build_versioned
image: node
commands:
- yarn build
environment:
SUBPATH: /tghandbook/${DRONE_COMMIT_BRANCH/\//_}-${DRONE_COMMIT_SHA:0:8}
REVISION: ${DRONE_COMMIT_SHA}
when:
event:
- push
depends_on:
- dependencies
- name: build_pr
image: node
commands:
- yarn build
environment:
SUBPATH: /tghandbook/pr-${DRONE_PULL_REQUEST}
OUTDIR: ./dist-pr
REVISION: ${DRONE_COMMIT_SHA}
when:
event:
- pull_request
depends_on:
- dependencies
- name: build_branch
image: node
commands:
- yarn build
environment:
SUBPATH: /tghandbook/${DRONE_COMMIT_BRANCH/\//_}
OUTDIR: ./dist-branch
REVISION: ${DRONE_COMMIT_SHA}
when:
event:
- push
depends_on:
- dependencies
- name: upload_build_versioned
image: plugins/s3
settings:
bucket: tghandbook
access_key:
from_secret: minio_access
secret_key:
from_secret: minio_secret
source: dist/**/*
target: /${DRONE_COMMIT_BRANCH/\//_}-${DRONE_COMMIT_SHA:0:8}/
strip_prefix: dist/
path_style: true
endpoint: https://artifacts.fromouter.space
when:
event:
- push
depends_on:
- build_versioned
- name: upload_build_pr
image: plugins/s3
settings:
bucket: tghandbook
access_key:
from_secret: minio_access
secret_key:
from_secret: minio_secret
source: dist-pr/**/*
target: /pr-${DRONE_PULL_REQUEST}/
strip_prefix: dist-pr/
path_style: true
endpoint: https://artifacts.fromouter.space
when:
event:
- pull_request
depends_on:
- build_pr
- name: upload_build_branch
image: plugins/s3
settings:
bucket: tghandbook
access_key:
from_secret: minio_access
secret_key:
from_secret: minio_secret
source: dist-branch/**/*
target: /${DRONE_COMMIT_BRANCH/\//_}/
strip_prefix: dist-branch/
path_style: true
endpoint: https://artifacts.fromouter.space
when:
event:
- push
depends_on:
- build_branch
- name: rebuild-cache
image: drillster/drone-volume-cache
failure: ignore
volumes:
- name: cache
path: /cache
settings:
rebuild: true
mount:
- ./node_modules
depends_on:
- dependencies
volumes:
- name: cache
host:
path: /opt/gitea/drone-cache/hamcha/tghandbook
---
kind: signature
hmac: 55dfd5c47c79e51394c5cdfaa9b98a6f6acd84e751e92964c202ac19b46c0373

View File

@ -19,7 +19,9 @@ module.exports = {
"no-param-reassign": "off", "no-param-reassign": "off",
"no-alert": "off", "no-alert": "off",
"no-console": "off", "no-console": "off",
"no-shadow": "off",
"func-names": "off", "func-names": "off",
"default-param-last": "off",
"dot-notation": ["error", { allowPattern: "^[A-Z][a-z]+$" }], "dot-notation": ["error", { allowPattern: "^[A-Z][a-z]+$" }],
"@typescript-eslint/ban-ts-comment": [ "@typescript-eslint/ban-ts-comment": [
"error", "error",
@ -27,5 +29,7 @@ module.exports = {
"ts-expect-error": "allow-with-description", "ts-expect-error": "allow-with-description",
}, },
], ],
"@typescript-eslint/no-shadow": ["error"],
"@typescript-eslint/default-param-last": ["error"],
}, },
}; };

32
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Publish on GitHub Pages
on:
push:
branches:
- master
pull_request:
jobs:
deploy:
runs-on: ubuntu-20.04
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- run: npm lint
- run: npm run build --if-present
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: ${{ github.ref == 'refs/heads/main' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
node_modules node_modules
dist dist
.cache .cache
yarn-error.log .parcel-cache
yarn-error.log
*.ts.js

24
LICENSE
View File

@ -1,23 +1,5 @@
This code is license under ISC, full copy below: Copyright 2020, Alessandro Gatti
Copyright 2020, Alessandro Gatti Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
This code uses idb-keyval, licensed under Apache 2:
Copyright 2016, Jake Archibald
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,11 +1,15 @@
# /tg/ handbook # /tg/station handbook
[![Build Status](https://ci.fromouter.space/api/badges/Hamcha/tghandbook/status.svg)](https://ci.fromouter.space/Hamcha/tghandbook) A fancier way to browse the /tg/ wiki. This handbook is a single page application that downloads 20+ pages from the /tg/station wiki (currently using a CORS proxy), adds some fancy filtering and Nanotrasen styling.
## Building It adapts the pages layout to be narrow as it's meant to be used in a small window, much like a PDA or an in-game book.
`yarn build`
## Development ## Development
`yarn dev` Start hot-reloading server with `npm start`
Build with `npm run build`
## License
The project is licensed under ISC (SPDX identifier). Please see the LICENSE file for details.

View File

@ -1,24 +0,0 @@
/* eslint-disable */
const Bundler = require("parcel-bundler");
const Path = require("path");
const entryFiles = Path.join(__dirname, "./index.html");
// Bundler options
const options = {
outDir: process.env.OUTDIR || "./dist",
outFile: "index.html",
publicUrl: process.env.SUBPATH || "/",
watch: false,
contentHash: false,
scopeHoist: false,
target: "browser",
logLevel: 3, // 5 = save everything to a file, 4 = like 3, but with timestamps and additionally log http requests to dev server, 3 = log info, warnings & errors, 2 = log warnings & errors, 1 = log errors, 0 = log nothing
sourceMaps: true, // Enable or disable sourcemaps, defaults to enabled (minified builds currently always create sourcemaps)
autoInstall: true, // Enable or disable auto install of missing dependencies found during bundling
};
(async () => {
const bundler = new Bundler(entryFiles, options);
await bundler.bundle();
})();

10
env.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_SUBDIR: string;
readonly VITE_APP_REVISION: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

View File

@ -14,31 +14,31 @@
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
href="assets/images/icons-manifest/icon152.png" href="./assets/images/icons-manifest/icon152.png"
/> />
<link rel="manifest" href="manifest.webmanifest" /> <link rel="manifest" href="./manifest.webmanifest" />
<link rel="icon" href="favicon.ico" type="image/x-icon" /> <link rel="icon" href="./favicon.ico" type="image/x-icon" />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="32x32" sizes="32x32"
href="assets/images/icons-manifest/icon32.png" href="./assets/images/icons-manifest/icon32.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="16x16" sizes="16x16"
href="assets/images/icons-manifest/icon16.png" href="./assets/images/icons-manifest/icon16.png"
/> />
<link <link
rel="preload" rel="preload"
href="assets/fonts/iosevka/iosevka-aile.css" href="./assets/fonts/iosevka/iosevka-aile.css"
as="style" as="style"
/> />
<link rel="preload" href="style/main.scss" as="style" /> <link rel="preload" href="./style/main.scss" as="style" />
<link rel="preload" href="src/index.ts" as="script" /> <link rel="preload" href="./src/index.ts" as="script" />
<link rel="stylesheet" href="assets/fonts/iosevka/iosevka-aile.css" /> <link rel="stylesheet" href="./assets/fonts/iosevka/iosevka-aile.css" />
<link rel="stylesheet" href="style/main.scss" /> <link rel="stylesheet" href="./style/main.scss" />
<title>/tg/station Handbook</title> <title>/tg/station Handbook</title>
</head> </head>
<body> <body>
@ -52,8 +52,8 @@
<div class="page special center" id="Welcome" data-tab="$Welcome"> <div class="page special center" id="Welcome" data-tab="$Welcome">
<div class="wrapper"> <div class="wrapper">
<header> <header>
<img class="icon" src="assets/images/outline.svg" /> <img class="icon" src="./assets/images/outline.svg" />
<img class="type" src="assets/images/type.svg" /> <img class="type" src="./assets/images/type.svg" />
</header> </header>
<div class="maxw"> <div class="maxw">
<p> <p>
@ -79,9 +79,7 @@
<div class="action_buttons"></div> <div class="action_buttons"></div>
</div> </div>
<div class="features hidden" data-name="Extra features"> <div class="features hidden" data-name="Extra features">
<h2> <h2>Extra Features</h2>
Extra Features
</h2>
<div class="maxw"> <div class="maxw">
<h3 class="nobg">Jump to section/item</h3> <h3 class="nobg">Jump to section/item</h3>
<p> <p>
@ -94,12 +92,12 @@
</p> </p>
<div class="images"> <div class="images">
<img <img
src="assets/images/welcome/bs-local.png" src="./assets/images/welcome/bs-local.png"
style="width: 40%;" style="width: 40%"
/> />
<img <img
src="assets/images/welcome/bs-global.png" src="./assets/images/welcome/bs-global.png"
style="width: 40%;" style="width: 40%"
/> />
</div> </div>
<p> <p>
@ -122,17 +120,15 @@
</div> </div>
</div> </div>
<div class="credits hidden" data-name="Other infos"> <div class="credits hidden" data-name="Other infos">
<h2> <h2>Other Informations</h2>
Other Informations
</h2>
<p> <p>
Thanks to /tg/station and every wiki contributor who did most of Thanks to /tg/station and every wiki contributor who did most of
the work! the work!
</p> </p>
<p> <p>
This thing is Open Source: This thing is Open Source:
<a href="https://git.fromouter.space/hamcha/tghandbook" <a href="https://github.com/Hamcha/tghandbook"
>git.fromouter.space/hamcha/tghandbook</a >github.com/Hamcha/tghandbook</a
> >
</p> </p>
<p> <p>
@ -144,9 +140,13 @@
</section> </section>
</main> </main>
<noscript> <noscript>
<h1>NO JS NO PARTY</h1> <h1>JavaScript is required for this tool</h1>
<h2>JavaScript support is required to run this app.</h2> <h2>
This tools runs completely in your browser, therefore it needs
JavaScript to download all the pages, parse them and add all the spicy
extras.
</h2>
</noscript> </noscript>
<script src="src/index.ts" async></script> <script src="./src/index.ts" async type="module"></script>
</body> </body>
</html> </html>

9934
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,27 +3,28 @@
"version": "1.0.0", "version": "1.0.0",
"main": "index.js", "main": "index.js",
"license": "ISC", "license": "ISC",
"type": "module",
"scripts": { "scripts": {
"dev": "parcel index.html", "start": "vite",
"lint": "eslint src", "lint": "eslint src",
"build": "node ./build.js" "build": "vite build --base=./"
}, },
"dependencies": { "dependencies": {
"@types/node": "^14.0.13", "@types/node": "^17.0.31",
"@types/service_worker_api": "^0.0.9", "@types/service_worker_api": "^0.0.9",
"@typescript-eslint/eslint-plugin": "^3.3.0", "@typescript-eslint/eslint-plugin": "^5.23.0",
"@typescript-eslint/parser": "^3.3.0", "@typescript-eslint/parser": "^5.23.0",
"eslint": "7.2.0", "eslint": "8.15.0",
"eslint-config-airbnb-base": "^14.2.0", "eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^6.11.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "2.21.2", "eslint-plugin-import": "2.26.0",
"eslint-plugin-prettier": "^3.1.4", "eslint-plugin-prettier": "^4.0.0",
"idb-keyval": "^3.2.0", "idb-keyval": "^6.1.0",
"parcel-bundler": "^1.12.4", "prettier": "^2.6.2",
"parcel-plugin-sw-cache": "^0.3.1", "sass": "^1.51.0",
"prettier": "^2.0.5", "typescript": "^4.6.4",
"sass": "^1.26.8", "vite": "^2.9.8",
"typescript": "^3.9.5" "vite-plugin-pwa": "^0.12.0"
}, },
"browserslist": [ "browserslist": [
"last 2 Chrome versions", "last 2 Chrome versions",

View File

@ -8,6 +8,7 @@ interface CacheEntry<T> {
export class Store { export class Store {
readonly dbp: Promise<IDBDatabase>; readonly dbp: Promise<IDBDatabase>;
// eslint-disable-next-line default-param-last
constructor(dbName = "tg-cache", readonly storeName = "keyval") { constructor(dbName = "tg-cache", readonly storeName = "keyval") {
this.dbp = new Promise((resolve, reject) => { this.dbp = new Promise((resolve, reject) => {
const openreq = indexedDB.open(dbName, 1); const openreq = indexedDB.open(dbName, 1);
@ -51,8 +52,8 @@ export function get<Type>(
): Promise<CacheEntry<Type>> { ): Promise<CacheEntry<Type>> {
let req: IDBRequest; let req: IDBRequest;
return store return store
.withIDBStore("readonly", (store) => { .withIDBStore("readonly", (idbstore) => {
req = store.get(key); req = idbstore.get(key);
}) })
.then(() => req.result); .then(() => req.result);
} }
@ -63,8 +64,8 @@ export function set<Type>(
version: string, version: string,
store = getDefaultStore() store = getDefaultStore()
): Promise<void> { ): Promise<void> {
return store.withIDBStore("readwrite", (store) => { return store.withIDBStore("readwrite", (idbstore) => {
store.put({ version, value }, key); idbstore.put({ version, value }, key);
}); });
} }
@ -72,14 +73,14 @@ export function del(
key: IDBValidKey, key: IDBValidKey,
store = getDefaultStore() store = getDefaultStore()
): Promise<void> { ): Promise<void> {
return store.withIDBStore("readwrite", (store) => { return store.withIDBStore("readwrite", (idbstore) => {
store.delete(key); idbstore.delete(key);
}); });
} }
export function clear(store = getDefaultStore()): Promise<void> { export function clear(store = getDefaultStore()): Promise<void> {
return store.withIDBStore("readwrite", (store) => { return store.withIDBStore("readwrite", (idbstore) => {
store.clear(); idbstore.clear();
}); });
} }
@ -87,16 +88,15 @@ export function keys(store = getDefaultStore()): Promise<IDBValidKey[]> {
const dbkeys: IDBValidKey[] = []; const dbkeys: IDBValidKey[] = [];
return store return store
.withIDBStore("readonly", (store) => { .withIDBStore("readonly", (idbstore) => {
// This would be store.getAllKeys(), but it isn't supported by Edge or Safari. // This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
// And openKeyCursor isn't supported by Safari. // And openKeyCursor isn't supported by Safari.
(store.openKeyCursor || store.openCursor).call( (idbstore.openKeyCursor || idbstore.openCursor).call(idbstore).onsuccess =
store function () {
).onsuccess = function () { if (!this.result) return;
if (!this.result) return; dbkeys.push(this.result.key);
dbkeys.push(this.result.key); this.result.continue();
this.result.continue(); };
};
}) })
.then(() => dbkeys); .then(() => dbkeys);
} }

View File

@ -3,8 +3,7 @@ import sections from "./ui/sections";
import { nextAnimationFrame } from "./utils"; import { nextAnimationFrame } from "./utils";
import { searchBox } from "./scripts/search"; import { searchBox } from "./scripts/search";
// @ts-expect-error: Parcel image import import unknown from "@/assets/images/tab-icons/unknown.svg";
import unknown from "~/assets/images/tab-icons/unknown.svg";
import { bindFunctions } from "./scripts/index"; import { bindFunctions } from "./scripts/index";
// Enable single page mode for developing scripts // Enable single page mode for developing scripts
@ -74,7 +73,9 @@ async function load() {
}); });
} }
if ("serviceWorker" in navigator) { if ("serviceWorker" in navigator) {
const x = process.env.SUBPATH ? `${process.env.SUBPATH}/sw.js` : "sw.js"; const x = import.meta.env.VITE_SUBDIR
? `${import.meta.env.VITE_SUBDIR}/sw.js`
: "sw.js";
navigator.serviceWorker navigator.serviceWorker
.register(x) .register(x)
.then((registration) => { .then((registration) => {
@ -94,4 +95,6 @@ document.body.appendChild(searchBox());
// Add revision info // Add revision info
document document
.getElementById("tgh-version") .getElementById("tgh-version")
.appendChild(document.createTextNode(process.env.REVISION || "unknown")); .appendChild(
document.createTextNode(import.meta.env.VITE_APP_REVISION || "unknown")
);

View File

@ -18,22 +18,30 @@ export const PAGE_VERSIONS = {
const MAX_WIDTH = 440; const MAX_WIDTH = 440;
export function processHTML(root: HTMLElement, docname: string): void { export function processHTML(root: HTMLElement, docname: string): void {
processGlobal(root, docname); try {
processGlobal(root, docname);
} catch (e) {
console.error(`Error processing page: ${docname}`);
}
switch (docname) { try {
case "Guide_to_chemistry": switch (docname) {
processChemistry(root); case "Guide_to_chemistry":
break; processChemistry(root);
case "Infections": break;
processVirology(root); case "Infections":
break; processVirology(root);
case "Guide_to_food": break;
processFood(root); case "Guide_to_food":
break; processFood(root);
case "Guide_to_drinks": break;
processDrinks(root); case "Guide_to_drinks":
break; processDrinks(root);
default: break;
default:
}
} catch (e) {
console.error(`Error processing page: ${docname} (specific enhancements)`);
} }
} }

View File

@ -204,12 +204,13 @@ export function chemistryScript(root: HTMLElement): void {
); );
registerSearchEntries( registerSearchEntries(
el.map((element, id) => ({ Array.from(
root.querySelectorAll<HTMLElement>(
"table.wikitable > tbody > tr:not(:first-child) th .reagent-header"
)
).map((element, id) => ({
page: "Guide_to_chemistry", page: "Guide_to_chemistry",
name: element name: element.textContent.trim().replace(/\n.+$/gm, "").replace("▮", ""),
.querySelector("th .reagent-header")
.textContent.trim()
.replace("▮", ""),
element, element,
alignment: "center", alignment: "center",
id, id,

View File

@ -41,6 +41,7 @@ export function processFood(root: HTMLElement): void {
]; ];
baseFoodTables.forEach(({ selector, title, process }) => { baseFoodTables.forEach(({ selector, title, process }) => {
const table = root.querySelector<HTMLElement>(`${selector} .wikitable`); const table = root.querySelector<HTMLElement>(`${selector} .wikitable`);
if (!table) return;
const foods = parseTable(table).map((row) => { const foods = parseTable(table).map((row) => {
const foodBlock = document.createElement("td"); const foodBlock = document.createElement("td");
foodBlock.innerHTML = `<div class="food-block"> foodBlock.innerHTML = `<div class="food-block">
@ -108,6 +109,7 @@ export function processFood(root: HTMLElement): void {
]; ];
foodRecipesTables.forEach((selector) => { foodRecipesTables.forEach((selector) => {
const table = root.querySelector<HTMLElement>(`${selector} .wikitable`); const table = root.querySelector<HTMLElement>(`${selector} .wikitable`);
if (!table) return;
const recipes = parseTable(table).map((row) => { const recipes = parseTable(table).map((row) => {
const foodBlock = document.createElement("td"); const foodBlock = document.createElement("td");
foodBlock.innerHTML = ` foodBlock.innerHTML = `

View File

@ -2,7 +2,7 @@ import { registerSearchEntries } from "../search";
export function genericScript(root: HTMLElement, docname: string): void { export function genericScript(root: HTMLElement, docname: string): void {
const el = Array.from( const el = Array.from(
root.querySelectorAll<HTMLElement>("div.mw-headline-cont[id][data-name]") root.querySelectorAll<HTMLElement>(".mw-headline-cont[id][data-name]")
); );
// Init fuzzy search with headlines // Init fuzzy search with headlines

View File

@ -75,7 +75,10 @@ export function processGlobal(root: HTMLElement, docname: string): void {
if (toc) { if (toc) {
const tocHeader = toc.querySelector("h2"); const tocHeader = toc.querySelector("h2");
toc.parentNode.insertBefore(tocHeader, toc); toc.parentNode.insertBefore(tocHeader, toc);
toc.removeChild(toc.querySelector("#toctitle")); const tocTitle = toc.querySelector("#toctitle");
if (tocTitle != null) {
toc.removeChild(tocTitle);
}
} }
// Group headers and content so stickies don't overlap // Group headers and content so stickies don't overlap
@ -99,10 +102,16 @@ export function processGlobal(root: HTMLElement, docname: string): void {
const container = findParent(span, (el) => const container = findParent(span, (el) =>
el.classList.contains("mw-headline-cont") el.classList.contains("mw-headline-cont")
); );
if (container) { if (
container &&
container.querySelectorAll<HTMLElement>(".mw-headline").length === 1
) {
container.id = span.id; container.id = span.id;
span.id += "-span"; span.id += "-span";
container.dataset.name = span.textContent; container.dataset.name = span.textContent;
} else {
span.dataset.name = span.textContent;
span.classList.add("mw-headline-cont");
} }
}); });
} }

View File

@ -30,8 +30,8 @@ export function searchBox(): HTMLElement {
const jumpTo = (entry: SearchEntry) => { const jumpTo = (entry: SearchEntry) => {
// If page is different jump to that // If page is different jump to that
if (global) { if (global) {
const currentPage = document.querySelector<HTMLElement>(".page.active") const currentPage =
.dataset.tab; document.querySelector<HTMLElement>(".page.active").dataset.tab;
if (currentPage !== entry.page) { if (currentPage !== entry.page) {
TabManager.instance.setActive(entry.page); TabManager.instance.setActive(entry.page);
} }
@ -193,9 +193,8 @@ export function searchBox(): HTMLElement {
return; return;
default: default:
if (sel.value !== oldValue) { if (sel.value !== oldValue) {
const currentPage = document.querySelector<HTMLElement>( const currentPage =
".page.active" document.querySelector<HTMLElement>(".page.active");
);
search(sel.value, currentPage.dataset.tab); search(sel.value, currentPage.dataset.tab);
oldValue = sel.value; oldValue = sel.value;
} }

View File

@ -1,5 +1,4 @@
// @ts-expect-error: Asset imports are handled by parcel import speen from "@/assets/images/speen.svg";
import speen from "~/assets/images/speen.svg";
import { getPageHTML } from "../wiki"; import { getPageHTML } from "../wiki";
import { import {
processHTML, processHTML,
@ -10,8 +9,7 @@ import {
import cache from "../cache"; import cache from "../cache";
import { nextAnimationFrame, delay } from "../utils"; import { nextAnimationFrame, delay } from "../utils";
// @ts-expect-error: Parcel image import import unknown from "@/assets/images/tab-icons/unknown.svg";
import unknown from "~/assets/images/tab-icons/unknown.svg";
function initWaiting(elem: HTMLElement) { function initWaiting(elem: HTMLElement) {
// Add spinner // Add spinner
@ -187,9 +185,8 @@ export default class TabManager {
* @param name Section name * @param name Section name
*/ */
showSection(name: string): void { showSection(name: string): void {
const active = this.sectionListContainer.querySelector<HTMLElement>( const active =
".active" this.sectionListContainer.querySelector<HTMLElement>(".active");
);
if (active) { if (active) {
// De-activate current section // De-activate current section
active.classList.remove("active"); active.classList.remove("active");
@ -298,9 +295,8 @@ export default class TabManager {
.forEach((it) => it.classList.remove("active")); .forEach((it) => it.classList.remove("active"));
// If section is not shown, show it! // If section is not shown, show it!
const isSectionActive = this.sections[section].element.classList.contains( const isSectionActive =
"active" this.sections[section].element.classList.contains("active");
);
if (!isSectionActive) { if (!isSectionActive) {
this.showSection(section); this.showSection(section);
} }

View File

@ -1,107 +1,55 @@
// @ts-expect-error: Parcel image import import chemistry from "@/assets/images/tab-icons/chemistry.svg";
import chemistry from "~/assets/images/tab-icons/chemistry.svg"; import medicine from "@/assets/images/tab-icons/medicine.svg";
// @ts-expect-error: Parcel image import import plumbing from "@/assets/images/tab-icons/plumbing.svg";
import medicine from "~/assets/images/tab-icons/medicine.svg"; import grenade from "@/assets/images/tab-icons/grenade.svg";
// @ts-expect-error: Parcel image import import genetics from "@/assets/images/tab-icons/genetics.svg";
import plumbing from "~/assets/images/tab-icons/plumbing.svg"; import virus from "@/assets/images/tab-icons/virus.svg";
// @ts-expect-error: Parcel image import import surgery from "@/assets/images/tab-icons/surgery.svg";
import grenade from "~/assets/images/tab-icons/grenade.svg"; import trauma from "@/assets/images/tab-icons/trauma.svg";
// @ts-expect-error: Parcel image import import wound from "@/assets/images/tab-icons/wound.svg";
import genetics from "~/assets/images/tab-icons/genetics.svg"; import ghetto from "@/assets/images/tab-icons/ghetto.svg";
// @ts-expect-error: Parcel image import import construction from "@/assets/images/tab-icons/construction.svg";
import virus from "~/assets/images/tab-icons/virus.svg"; import machines from "@/assets/images/tab-icons/machines.svg";
// @ts-expect-error: Parcel image import import power from "@/assets/images/tab-icons/power.svg";
import surgery from "~/assets/images/tab-icons/surgery.svg"; import solar from "@/assets/images/tab-icons/solar.svg";
// @ts-expect-error: Parcel image import import supermatter from "@/assets/images/tab-icons/supermatter.svg";
import trauma from "~/assets/images/tab-icons/trauma.svg"; import shield from "@/assets/images/tab-icons/shield.svg";
// @ts-expect-error: Parcel image import import turbine from "@/assets/images/tab-icons/turbine.svg";
import wound from "~/assets/images/tab-icons/wound.svg"; import atmos from "@/assets/images/tab-icons/atmos.svg";
// @ts-expect-error: Parcel image import import tcomm from "@/assets/images/tab-icons/tcomm.svg";
import ghetto from "~/assets/images/tab-icons/ghetto.svg"; import rnd from "@/assets/images/tab-icons/rnd.svg";
// @ts-expect-error: Parcel image import import toxins from "@/assets/images/tab-icons/toxins.svg";
import construction from "~/assets/images/tab-icons/construction.svg"; import xeno from "@/assets/images/tab-icons/xeno.svg";
// @ts-expect-error: Parcel image import import nanites from "@/assets/images/tab-icons/nanites.svg";
import machines from "~/assets/images/tab-icons/machines.svg"; import rules from "@/assets/images/tab-icons/rules.svg";
// @ts-expect-error: Parcel image import import aimod from "@/assets/images/tab-icons/aimod.svg";
import power from "~/assets/images/tab-icons/power.svg"; import tips from "@/assets/images/tab-icons/tips.svg";
// @ts-expect-error: Parcel image import import critter from "@/assets/images/tab-icons/critter.svg";
import solar from "~/assets/images/tab-icons/solar.svg"; import races from "@/assets/images/tab-icons/races.svg";
// @ts-expect-error: Parcel image import import food from "@/assets/images/tab-icons/food.svg";
import supermatter from "~/assets/images/tab-icons/supermatter.svg"; import hydro from "@/assets/images/tab-icons/hydro.svg";
// @ts-expect-error: Parcel image import import song from "@/assets/images/tab-icons/song.svg";
import shield from "~/assets/images/tab-icons/shield.svg"; import crate from "@/assets/images/tab-icons/crate.svg";
// @ts-expect-error: Parcel image import import space from "@/assets/images/tab-icons/space.svg";
import turbine from "~/assets/images/tab-icons/turbine.svg"; import aux from "@/assets/images/tab-icons/auxbase.svg";
// @ts-expect-error: Parcel image import import robo from "@/assets/images/tab-icons/robo.svg";
import atmos from "~/assets/images/tab-icons/atmos.svg"; import security from "@/assets/images/tab-icons/security.svg";
// @ts-expect-error: Parcel image import import law from "@/assets/images/tab-icons/law.svg";
import tcomm from "~/assets/images/tab-icons/tcomm.svg"; import sop from "@/assets/images/tab-icons/sop.svg";
// @ts-expect-error: Parcel image import import trial from "@/assets/images/tab-icons/trial.svg";
import rnd from "~/assets/images/tab-icons/rnd.svg"; import traitor from "@/assets/images/tab-icons/traitor.svg";
// @ts-expect-error: Parcel image import import hacking from "@/assets/images/tab-icons/hacking.svg";
import toxins from "~/assets/images/tab-icons/toxins.svg"; import weapons from "@/assets/images/tab-icons/weapons.svg";
// @ts-expect-error: Parcel image import import uplink from "@/assets/images/tab-icons/uplink.svg";
import xeno from "~/assets/images/tab-icons/xeno.svg"; import rev from "@/assets/images/tab-icons/rev.svg";
// @ts-expect-error: Parcel image import import cult from "@/assets/images/tab-icons/cult.svg";
import nanites from "~/assets/images/tab-icons/nanites.svg"; import nuke from "@/assets/images/tab-icons/nuke.svg";
// @ts-expect-error: Parcel image import import malf from "@/assets/images/tab-icons/malf.svg";
import rules from "~/assets/images/tab-icons/rules.svg"; import combat from "@/assets/images/tab-icons/combat.svg";
// @ts-expect-error: Parcel image import import access from "@/assets/images/tab-icons/access.svg";
import aimod from "~/assets/images/tab-icons/aimod.svg"; import xmorph from "@/assets/images/tab-icons/xmorph.svg";
// @ts-expect-error: Parcel image import import abduction from "@/assets/images/tab-icons/abduction.svg";
import tips from "~/assets/images/tab-icons/tips.svg"; import mafia from "@/assets/images/tab-icons/mafia.svg";
// @ts-expect-error: Parcel image import
import critter from "~/assets/images/tab-icons/critter.svg";
// @ts-expect-error: Parcel image import
import races from "~/assets/images/tab-icons/races.svg";
// @ts-expect-error: Parcel image import
import food from "~/assets/images/tab-icons/food.svg";
// @ts-expect-error: Parcel image import
import hydro from "~/assets/images/tab-icons/hydro.svg";
// @ts-expect-error: Parcel image import
import song from "~/assets/images/tab-icons/song.svg";
// @ts-expect-error: Parcel image import
import crate from "~/assets/images/tab-icons/crate.svg";
// @ts-expect-error: Parcel image import
import space from "~/assets/images/tab-icons/space.svg";
// @ts-expect-error: Parcel image import
import aux from "~/assets/images/tab-icons/auxbase.svg";
// @ts-expect-error: Parcel image import
import robo from "~/assets/images/tab-icons/robo.svg";
// @ts-expect-error: Parcel image import
import security from "~/assets/images/tab-icons/security.svg";
// @ts-expect-error: Parcel image import
import law from "~/assets/images/tab-icons/law.svg";
// @ts-expect-error: Parcel image import
import sop from "~/assets/images/tab-icons/sop.svg";
// @ts-expect-error: Parcel image import
import trial from "~/assets/images/tab-icons/trial.svg";
// @ts-expect-error: Parcel image import
import traitor from "~/assets/images/tab-icons/traitor.svg";
// @ts-expect-error: Parcel image import
import hacking from "~/assets/images/tab-icons/hacking.svg";
// @ts-expect-error: Parcel image import
import weapons from "~/assets/images/tab-icons/weapons.svg";
// @ts-expect-error: Parcel image import
import uplink from "~/assets/images/tab-icons/uplink.svg";
// @ts-expect-error: Parcel image import
import rev from "~/assets/images/tab-icons/rev.svg";
// @ts-expect-error: Parcel image import
import cult from "~/assets/images/tab-icons/cult.svg";
// @ts-expect-error: Parcel image import
import nuke from "~/assets/images/tab-icons/nuke.svg";
// @ts-expect-error: Parcel image import
import malf from "~/assets/images/tab-icons/malf.svg";
// @ts-expect-error: Parcel image import
import combat from "~/assets/images/tab-icons/combat.svg";
// @ts-expect-error: Parcel image import
import access from "~/assets/images/tab-icons/access.svg";
// @ts-expect-error: Parcel image import
import xmorph from "~/assets/images/tab-icons/xmorph.svg";
// @ts-expect-error: Parcel image import
import abduction from "~/assets/images/tab-icons/abduction.svg";
// @ts-expect-error: Parcel image import
import mafia from "~/assets/images/tab-icons/mafia.svg";
export interface SectionInfo { export interface SectionInfo {
name: string; name: string;

View File

@ -1,5 +1,7 @@
export function nextAnimationFrame(): Promise<void> { export function nextAnimationFrame(): Promise<void> {
return new Promise((resolve) => requestAnimationFrame(() => resolve())); return new Promise((resolve) => {
requestAnimationFrame(() => resolve());
});
} }
export function delay(ms: number): Promise<void> { export function delay(ms: number): Promise<void> {

View File

@ -1,9 +1,11 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2020", "target": "es2020",
"module": "es2020",
"baseUrl": ".", "baseUrl": ".",
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"paths": { "paths": {
"@": ["."],
"~*": ["./src/*"] "~*": ["./src/*"]
} }
} }

19
vite.config.ts Normal file
View File

@ -0,0 +1,19 @@
import path from "path";
import { defineConfig } from "vite";
import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({
plugins: [
VitePWA({
devOptions: {
enabled: true,
},
}),
],
resolve: {
alias: {
"~": path.resolve(__dirname, "./src"),
"@": path.resolve(__dirname),
},
},
});

6637
yarn.lock

File diff suppressed because it is too large Load Diff