Simplified the frontend serving part of the backend

This commit is contained in:
Natty 2023-07-06 21:55:59 +02:00
parent 1975a21c80
commit d47566626a
Signed by: natty
GPG Key ID: BF6CB659ADEE60EC
10 changed files with 21 additions and 425 deletions

View File

@ -49,8 +49,6 @@ gulp.task("build:backend:script", () => {
return gulp return gulp
.src([ .src([
"./packages/backend/src/server/web/boot.js", "./packages/backend/src/server/web/boot.js",
"./packages/backend/src/server/web/bios.js",
"./packages/backend/src/server/web/cli.js",
]) ])
.pipe(replace("LANGS", JSON.stringify(Object.keys(locales)))) .pipe(replace("LANGS", JSON.stringify(Object.keys(locales))))
.pipe( .pipe(
@ -65,8 +63,6 @@ gulp.task("build:backend:style", () => {
return gulp return gulp
.src([ .src([
"./packages/backend/src/server/web/style.css", "./packages/backend/src/server/web/style.css",
"./packages/backend/src/server/web/bios.css",
"./packages/backend/src/server/web/cli.css",
]) ])
.pipe( .pipe(
cssnano({ cssnano({

View File

@ -1,89 +0,0 @@
"use strict";
window.onload = async () => {
const account = JSON.parse(localStorage.getItem("account"));
const i = account.token;
const api = (endpoint, data = {}) => {
const promise = new Promise((resolve, reject) => {
// Append a credential
if (i) data.i = i;
// Send request
fetch(endpoint.indexOf("://") > -1 ? endpoint : `/api/${endpoint}`, {
method: "POST",
body: JSON.stringify(data),
credentials: "omit",
cache: "no-cache",
})
.then(async (res) => {
const body = res.status === 204 ? null : await res.json();
if (res.status === 200) {
resolve(body);
} else if (res.status === 204) {
resolve();
} else {
reject(body.error);
}
})
.catch(reject);
});
return promise;
};
const content = document.getElementById("content");
document.getElementById("ls").addEventListener("click", () => {
content.innerHTML = "";
const lsEditor = document.createElement("div");
lsEditor.id = "lsEditor";
const adder = document.createElement("div");
adder.classList.add("adder");
const addKeyInput = document.createElement("input");
const addValueTextarea = document.createElement("textarea");
const addButton = document.createElement("button");
addButton.textContent = "Add";
addButton.addEventListener("click", () => {
localStorage.setItem(addKeyInput.value, addValueTextarea.value);
location.reload();
});
adder.appendChild(addKeyInput);
adder.appendChild(addValueTextarea);
adder.appendChild(addButton);
lsEditor.appendChild(adder);
for (let i = 0; i < localStorage.length; i++) {
const k = localStorage.key(i);
const record = document.createElement("div");
record.classList.add("record");
const header = document.createElement("header");
header.textContent = k;
const textarea = document.createElement("textarea");
textarea.textContent = localStorage.getItem(k);
const saveButton = document.createElement("button");
saveButton.textContent = "Save";
saveButton.addEventListener("click", () => {
localStorage.setItem(k, textarea.value);
location.reload();
});
const removeButton = document.createElement("button");
removeButton.textContent = "Remove";
removeButton.addEventListener("click", () => {
localStorage.removeItem(k);
location.reload();
});
record.appendChild(header);
record.appendChild(textarea);
record.appendChild(saveButton);
record.appendChild(removeButton);
lsEditor.appendChild(record);
}
content.appendChild(lsEditor);
});
};

View File

@ -144,25 +144,13 @@
</button> </button>
<p class="dont-worry">Don't worry, it's (probably) not your fault.</p> <p class="dont-worry">Don't worry, it's (probably) not your fault.</p>
<p>Please make sure your browser is up-to-date and any AdBlockers are off.</p> <p>Please make sure your browser is up-to-date and any AdBlockers are off.</p>
<p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try the following options:</p> <p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try:</p>
<a href="/flush"> <a href="/flush">
<button class="button-small"> <button class="button-small">
<span class="button-label-small">Clear preferences and cache</span> <span class="button-label-small">Clear preferences and cache</span>
</button> </button>
</a> </a>
<br> <br>
<a href="/cli">
<button class="button-small">
<span class="button-label-small">Start the simple client</span>
</button>
</a>
<br>
<a href="/bios">
<button class="button-small">
<span class="button-label-small">Start the repair tool</span>
</button>
</a>
<br>
<div id="errors"></div> <div id="errors"></div>
`; `;
errorsElement = document.getElementById("errors"); errorsElement = document.getElementById("errors");

View File

@ -1,92 +0,0 @@
html {
background: #191724;
}
main {
background: #1f1d2e;
border-radius: 10px;
}
#tl > div {
border: 1px solid #908caa;
border-radius: 10px;
margin: 10px;
padding: 10px;
width: fit-content;
}
#tl > div > header {
font-weight: 700;
display: inline-flex;
}
img {
border-radius: 10px;
margin-right: 10px;
}
#form {
text-align: center;
}
#calckey_app {
display: none !important;
}
body,
html {
font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
background-color: #191724;
color: #e0def4;
justify-content: center;
margin: auto;
padding: 10px;
}
button {
border-radius:999px;
padding:0 40px;
margin-top: 1rem;
border:none;
cursor:pointer;
margin-bottom:12px;
background:linear-gradient(90deg,#9ccfd8,#31748f);
line-height:50px;
color:#191724;
font-weight:700;
font-size:20px;
}
button:hover {
background: rgb(156, 207, 216);
}
a {
color: rgb(156, 207, 216);
text-decoration: none;
}
p,
li {
font-size: 16px;
}
h1 {
font-size: 32px;
}
code {
font-family: Fira, FiraCode, monospace;
}
#text {
background-color: #444;
border: solid #aaa;
border-radius: 10px;
color: #e0def4;
margin-top: 3rem;
width: 20rem;
height: 5rem;
padding: 0.5rem;
}
#text:focus {
border: solid #eee;
}
@media screen and (max-width: 500px) {
#text {
width: 80%
}
}

View File

@ -1,72 +0,0 @@
"use strict";
window.onload = async () => {
const account = JSON.parse(localStorage.getItem("account"));
const i = account.token;
const api = (endpoint, data = {}) => {
const promise = new Promise((resolve, reject) => {
// Append a credential
if (i) data.i = i;
// Send request
fetch(endpoint.indexOf("://") > -1 ? endpoint : `/api/${endpoint}`, {
method: "POST",
body: JSON.stringify(data),
credentials: "omit",
cache: "no-cache",
})
.then(async (res) => {
const body = res.status === 204 ? null : await res.json();
if (res.status === 200) {
resolve(body);
} else if (res.status === 204) {
resolve();
} else {
reject(body.error);
}
})
.catch(reject);
});
return promise;
};
document.getElementById("submit").addEventListener("click", () => {
api("notes/create", {
text: document.getElementById("text").value,
}).then(() => {
location.reload();
});
});
api("notes/timeline").then((notes) => {
const tl = document.getElementById("tl");
for (const note of notes) {
const el = document.createElement("div");
const header = document.createElement("header");
const name = document.createElement("p");
const avatar = document.createElement("img");
name.textContent = `${note.user.name} @${note.user.username}`;
avatar.src = note.user.avatarUrl;
avatar.style = "height: 40px";
const text = document.createElement("div");
text.textContent = `${note.text}`;
el.appendChild(header);
header.appendChild(avatar);
header.appendChild(name);
if (note.text) {
el.appendChild(text);
}
if (note.files) {
for (const file of note.files) {
const img = document.createElement("img");
img.src = file.properties.thumbnailUrl;
el.appendChild(img);
}
}
tl.appendChild(el);
}
});
};

View File

@ -2,39 +2,30 @@
* Web Client Server * Web Client Server
*/ */
import { dirname } from "node:path"; import {dirname} from "node:path";
import { fileURLToPath } from "node:url"; import {fileURLToPath} from "node:url";
import { readFileSync } from "node:fs"; import {readFileSync} from "node:fs";
import Koa from "koa"; import Koa from "koa";
import Router from "@koa/router"; import Router from "@koa/router";
import send from "koa-send"; import send from "koa-send";
import favicon from "koa-favicon"; import favicon from "koa-favicon";
import views from "koa-views"; import views from "koa-views";
import sharp from "sharp"; import {createBullBoard} from "@bull-board/api";
import { createBullBoard } from "@bull-board/api"; import {BullAdapter} from "@bull-board/api/bullAdapter.js";
import { BullAdapter } from "@bull-board/api/bullAdapter.js"; import {KoaAdapter} from "@bull-board/koa";
import { KoaAdapter } from "@bull-board/koa";
import { In, IsNull } from "typeorm"; import {In, IsNull} from "typeorm";
import { fetchMeta, metaToPugArgs } from "@/misc/fetch-meta.js"; import {fetchMeta, metaToPugArgs} from "@/misc/fetch-meta.js";
import config from "@/config/index.js"; import config from "@/config/index.js";
import { import {Channels, Clips, GalleryPosts, Notes, Pages, UserProfiles, Users,} from "@/models/index.js";
Users,
Notes,
UserProfiles,
Pages,
Channels,
Clips,
GalleryPosts,
} from "@/models/index.js";
import * as Acct from "@/misc/acct.js"; import * as Acct from "@/misc/acct.js";
import { getNoteSummary } from "@/misc/get-note-summary.js"; import {getNoteSummary} from "@/misc/get-note-summary.js";
import { queues } from "@/queue/queues.js"; import {queues} from "@/queue/queues.js";
import { genOpenapiSpec } from "../api/openapi/gen-spec.js"; import {genOpenapiSpec} from "../api/openapi/gen-spec.js";
import { urlPreviewHandler } from "./url-preview.js"; import {urlPreviewHandler} from "./url-preview.js";
import { manifestHandler } from "./manifest.js"; import {manifestHandler} from "./manifest.js";
import packFeed from "./feed.js"; import packFeed from "./feed.js";
import { MINUTE, DAY } from "@/const.js"; import {DAY, MINUTE} from "@/const.js";
const _filename = fileURLToPath(import.meta.url); const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename); const _dirname = dirname(_filename);
@ -160,60 +151,6 @@ router.get("/twemoji/(.*)", async (ctx) => {
}); });
}); });
router.get("/twemoji-badge/(.*)", async (ctx) => {
const path = ctx.path.replace("/twemoji-badge/", "");
if (!path.match(/^[0-9a-f-]+\.png$/)) {
ctx.status = 404;
return;
}
const mask = await sharp(
`${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/${path.replace(
".png",
"",
)}.svg`,
{ density: 1000 },
)
.resize(488, 488)
.greyscale()
.normalise()
.linear(1.75, -(128 * 1.75) + 128) // 1.75x contrast
.flatten({ background: "#000" })
.extend({
top: 12,
bottom: 12,
left: 12,
right: 12,
background: "#000",
})
.toColorspace("b-w")
.png()
.toBuffer();
const buffer = await sharp({
create: {
width: 512,
height: 512,
channels: 4,
background: { r: 0, g: 0, b: 0, alpha: 0 },
},
})
.pipelineColorspace("b-w")
.boolean(mask, "eor")
.resize(96, 96)
.png()
.toBuffer();
ctx.set(
"Content-Security-Policy",
"default-src 'none'; style-src 'unsafe-inline'",
);
ctx.set("Cache-Control", "max-age=2592000");
ctx.set("Content-Type", "image/png");
ctx.body = buffer;
});
// ServiceWorker // ServiceWorker
router.get("/sw.js", async (ctx) => { router.get("/sw.js", async (ctx) => {
await send(ctx as any, "/sw.js", { await send(ctx as any, "/sw.js", {
@ -573,18 +510,6 @@ router.get("/channels/:channel", async (ctx, next) => {
}); });
//#endregion //#endregion
router.get("/bios", async (ctx) => {
await ctx.render("bios", {
version: config.version,
});
});
router.get("/cli", async (ctx) => {
await ctx.render("cli", {
version: config.version,
});
});
const override = (source: string, target: string, depth = 0) => const override = (source: string, target: string, depth = 0) =>
[ [
undefined, undefined,

View File

@ -1,21 +0,0 @@
doctype html
html
head
meta(charset='utf-8')
meta(name='application-name' content='Calckey')
meta(name='viewport' content='width=device-width, initial-scale=1.0')
title Calckey Repair Tool
style
include ../bios.css
script
include ../bios.js
body
header
h1 Calckey Repair Tool v#{version}
main
div.tabs
button#ls Edit local storage
div#content

View File

@ -1,23 +0,0 @@
doctype html
html
head
meta(charset='utf-8')
meta(name='application-name' content='Calckey')
meta(name='viewport' content='width=device-width, initial-scale=1.0')
title Calckey Cli
style
include ../cli.css
script
include ../cli.js
body
header
h1 Calckey Simple Client v#{version}
main
div#form
textarea#text
br
button#submit Post
div#tl

View File

@ -3,13 +3,12 @@
*/ */
declare let self: ServiceWorkerGlobalScope; declare let self: ServiceWorkerGlobalScope;
import { swLang } from "@/scripts/lang"; import {swLang} from "@/scripts/lang";
import { cli } from "@/scripts/operations"; import {cli} from "@/scripts/operations";
import { pushNotificationDataMap } from "@/types"; import {pushNotificationDataMap} from "@/types";
import getUserName from "@/scripts/get-user-name"; import getUserName from "@/scripts/get-user-name";
import { I18n } from "@/scripts/i18n"; import {I18n} from "@/scripts/i18n";
import { getAccountFromId } from "@/scripts/get-account-from-id"; import {getAccountFromId} from "@/scripts/get-account-from-id";
import { char2fileName } from "@/scripts/twemoji-base";
import * as url from "@/scripts/url"; import * as url from "@/scripts/url";
const iconUrl = (name: string) => const iconUrl = (name: string) =>
@ -185,9 +184,6 @@ async function composeNotification<K extends keyof pushNotificationDataMap>(
})}`; })}`;
} }
} }
} else {
// Unicode絵文字の場合
badge = `/twemoji-badge/${char2fileName(reaction)}.png`;
} }
if ( if (

View File

@ -1,12 +0,0 @@
export const twemojiSvgBase = "/twemoji";
export function char2fileName(char: string): string {
let codes = Array.from(char).map((x) => x.codePointAt(0)?.toString(16));
if (!codes.includes("200d")) codes = codes.filter((x) => x !== "fe0f");
codes = codes.filter((x) => x?.length);
return codes.join("-");
}
export function char2filePath(char: string): string {
return `${twemojiSvgBase}/${char2fileName(char)}.svg`;
}