REFACTOR: Generate Static Pages instead of ?id query param for sticker pack

This commit is contained in:
Kentai Radiquum 2025-01-01 17:19:00 +05:00
parent 5cb32a8681
commit dfcddfc0cd
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
21 changed files with 2074 additions and 473 deletions

6
src/config.js Normal file
View file

@ -0,0 +1,6 @@
const config = {
stickerPacksDir: "./stickerpacks",
outDir: "./",
}
module.exports = config

27
src/index.js Normal file
View file

@ -0,0 +1,27 @@
const config = require("./config");
const fs = require("fs");
const _CreatePackPage = require("./templates/pack");
function GenerateStaticSite() {
let PackIndex = null
try {
PackIndex = JSON.parse(fs.readFileSync(config.stickerPacksDir + "/index.json"));
} catch (e) {
console.error("No index.json found!");
process.exit(1);
}
if (!fs.existsSync(config.outDir)) fs.mkdirSync(config.outDir);
PackIndex.packs.forEach((pack) => {
const packFile = JSON.parse(fs.readFileSync(config.stickerPacksDir + "/" + pack));
if (!fs.existsSync(config.outDir + "/" + packFile.id)) fs.mkdirSync(config.outDir + "/" + packFile.id);
fs.writeFileSync(config.outDir + "/" + packFile.id + "/index.html", _CreatePackPage(PackIndex, packFile));
console.log("preview for " + packFile.id + " created");
})
}
GenerateStaticSite();
module.exports = GenerateStaticSite

13
src/src.css Normal file
View file

@ -0,0 +1,13 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
.tiledBackground {
background-image: url('images/background-white.png');
background-repeat: repeat;
background-size: contain;
background-attachment: fixed;
background-size: 256px;
opacity: .25;
margin-top: -16px;
}

View file

@ -0,0 +1,20 @@
const {CreateImageURL, CreatePackDescription} = require("../../utils");
function _CreateHead(index, pack) {
return `
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>${pack.title}</title>
<link rel="icon" type="${pack.stickers[0].info.mimetype}" href="${CreateImageURL(index, pack.stickers[0].id)}" />
<meta property="og:title" content="${pack.title}" />
<meta property="og:description" content="${CreatePackDescription(pack)}" />
<meta property="og:type" content="website" />
<meta property="og:image" content="${CreateImageURL(index, pack.stickers[0].id)}" />
<meta property="og:image:type" content="${pack.stickers[0].info.mimetype}" />
<meta property="og:image:width" content="${pack.stickers[0].info.w}" />
<meta property="og:image:height" content="${pack.stickers[0].info.h}" />
<meta property="og:image:alt" content="${pack.stickers[0].body}" />
<link href="../static/tailwind.css" rel="stylesheet">
`}
module.exports = _CreateHead

View file

@ -0,0 +1,71 @@
const { CreateImageURL } = require("../../utils");
function _packName(pack) {
let string = "";
string += `<p class="text-4xl">${pack.title}</p>`;
if (pack.hasOwnProperty("author") && pack.author) {
let author_string = `<p class="text-2xl">by: ${pack.author.name}</p>`;
if (pack.author.url) {
author_string = `<p class="text-2xl">by: <a href="${pack.author.url}" class="underline">${pack.author.name}</a></p>`;
}
string += author_string;
}
if (pack.hasOwnProperty("rating") && pack.rating) {
switch (pack.rating.toLowerCase()) {
case "safe":
string += `<p class="text-2xl text-green-400 text-bold">safe</p>`;
break;
case "questionable":
string += `<p class="text-2xl text-yellow-500 text-bold">questionable</p>`;
break;
case "explicit":
string += `<p class="text-2xl text-red-500 text-bold">explicit</p>`;
break;
default:
break;
}
}
return string;
}
function _packCard(index, pack) {
return `
<div class="w-full flex gap-4 flex-col md:flex-row md:w-[768px] justify-center items-center bg-stone-800 text-zinc-100 px-4 py-8 rounded-lg">
<div class="w-48 h-48 flex justify-center items-center">
<div role="status" data-spinner-id="${pack.stickers[0].id}">
<svg
aria-hidden="true"
class="inline w-16 h-16 text-gray-200 animate-spin dark:text-gray-600 fill-green-500"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span class="sr-only">Loading...</span>
</div>
<img
src="${CreateImageURL(index, pack.stickers[0].id)}"
alt="${pack.stickers[0].body}"
class="object-contain w-48 h-48 hidden"
data-image-id="${pack.stickers[0].id}"
/>
</div>
<div class="flex flex-col gap-2 justify-center">
${_packName(pack)}
</div>
</div>
`;
}
module.exports = _packCard;

View file

@ -0,0 +1,26 @@
function PackLinks(pack) {
return `
<a class="bg-[#2f7ca3] gap-2 items-center w-full px-8 py-4 rounded-lg flex hover:scale-105 transition-transform" href="https://t.me/addstickers/${pack.id}">
<img src="../static/images/telegram.png" alt="" class="object-contain w-10" />
<p class="text-2xl text-slate-50">Telegram</p>
</a>
<button class="bg-[#259d7b] gap-2 items-center w-full px-8 py-4 rounded-lg flex hover:scale-105 transition-transform" onclick="toggleElementInstruction()">
<img src="../static/images/element.png" alt="" class="object-contain w-10" />
<p class="text-2xl text-slate-50">Element</p>
</button>
${(pack.hasOwnProperty("room_id") && pack.room_id) ? (
`
<a class="bg-[#282443] gap-2 items-center w-full px-8 py-4 rounded-lg flex hover:scale-105 transition-transform" href="https://matrix.to/#/${pack.room_id}">
<img src="../static/images/fluffychat.png" alt="" class="object-contain w-10" />
<p class="text-2xl text-slate-50">FluffyChat</p>
</a>
<a class="bg-[#373737] gap-2 items-center w-full px-8 py-4 rounded-lg flex hover:scale-105 transition-transform" href="https://matrix.to/#/${pack.room_id}">
<img src="../static/images/cinny.png" alt="" class="object-contain w-10" />
<p class="text-2xl text-slate-50">Cinny</p>
</a>
`
)
: ""}
`}
module.exports = PackLinks

64
src/templates/pack.js Normal file
View file

@ -0,0 +1,64 @@
const Head = require("./components/head");
const PackCard = require("./components/packCard");
const PackLinks = require("./components/PackLinks");
function _CreatePackPage(index, pack) {
return `
<html>
<head>
${Head(index, pack)}
</head>
<body class="overflow-x-hidden">
<div class="fixed inset-0 min-h-screen -z-10 tiledBackground"></div>
<div class="fixed inset-0 min-h-screen -z-20 bg-gradient-to-b from-gray-900 to-black"></div>
<div class="container flex flex-col items-center justify-center min-h-screen gap-4 p-4 mx-auto">
${PackCard(index, pack)}
<div class="flex flex-col gap-2 justify-center w-full md:w-[768px]">
${PackLinks(pack)}
</div>
</div>
<div class="fixed inset-0 z-10 hidden min-h-screen bg-black opacity-40" id="preview_sticker_pack_add_to_element_overlay"></div>
<div class="fixed top-8 md:top-32 w-full md:max-w-[768px] left-1/2 -translate-x-1/2 text-white z-20 hidden flex-col gap-4 p-4 rounded-lg shadow-lg bg-stone-900" id="preview_sticker_pack_add_to_element">
<p>
Type /devtools in chat. Other -> Explore account data in Element Web (not "room account data", must be the global one), edit the m.widgets account data event to have the following content:
</p>
<p class="md:whitespace-pre">
{
"stickerpicker": {
"content": {
"type": "m.stickerpicker",
"url": "https://matrix.wah.su/stickerpicker/?theme=$theme",
"name": "Stickerpicker",
"creatorUserId": "@you:matrix.server.name",
"data": {}
},
"sender": "@you:matrix.server.name",
"state_key": "stickerpicker",
"type": "m.widget",
"id": "stickerpicker"
}
}
</p>
<p>
If you do not yet have a m.widgets event, simply create it with that content. You can also use the client-server API directly instead of using Element Web.
<br />
<br />
The theme=$theme query parameter will make the widget conform to Element's theme automatically. You can also use light, dark or black instead of $theme to always use a specific theme.
</p>
<button class="flex items-center justify-center w-full py-2 text-2xl bg-red-600 rounded-lg" onclick="toggleElementInstruction()">Close</button>
</div>
<script src="../static/RenderImages.js"></script>
<script src="../static/OpenPopUp.js"></script>
</body>
</html>
`
}
module.exports = _CreatePackPage

39
src/utils.js Normal file
View file

@ -0,0 +1,39 @@
function CreateImageURL(index, id) {
return `${index.homeserver_url}${id.slice(0, 2)}/${id.slice(2, 4)}/${id.slice(
4
)}`;
}
function CreatePackDescription(pack) {
let description = [];
description.push(`${pack.stickers.length} stickers`);
if (pack.hasOwnProperty("rating") && pack.rating) {
switch (pack.rating.toLowerCase()) {
case "safe":
description.push("rating: safe");
break;
case "questionable":
description.push("rating: questionable");
break;
case "explicit":
description.push("rating: explicit");
break;
default:
break;
}
}
if (pack.hasOwnProperty("author") && pack.author) {
let author_string = `author: ${pack.author.name}`;
if (pack.author.url) {
author_string += ` (${pack.author.url})`;
}
description.push(author_string);
}
return description.join(" | ");
}
module.exports = {CreateImageURL, CreatePackDescription};

36
src/watch.js Normal file
View file

@ -0,0 +1,36 @@
const chokidar = require("chokidar");
const exec = require("child_process");
function onChange() {
exec.exec("npm run build", (error, stdout, stderr) => {
if (error) {
console.error(`error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
}
const watcher = chokidar.watch("./src/templates", {
ignored: (path, stats) =>
stats?.isFile() && !(path.endsWith(".js") || path.endsWith(".json")),
// atomic: true,
awaitWriteFinish: true,
persistent: true,
});
watcher.on("add", (path) => {
console.log(`File ${path} has been added, rebuilding...`);
onChange();
});
watcher.on("change", (path) => {
console.log(`File ${path} has been changed, rebuilding...`);
onChange();
});
watcher.on("unlink", (path) => {
console.log(`File ${path} has been removed, rebuilding...`);
onChange();
});