Compare commits
6 commits
main
...
custom-the
Author | SHA1 | Date | |
---|---|---|---|
|
5a3db14872 | ||
|
794011af62 | ||
|
7700b668ab | ||
|
5e8fd5ccae | ||
|
8049ce6abf | ||
|
904d33e895 |
6 changed files with 618 additions and 465 deletions
|
@ -19,6 +19,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/parser": "^5.6.0",
|
"@typescript-eslint/parser": "^5.6.0",
|
||||||
"autosize": "^5.0.1",
|
"autosize": "^5.0.1",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
"check-password-strength": "^2.0.3",
|
"check-password-strength": "^2.0.3",
|
||||||
"choices.js": "^10.0.0",
|
"choices.js": "^10.0.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
import fs from "fs";
|
||||||
import { IncomingHttpHeaders } from "http";
|
import { IncomingHttpHeaders } from "http";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import { matchPath, StaticRouter } from "inferno-router";
|
import { matchPath, StaticRouter } from "inferno-router";
|
||||||
|
@ -23,6 +24,10 @@ const server = express();
|
||||||
const [hostname, port] = process.env["LEMMY_UI_HOST"]
|
const [hostname, port] = process.env["LEMMY_UI_HOST"]
|
||||||
? process.env["LEMMY_UI_HOST"].split(":")
|
? process.env["LEMMY_UI_HOST"].split(":")
|
||||||
: ["0.0.0.0", "1234"];
|
: ["0.0.0.0", "1234"];
|
||||||
|
const extraThemesFolder =
|
||||||
|
process.env["LEMMY_UI_EXTRA_THEMES_FOLDER"] || "./extra_themes";
|
||||||
|
|
||||||
|
export const themeList = buildThemeList();
|
||||||
|
|
||||||
server.use(express.json());
|
server.use(express.json());
|
||||||
server.use(express.urlencoded({ extended: false }));
|
server.use(express.urlencoded({ extended: false }));
|
||||||
|
@ -46,6 +51,86 @@ server.get("/robots.txt", async (_req, res) => {
|
||||||
res.send(robotstxt);
|
res.send(robotstxt);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const builtinThemes = [
|
||||||
|
"litera",
|
||||||
|
"materia",
|
||||||
|
"minty",
|
||||||
|
"solar",
|
||||||
|
"united",
|
||||||
|
"cyborg",
|
||||||
|
"darkly",
|
||||||
|
"journal",
|
||||||
|
"sketchy",
|
||||||
|
"vaporwave",
|
||||||
|
"vaporwave-dark",
|
||||||
|
"i386",
|
||||||
|
"litely",
|
||||||
|
"nord",
|
||||||
|
];
|
||||||
|
|
||||||
|
function buildThemeList(): string[] {
|
||||||
|
let data = fs.readdirSync(extraThemesFolder);
|
||||||
|
if (data != null) {
|
||||||
|
data = data
|
||||||
|
.filter(d => d.endsWith(".min.css"))
|
||||||
|
.map(d => d.replace(".min.css", ""));
|
||||||
|
data = builtinThemes.concat(data);
|
||||||
|
// use set to remove duplicate values
|
||||||
|
data = Array.from(new Set(data));
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
return builtinThemes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server.get("/css/themes-list", async (req, res) => {
|
||||||
|
const builtinThemes = [
|
||||||
|
"litera",
|
||||||
|
"materia",
|
||||||
|
"minty",
|
||||||
|
"solar",
|
||||||
|
"united",
|
||||||
|
"cyborg",
|
||||||
|
"darkly",
|
||||||
|
"journal",
|
||||||
|
"sketchy",
|
||||||
|
"vaporwave",
|
||||||
|
"vaporwave-dark",
|
||||||
|
"i386",
|
||||||
|
"litely",
|
||||||
|
"nord",
|
||||||
|
];
|
||||||
|
fs.readdir(extraThemesFolder, function (_, data) {
|
||||||
|
if (data != null) {
|
||||||
|
data = data
|
||||||
|
.filter(d => d.endsWith(".min.css"))
|
||||||
|
.map(d => d.replace(".min.css", ""));
|
||||||
|
data = builtinThemes.concat(data);
|
||||||
|
// use set to remove duplicate values
|
||||||
|
data = Array.from(new Set(data));
|
||||||
|
res.send(data);
|
||||||
|
} else {
|
||||||
|
res.send(builtinThemes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/css/themes/:name", async (req, res) => {
|
||||||
|
res.contentType("text/css");
|
||||||
|
const theme = req.params.name;
|
||||||
|
if (!theme.endsWith(".min.css")) {
|
||||||
|
res.send("Theme must be a css file");
|
||||||
|
}
|
||||||
|
|
||||||
|
const customTheme = path.resolve(`./${extraThemesFolder}/${theme}`);
|
||||||
|
if (fs.existsSync(customTheme)) {
|
||||||
|
res.sendFile(customTheme);
|
||||||
|
} else {
|
||||||
|
const internalTheme = path.resolve(`./dist/assets/css/themes/${theme}`);
|
||||||
|
res.sendFile(internalTheme);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// server.use(cookieParser());
|
// server.use(cookieParser());
|
||||||
server.get("/*", async (req, res) => {
|
server.get("/*", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -17,21 +17,21 @@ export class Theme extends Component<Props> {
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
href={`/static/assets/css/themes/${user.local_user_view.local_user.theme}.min.css`}
|
href={`css/themes/${user.local_user_view.local_user.theme}.min.css`}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
[
|
[
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
href="/static/assets/css/themes/litely.min.css"
|
href="css/themes/litely.min.css"
|
||||||
id="default-light"
|
id="default-light"
|
||||||
media="(prefers-color-scheme: light)"
|
media="(prefers-color-scheme: light)"
|
||||||
/>,
|
/>,
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
href="/static/assets/css/themes/darkly.min.css"
|
href="css/themes/darkly.min.css"
|
||||||
id="default-dark"
|
id="default-dark"
|
||||||
media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
|
media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
|
||||||
/>,
|
/>,
|
||||||
|
|
|
@ -29,6 +29,7 @@ import {
|
||||||
debounce,
|
debounce,
|
||||||
elementUrl,
|
elementUrl,
|
||||||
fetchCommunities,
|
fetchCommunities,
|
||||||
|
fetchThemes,
|
||||||
fetchUsers,
|
fetchUsers,
|
||||||
getLanguages,
|
getLanguages,
|
||||||
isBrowser,
|
isBrowser,
|
||||||
|
@ -39,7 +40,6 @@ import {
|
||||||
setTheme,
|
setTheme,
|
||||||
setupTippy,
|
setupTippy,
|
||||||
showLocal,
|
showLocal,
|
||||||
themes,
|
|
||||||
toast,
|
toast,
|
||||||
updateCommunityBlock,
|
updateCommunityBlock,
|
||||||
updatePersonBlock,
|
updatePersonBlock,
|
||||||
|
@ -545,7 +545,7 @@ export class Settings extends Component<any, SettingsState> {
|
||||||
{i18n.t("theme")}
|
{i18n.t("theme")}
|
||||||
</option>
|
</option>
|
||||||
<option value="browser">{i18n.t("browser_default")}</option>
|
<option value="browser">{i18n.t("browser_default")}</option>
|
||||||
{themes.map(theme => (
|
{fetchThemes().map(theme => (
|
||||||
<option value={theme}>{theme}</option>
|
<option value={theme}>{theme}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -77,22 +77,23 @@ export const mentionDropdownFetchLimit = 10;
|
||||||
|
|
||||||
export const relTags = "noopener nofollow";
|
export const relTags = "noopener nofollow";
|
||||||
|
|
||||||
export const themes = [
|
export function fetchThemes(): Promise<string[]> {
|
||||||
"litera",
|
var promise = new Promise<string[]>((resolve, reject) => {
|
||||||
"materia",
|
if (isBrowser()) {
|
||||||
"minty",
|
const url = `${window.location.protocol}//${window.location.host}/css/themes-list`;
|
||||||
"solar",
|
console.log(url);
|
||||||
"united",
|
fetch(url).then(res => {
|
||||||
"cyborg",
|
res.json().then(json => {
|
||||||
"darkly",
|
console.log(json);
|
||||||
"journal",
|
resolve(json);
|
||||||
"sketchy",
|
});
|
||||||
"vaporwave",
|
});
|
||||||
"vaporwave-dark",
|
} else {
|
||||||
"i386",
|
listThemes().then(themes => resolve(themes));
|
||||||
"litely",
|
}
|
||||||
"nord",
|
});
|
||||||
];
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_ALPHABET =
|
const DEFAULT_ALPHABET =
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
|
Loading…
Reference in a new issue