mirror of
https://github.com/DI0IK/homepage-plus.git
synced 2025-07-18 18:49:50 +00:00
Custom JS and CSS (#1950)
* First commit for custom styles and JS * Adjusted classes * Added ids and classes for services and bookmarks * Apply suggestions from code review * Remove mime dependency * Update settings.json * Detect custom css / js changes, no refresh * Added preload to custom scripts and styles so they can load earlier * Added data attribute name for bookmarks too * Update [path].js * code style, revert some pointer changes --------- Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
parent
0741ef0427
commit
b39c79bea1
46 changed files with 176 additions and 99 deletions
35
src/pages/api/config/[path].js
Normal file
35
src/pages/api/config/[path].js
Normal file
|
@ -0,0 +1,35 @@
|
|||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
import { CONF_DIR } from "utils/config/config";
|
||||
import createLogger from "utils/logger";
|
||||
|
||||
const logger = createLogger("configFileService");
|
||||
|
||||
/**
|
||||
* @param {import("next").NextApiRequest} req
|
||||
* @param {import("next").NextApiResponse} res
|
||||
*/
|
||||
export default async function handler(req, res) {
|
||||
const { path: relativePath } = req.query;
|
||||
|
||||
// only two supported files, for now
|
||||
if (!['custom.css', 'custom.js'].includes(relativePath))
|
||||
{
|
||||
return res.status(422).end('Unsupported file');
|
||||
}
|
||||
|
||||
const filePath = path.join(CONF_DIR, relativePath);
|
||||
|
||||
try {
|
||||
// Read the content of the file or return empty content
|
||||
const fileContent = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '';
|
||||
// hard-coded since we only support two known files for now
|
||||
const mimeType = (relativePath === 'custom.css') ? 'text/css' : 'text/javascript';
|
||||
res.setHeader('Content-Type', mimeType);
|
||||
return res.status(200).send(fileContent);
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return res.status(500).end('Internal Server Error');
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import { readFileSync } from "fs";
|
|||
|
||||
import checkAndCopyConfig, { CONF_DIR } from "utils/config/config";
|
||||
|
||||
const configs = ["docker.yaml", "settings.yaml", "services.yaml", "bookmarks.yaml", "widgets.yaml"];
|
||||
const configs = ["docker.yaml", "settings.yaml", "services.yaml", "bookmarks.yaml", "widgets.yaml", "custom.css", "custom.js"];
|
||||
|
||||
function hash(buffer) {
|
||||
const hashSum = createHash("sha256");
|
||||
|
|
|
@ -8,6 +8,7 @@ import { useEffect, useContext, useState, useMemo } from "react";
|
|||
import { BiError } from "react-icons/bi";
|
||||
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
||||
|
||||
import FileContent from "components/filecontent";
|
||||
import ServicesGroup from "components/services/group";
|
||||
import BookmarksGroup from "components/bookmarks/group";
|
||||
import Widget from "components/widgets/widget";
|
||||
|
@ -239,7 +240,7 @@ function Home({ initialSettings }) {
|
|||
const bookmarkGroups = bookmarks.filter(group => settings.layout?.[group.name] === undefined);
|
||||
|
||||
return <>
|
||||
{layoutGroups.length > 0 && <div key="layoutGroups" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
|
||||
{layoutGroups.length > 0 && <div key="layoutGroups" id="layout-groups" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
|
||||
{layoutGroups.map((group) => (
|
||||
group.services ?
|
||||
(<ServicesGroup
|
||||
|
@ -259,7 +260,7 @@ function Home({ initialSettings }) {
|
|||
)
|
||||
)}
|
||||
</div>}
|
||||
{serviceGroups?.length > 0 && <div key="services" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
|
||||
{serviceGroups?.length > 0 && <div key="services" id="services" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
|
||||
{serviceGroups.map((group) => (
|
||||
<ServicesGroup
|
||||
key={group.name}
|
||||
|
@ -271,7 +272,7 @@ function Home({ initialSettings }) {
|
|||
/>
|
||||
))}
|
||||
</div>}
|
||||
{bookmarkGroups?.length > 0 && <div key="bookmarks" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
|
||||
{bookmarkGroups?.length > 0 && <div key="bookmarks" id="bookmarks" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
|
||||
{bookmarkGroups.map((group) => (
|
||||
<BookmarksGroup
|
||||
key={group.name}
|
||||
|
@ -311,6 +312,24 @@ function Home({ initialSettings }) {
|
|||
<meta name="msapplication-TileColor" content={themes[settings.color || "slate"][settings.theme || "dark"]} />
|
||||
<meta name="theme-color" content={themes[settings.color || "slate"][settings.theme || "dark"]} />
|
||||
</Head>
|
||||
|
||||
<link rel="preload" href="/api/config/custom.css" as="fetch" crossorigin="anonymous" />
|
||||
<style data-name="custom.css">
|
||||
<FileContent path="custom.css"
|
||||
loadingValue="/* Loading custom CSS... */"
|
||||
errorValue="/* Failed to load custom CSS... */"
|
||||
emptyValue="/* No custom CSS */"
|
||||
/>
|
||||
</style>
|
||||
<link rel="preload" href="/api/config/custom.js" as="fetch" crossorigin="anonymous" />
|
||||
<script data-name="custom.js">
|
||||
<FileContent path="custom.js"
|
||||
loadingValue="/* Loading custom JS... */"
|
||||
errorValue="/* Failed to load custom JS... */"
|
||||
emptyValue="/* No custom JS */"
|
||||
/>
|
||||
</script>
|
||||
|
||||
<div className="relative container m-auto flex flex-col justify-start z-10 h-full">
|
||||
<QuickLaunch
|
||||
servicesAndBookmarks={servicesAndBookmarks}
|
||||
|
@ -321,6 +340,7 @@ function Home({ initialSettings }) {
|
|||
searchProvider={settings.quicklaunch?.hideInternetSearch ? null : searchProvider}
|
||||
/>
|
||||
<div
|
||||
id="information-widgets"
|
||||
className={classNames(
|
||||
"flex flex-row flex-wrap justify-between",
|
||||
headerStyles[headerStyle],
|
||||
|
@ -335,7 +355,7 @@ function Home({ initialSettings }) {
|
|||
<Widget key={i} widget={widget} style={{ header: headerStyle, isRightAligned: false, cardBlur: settings.cardBlur }} />
|
||||
))}
|
||||
|
||||
<div className={classNames(
|
||||
<div id="information-widgets-right" className={classNames(
|
||||
"m-auto flex flex-wrap grow sm:basis-auto justify-between md:justify-end",
|
||||
headerStyle === "boxedWidgets" ? "sm:ml-4" : "sm:ml-2"
|
||||
)}>
|
||||
|
@ -351,14 +371,14 @@ function Home({ initialSettings }) {
|
|||
|
||||
{servicesAndBookmarksGroups}
|
||||
|
||||
<div className="flex flex-col mt-auto p-8 w-full">
|
||||
<div className="flex w-full justify-end">
|
||||
<div id="footer" className="flex flex-col mt-auto p-8 w-full">
|
||||
<div id="style" className="flex w-full justify-end">
|
||||
{!settings?.color && <ColorToggle />}
|
||||
<Revalidate />
|
||||
{!settings.theme && <ThemeToggle />}
|
||||
</div>
|
||||
|
||||
<div className="flex mt-4 w-full justify-end">
|
||||
<div id="version" className="flex mt-4 w-full justify-end">
|
||||
{!settings.hideVersion && <Version />}
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue