Simplified the frontend serving part of the backend
This commit is contained in:
parent
1975a21c80
commit
d47566626a
|
@ -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({
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -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");
|
||||||
|
|
|
@ -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%
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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`;
|
|
||||||
}
|
|
Loading…
Reference in New Issue