add customization

This commit is contained in:
Pouria Ezzati 2025-01-15 11:45:53 +03:30
parent 191e58b3f6
commit 1e01e10459
7 changed files with 47 additions and 3 deletions

2
.gitignore vendored
View File

@ -14,3 +14,5 @@ docs/api/static
**/.DS_Store **/.DS_Store
db/* db/*
!db/.gitkeep !db/.gitkeep
custom/*
!custom/.gitkeep

3
custom/.gitkeep Normal file
View File

@ -0,0 +1,3 @@
# keep this folder in git
# put supported customization files for styles and such
# if you're using docker make sure to mount this folder

View File

@ -4,7 +4,7 @@
"description": "Modern URL shortener.", "description": "Modern URL shortener.",
"main": "./server/server.js", "main": "./server/server.js",
"scripts": { "scripts": {
"dev": "cross-env NODE_ENV=development node --watch-path=./server server/server.js", "dev": "cross-env NODE_ENV=development node --watch-path=./server --watch-path=./custom server/server.js",
"start": "cross-env NODE_ENV=production node server/server.js", "start": "cross-env NODE_ENV=production node server/server.js",
"migrate": "knex migrate:latest", "migrate": "knex migrate:latest",
"migrate:make": "knex migrate:make", "migrate:make": "knex migrate:make",

View File

@ -29,6 +29,7 @@ function config(req, res, next) {
res.locals.disallow_registration = env.DISALLOW_REGISTRATION; res.locals.disallow_registration = env.DISALLOW_REGISTRATION;
res.locals.mail_enabled = env.MAIL_ENABLED; res.locals.mail_enabled = env.MAIL_ENABLED;
res.locals.report_email = env.REPORT_EMAIL; res.locals.report_email = env.REPORT_EMAIL;
res.locals.custom_styles = utils.getCustomCSSFileNames();
next(); next();
} }

View File

@ -40,6 +40,10 @@ app.use(helmet({ contentSecurityPolicy: false }));
app.use(cookieParser()); app.use(cookieParser());
app.use(express.json()); app.use(express.json());
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));
// serve static
app.use("/images", express.static("custom/images"));
app.use("/css", express.static("custom/css", { extensions: ["css"] }));
app.use(express.static("static")); app.use(express.static("static"));
app.use(passport.initialize()); app.use(passport.initialize());
@ -47,8 +51,12 @@ app.use(locals.isHTML);
app.use(locals.config); app.use(locals.config);
// template engine / serve html // template engine / serve html
app.set("view engine", "hbs"); app.set("view engine", "hbs");
app.set("views", path.join(__dirname, "views")); app.set("views", [
path.join(__dirname, "../custom/views"),
path.join(__dirname, "views"),
]);
utils.registerHandlebarsHelpers(); utils.registerHandlebarsHelpers();
// if is custom domain, redirect to the set homepage // if is custom domain, redirect to the set homepage

View File

@ -1,7 +1,8 @@
const { differenceInDays, differenceInHours, differenceInMonths, differenceInMilliseconds, addDays, subHours, subDays, subMonths, subYears, format } = require("date-fns"); const { differenceInDays, differenceInHours, differenceInMonths, differenceInMilliseconds, addDays, subHours, subDays, subMonths, subYears, format } = require("date-fns");
const { customAlphabet } = require("nanoid"); const { customAlphabet } = require("nanoid");
const JWT = require("jsonwebtoken"); const JWT = require("jsonwebtoken");
const path = require("path"); const path = require("node:path");
const fs = require("node:fs");
const hbs = require("hbs"); const hbs = require("hbs");
const ms = require("ms"); const ms = require("ms");
@ -360,6 +361,31 @@ function registerHandlebarsHelpers() {
return val; return val;
}); });
hbs.registerPartials(path.join(__dirname, "../views/partials"), function (err) {}); hbs.registerPartials(path.join(__dirname, "../views/partials"), function (err) {});
const customPartialsPath = path.join(__dirname, "../../custom/views/partials");
const customPartialsExist = fs.existsSync(customPartialsPath);
if (customPartialsExist) {
hbs.registerPartials(customPartialsPath, function (err) {});
}
}
// grab custom styles file name from the custom/css folder
const custom_css_file_names = [];
const customCSSPath = path.join(__dirname, "../../custom/css");
const customCSSExists = fs.existsSync(customCSSPath);
if (customCSSExists) {
fs.readdir(customCSSPath, function(error, files) {
if (error) {
console.warn("Could not read the custom CSS folder:", error);
} else {
files.forEach(function(file_name) {
custom_css_file_names.push(file_name);
});
}
})
}
function getCustomCSSFileNames() {
return custom_css_file_names;
} }
module.exports = { module.exports = {
@ -368,6 +394,7 @@ module.exports = {
dateToUTC, dateToUTC,
deleteCurrentToken, deleteCurrentToken,
generateId, generateId,
getCustomCSSFileNames,
getDifferenceFunction, getDifferenceFunction,
getInitStats, getInitStats,
getShortURL, getShortURL,

View File

@ -24,6 +24,9 @@
<meta name="description" content="{{site_name}} is a free and open source URL shortener with custom domains and stats." /> <meta name="description" content="{{site_name}} is a free and open source URL shortener with custom domains and stats." />
<title>{{site_name}} | {{title}}</title> <title>{{site_name}} | {{title}}</title>
<link rel="stylesheet" href="/css/styles.css"> <link rel="stylesheet" href="/css/styles.css">
{{#each custom_styles}}
<link rel="stylesheet" href="/css/{{this}}">
{{/each}}
{{{block "stylesheets"}}} {{{block "stylesheets"}}}
</head> </head>
<body> <body>