mirror of
https://github.com/Wolvan/poll.horse.git
synced 2024-11-21 20:47:59 +01:00
Implement favicon and embbed icon
Thanks to Shydale for lending me their OC checkbox. She a cute.
This commit is contained in:
parent
8042cfb4ff
commit
f68ff6dbd2
11 changed files with 3715 additions and 75 deletions
|
@ -1,3 +1,4 @@
|
||||||
dist/
|
dist/
|
||||||
node_modules/
|
node_modules/
|
||||||
utils/todo-finder.js
|
utils/todo-finder.js
|
||||||
|
utils/create-favicons.js
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -117,3 +117,6 @@ data/
|
||||||
# Config files
|
# Config files
|
||||||
config*.js*
|
config*.js*
|
||||||
!config.example.json
|
!config.example.json
|
||||||
|
|
||||||
|
# Favicons that are being auto-generated
|
||||||
|
frontend/favicons/
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<meta property="og:title" content="{{ TITLE }}" />
|
<meta property="og:title" content="{{ TITLE }}" />
|
||||||
<meta property="og:description" content="Simple, free and open source way to host polls for people to vote on. Create your own polls and share them with others!" />
|
<meta property="og:description" content="Simple, free and open source way to host polls for people to vote on. Create your own polls and share them with others!" />
|
||||||
<meta property="og:url" content="{{ CANONICAL_HOST }}" />
|
<meta property="og:url" content="{{ CANONICAL_HOST }}" />
|
||||||
<meta property="og:image" content="" />
|
<meta property="og:image" content="{{ HOST }}/static/img/icon.png" />
|
||||||
<meta property="og:site_name" content="Poll.Horse" />
|
<meta property="og:site_name" content="Poll.Horse" />
|
||||||
<meta content="#FFD756" data-react-helmet="true" name="theme-color" />
|
<meta content="#FFD756" data-react-helmet="true" name="theme-color" />
|
||||||
|
|
||||||
|
@ -27,6 +27,9 @@
|
||||||
const MAX_CHARACTER_LENGTH = "{{ MAX_CHARACTER_LENGTH }}";
|
const MAX_CHARACTER_LENGTH = "{{ MAX_CHARACTER_LENGTH }}";
|
||||||
</script>
|
</script>
|
||||||
<script nonce="{{ CORS_SCRIPT_NONCE }}" type="text/javascript" src="/static/js/index.js" defer="true" async="true"></script>
|
<script nonce="{{ CORS_SCRIPT_NONCE }}" type="text/javascript" src="/static/js/index.js" defer="true" async="true"></script>
|
||||||
|
<!-- FAVICON_MARKER -->
|
||||||
|
|
||||||
|
<!-- /FAVICON_MARKER -->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<meta property="og:title" content="{{ TITLE }}" />
|
<meta property="og:title" content="{{ TITLE }}" />
|
||||||
<meta property="og:description" content="{{ POLL_META_DESCRIPTION }}" />
|
<meta property="og:description" content="{{ POLL_META_DESCRIPTION }}" />
|
||||||
<meta property="og:url" content="{{ CANONICAL_HOST }}" />
|
<meta property="og:url" content="{{ CANONICAL_HOST }}" />
|
||||||
<meta property="og:image" content="" />
|
<meta property="og:image" content="{{ HOST }}/static/img/icon.png" />
|
||||||
<meta property="og:site_name" content="Poll.Horse" />
|
<meta property="og:site_name" content="Poll.Horse" />
|
||||||
<meta content="#FFD756" data-react-helmet="true" name="theme-color" />
|
<meta content="#FFD756" data-react-helmet="true" name="theme-color" />
|
||||||
|
|
||||||
|
@ -36,6 +36,9 @@
|
||||||
document.querySelectorAll(".poll-option .text").forEach(element => textFit(element, textFitOptions));
|
document.querySelectorAll(".poll-option .text").forEach(element => textFit(element, textFitOptions));
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<!-- FAVICON_MARKER -->
|
||||||
|
|
||||||
|
<!-- /FAVICON_MARKER -->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<meta property="og:title" content="{{ TITLE }}" />
|
<meta property="og:title" content="{{ TITLE }}" />
|
||||||
<meta property="og:description" content="{{ POLL_META_DESCRIPTION }}" />
|
<meta property="og:description" content="{{ POLL_META_DESCRIPTION }}" />
|
||||||
<meta property="og:url" content="{{ CANONICAL_HOST }}" />
|
<meta property="og:url" content="{{ CANONICAL_HOST }}" />
|
||||||
<meta property="og:image" content="" />
|
<meta property="og:image" content="{{ HOST }}/static/img/icon.png" />
|
||||||
<meta property="og:site_name" content="Poll.Horse" />
|
<meta property="og:site_name" content="Poll.Horse" />
|
||||||
<meta content="#FFD756" data-react-helmet="true" name="theme-color" />
|
<meta content="#FFD756" data-react-helmet="true" name="theme-color" />
|
||||||
|
|
||||||
|
@ -30,6 +30,9 @@
|
||||||
const POLL_ID = "{{ POLL_ID }}";
|
const POLL_ID = "{{ POLL_ID }}";
|
||||||
</script>
|
</script>
|
||||||
<script nonce="{{ CORS_SCRIPT_NONCE }}" type="text/javascript" src="/static/js/result.js" defer="true"></script>
|
<script nonce="{{ CORS_SCRIPT_NONCE }}" type="text/javascript" src="/static/js/result.js" defer="true"></script>
|
||||||
|
<!-- FAVICON_MARKER -->
|
||||||
|
|
||||||
|
<!-- /FAVICON_MARKER -->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
|
|
BIN
frontend/static/img/icon.png
Normal file
BIN
frontend/static/img/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
3699
package-lock.json
generated
3699
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,8 @@
|
||||||
"find-todo": "node utils/todo-finder.js ./src && node utils/todo-finder.js ./frontend",
|
"find-todo": "node utils/todo-finder.js ./src && node utils/todo-finder.js ./frontend",
|
||||||
"mocha": "mocha",
|
"mocha": "mocha",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"build": "rimraf ./dist && tsc",
|
"build:favicons": "node utils/create-favicons",
|
||||||
|
"build": "rimraf ./dist && npm run build:favicons && tsc",
|
||||||
"test": "npm run lint && npm run find-todo && npm run mocha",
|
"test": "npm run lint && npm run find-todo && npm run mocha",
|
||||||
"debug": "ts-node-dev --inspect --respawn --clear ./src/main.ts",
|
"debug": "ts-node-dev --inspect --respawn --clear ./src/main.ts",
|
||||||
"start:build": "npm test && npm run build && node ./dist/main.js",
|
"start:build": "npm test && npm run build && node ./dist/main.js",
|
||||||
|
@ -46,6 +47,7 @@
|
||||||
"@types/node": "^16.11.10",
|
"@types/node": "^16.11.10",
|
||||||
"@types/node-fetch": "^2.5.12",
|
"@types/node-fetch": "^2.5.12",
|
||||||
"@types/node-persist": "^3.1.2",
|
"@types/node-persist": "^3.1.2",
|
||||||
|
"@types/serve-favicon": "^2.5.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
|
@ -65,10 +67,12 @@
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"express": "^4.17.2",
|
"express": "^4.17.2",
|
||||||
|
"favicons": "^6.2.2",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"helmet": "^5.0.2",
|
"helmet": "^5.0.2",
|
||||||
"mysql2": "^2.3.3",
|
"mysql2": "^2.3.3",
|
||||||
"node-fetch": "^2.6.6",
|
"node-fetch": "^2.6.6",
|
||||||
"node-persist": "^3.1.0"
|
"node-persist": "^3.1.0",
|
||||||
|
"serve-favicon": "^2.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,8 @@ export default function init(router: Router): void {
|
||||||
"QR_CODE": `https://chart.googleapis.com/chart?cht=qr&chs=190x190&chld=L|1&chl=${ encodeURIComponent(`${ req.protocol }://${ req.headers.host }/${ id }`) }`,
|
"QR_CODE": `https://chart.googleapis.com/chart?cht=qr&chs=190x190&chld=L|1&chl=${ encodeURIComponent(`${ req.protocol }://${ req.headers.host }/${ id }`) }`,
|
||||||
"CANONICAL_HOST": req.protocol + "://" + (req.headers.host || "") + "/" + id + "/r",
|
"CANONICAL_HOST": req.protocol + "://" + (req.headers.host || "") + "/" + id + "/r",
|
||||||
"POLL_META_DESCRIPTION": xss(poll.title || "Simple, free and open source way to host polls for people to vote on. Create your own polls and share them with others!").substring(0, 150),
|
"POLL_META_DESCRIPTION": xss(poll.title || "Simple, free and open source way to host polls for people to vote on. Create your own polls and share them with others!").substring(0, 150),
|
||||||
"CORS_SCRIPT_NONCE": res.locals.cspNonce
|
"CORS_SCRIPT_NONCE": res.locals.cspNonce,
|
||||||
|
"HOST": req.protocol + "://" + (req.headers.host || "")
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -202,7 +203,8 @@ export default function init(router: Router): void {
|
||||||
"QR_CODE": `https://chart.googleapis.com/chart?cht=qr&chs=190x190&chld=L|1&chl=${ encodeURIComponent(`${ req.protocol }://${ req.headers.host }/${ id }`) }`,
|
"QR_CODE": `https://chart.googleapis.com/chart?cht=qr&chs=190x190&chld=L|1&chl=${ encodeURIComponent(`${ req.protocol }://${ req.headers.host }/${ id }`) }`,
|
||||||
"CANONICAL_HOST": req.protocol + "://" + (req.headers.host || "") + "/" + id,
|
"CANONICAL_HOST": req.protocol + "://" + (req.headers.host || "") + "/" + id,
|
||||||
"POLL_META_DESCRIPTION": xss(poll.title || "Simple, free and open source way to host polls for people to vote on. Create your own polls and share them with others!").substring(0, 150),
|
"POLL_META_DESCRIPTION": xss(poll.title || "Simple, free and open source way to host polls for people to vote on. Create your own polls and share them with others!").substring(0, 150),
|
||||||
"CORS_SCRIPT_NONCE": res.locals.cspNonce
|
"CORS_SCRIPT_NONCE": res.locals.cspNonce,
|
||||||
|
"HOST": req.protocol + "://" + (req.headers.host || "")
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -237,7 +239,8 @@ export default function init(router: Router): void {
|
||||||
"MAX_POLL_OPTIONS": MAX_POLL_OPTIONS,
|
"MAX_POLL_OPTIONS": MAX_POLL_OPTIONS,
|
||||||
"MAX_CHARACTER_LENGTH": MAX_CHARACTER_LENGTH,
|
"MAX_CHARACTER_LENGTH": MAX_CHARACTER_LENGTH,
|
||||||
"CANONICAL_HOST": req.protocol + "://" + (req.headers.host || ""),
|
"CANONICAL_HOST": req.protocol + "://" + (req.headers.host || ""),
|
||||||
"CORS_SCRIPT_NONCE": res.locals.cspNonce
|
"CORS_SCRIPT_NONCE": res.locals.cspNonce,
|
||||||
|
"HOST": req.protocol + "://" + (req.headers.host || "")
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
12
src/main.ts
12
src/main.ts
|
@ -11,6 +11,8 @@ import Storage from "./Storage";
|
||||||
import MySQLStorage from "./MySQLStorage";
|
import MySQLStorage from "./MySQLStorage";
|
||||||
import helmet from "helmet";
|
import helmet from "helmet";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
|
import { statSync } from "fs";
|
||||||
|
import serveFavicon from "serve-favicon";
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
await loadConfig([
|
await loadConfig([
|
||||||
|
@ -31,6 +33,16 @@ async function main(): Promise<void> {
|
||||||
const opts = program.opts();
|
const opts = program.opts();
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (statSync(resolve(__dirname, "../frontend/favicons")).isDirectory()) {
|
||||||
|
app.use("/favicons", express.static(resolve(__dirname, "../frontend/favicons")));
|
||||||
|
if (statSync(resolve(__dirname, "../frontend/favicons/favicon.ico")).isFile()) app.use(serveFavicon(resolve(__dirname, "../frontend/favicons/favicon.ico")));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("FavIcons not available: ", error);
|
||||||
|
}
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: false }));
|
app.use(express.urlencoded({ extended: false }));
|
||||||
app.use(compression());
|
app.use(compression());
|
||||||
|
|
43
utils/create-favicons.js
Normal file
43
utils/create-favicons.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const favicons = require("favicons");
|
||||||
|
const resolve = require("path").resolve;
|
||||||
|
const fs = require("fs-extra");
|
||||||
|
|
||||||
|
const start = new Date();
|
||||||
|
favicons(resolve(__dirname, "../frontend/static/img/icon.png"), {
|
||||||
|
path: "/favicons",
|
||||||
|
appName: "Poll.Horse",
|
||||||
|
appShortName: "poll_horse",
|
||||||
|
appDescription: "Simple, free and open source way to host polls for people to vote on. Create your own polls and share them with others!",
|
||||||
|
developerName: "Wolvan",
|
||||||
|
developerURL: "https://github.com/wolvan",
|
||||||
|
background: "#FFD756",
|
||||||
|
theme_color: "#FFD756",
|
||||||
|
version: require(resolve(__dirname, "../package.json")).version
|
||||||
|
}, async (error, response) => {
|
||||||
|
if (error) throw new error;
|
||||||
|
await fs.remove(resolve(__dirname, "../frontend/favicons"));
|
||||||
|
await fs.ensureDir(resolve(__dirname, "../frontend/favicons"));
|
||||||
|
await Promise.all(response.images.map(({ name, contents }) => fs.writeFile(resolve(__dirname, "../frontend/favicons", name), contents)));
|
||||||
|
await Promise.all(response.files.map(({ name, contents }) => fs.writeFile(resolve(__dirname, "../frontend/favicons", name), contents)));
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ((await fs.stat(resolve(__dirname, "../frontend/html"))).isDirectory()) {
|
||||||
|
const files = await fs.readdir(resolve(__dirname, "../frontend/html"));
|
||||||
|
await Promise.all(files.filter(file => file.match(/\.html?/i)).map(async file => {
|
||||||
|
let content = await fs.readFile(resolve(__dirname, "../frontend/html", file), "utf8");
|
||||||
|
content = content
|
||||||
|
.replace(/<!-- FAVICON_MARKER -->[\s\S]*<!-- \/FAVICON_MARKER -->/i,
|
||||||
|
`<!-- FAVICON_MARKER -->
|
||||||
|
${response.html.join("\n ")}
|
||||||
|
<!-- \/FAVICON_MARKER -->`);
|
||||||
|
await fs.writeFile(resolve(__dirname, "../frontend/html", file), content);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
console.log("Finished Favicon generation in", ((new Date() - start) / 1000).toFixed(2), "s");
|
||||||
|
});
|
Loading…
Reference in a new issue