diff --git a/apps/client/src/common/api/constants.ts b/apps/client/src/common/api/constants.ts
index aad81975f..3998e9800 100644
--- a/apps/client/src/common/api/constants.ts
+++ b/apps/client/src/common/api/constants.ts
@@ -13,6 +13,7 @@ export const RUNDOWN = ['rundown'];
export const RUNTIME = ['runtimeStore'];
export const URL_PRESETS = ['urlpresets'];
export const VIEW_SETTINGS = ['viewSettings'];
+export const CSS_OVERRIDE = ['cssOverride'];
export const CLIENT_LIST = ['clientList'];
export const REPORT = ['report'];
export const TRANSLATION = ['translation'];
@@ -21,9 +22,7 @@ export const TRANSLATION = ['translation'];
export const apiEntryUrl = `${serverURL}/data`;
const userAssetsPath = 'user';
-const cssOverridePath = 'styles/override.css';
const customTranslationsPath = 'translations/translations.json';
-export const overrideStylesURL = `${serverURL}/${userAssetsPath}/${cssOverridePath}`;
export const projectLogoPath = `${serverURL}/${userAssetsPath}/logo`;
export const customTranslationsURL = `${serverURL}/${userAssetsPath}/${customTranslationsPath}`;
diff --git a/apps/client/src/common/hooks-query/useCssOverride.ts b/apps/client/src/common/hooks-query/useCssOverride.ts
new file mode 100644
index 000000000..0ee332362
--- /dev/null
+++ b/apps/client/src/common/hooks-query/useCssOverride.ts
@@ -0,0 +1,18 @@
+import { useQuery } from '@tanstack/react-query';
+import { MILLIS_PER_HOUR } from 'ontime-utils';
+
+import { getCSSContents } from '../api/assets';
+import { CSS_OVERRIDE } from '../api/constants';
+
+export default function useCssOverride(enabled: boolean) {
+ const { data, status } = useQuery({
+ queryKey: CSS_OVERRIDE,
+ queryFn: ({ signal }) => getCSSContents({ signal }),
+ staleTime: MILLIS_PER_HOUR,
+ enabled
+ });
+
+ return {
+ data: data ?? '', status
+ };
+}
diff --git a/apps/client/src/common/utils/socket.ts b/apps/client/src/common/utils/socket.ts
index 52416977b..ce7520e98 100644
--- a/apps/client/src/common/utils/socket.ts
+++ b/apps/client/src/common/utils/socket.ts
@@ -13,6 +13,7 @@ import { isProduction, websocketUrl } from '../../externals';
import {
APP_SETTINGS,
CLIENT_LIST,
+ CSS_OVERRIDE,
CUSTOM_FIELDS,
PROJECT_DATA,
REPORT,
@@ -199,6 +200,9 @@ export const connectSocket = () => {
case RefetchKey.ViewSettings:
ontimeQueryClient.invalidateQueries({ queryKey: VIEW_SETTINGS });
break;
+ case RefetchKey.CssOverride:
+ ontimeQueryClient.invalidateQueries({ queryKey: CSS_OVERRIDE });
+ break;
case RefetchKey.Translation:
ontimeQueryClient.invalidateQueries({ queryKey: TRANSLATION });
break;
diff --git a/apps/client/src/views/ViewLoader.tsx b/apps/client/src/views/ViewLoader.tsx
index 2b72c03a7..6743492d9 100644
--- a/apps/client/src/views/ViewLoader.tsx
+++ b/apps/client/src/views/ViewLoader.tsx
@@ -1,35 +1,39 @@
-import { PropsWithChildren } from 'react';
+import { PropsWithChildren, Suspense } from 'react';
-import { overrideStylesURL } from '../common/api/constants';
+import useCssOverride from '../common/hooks-query/useCssOverride';
import useViewSettings from '../common/hooks-query/useViewSettings';
-import { useRuntimeStylesheet } from '../common/hooks/useRuntimeStylesheet';
import Loader from './common/loader/Loader';
-export default function ViewLoader({ children }: PropsWithChildren) {
- const { data } = useViewSettings();
- const { shouldRender } = useRuntimeStylesheet(data.overrideStyles ? overrideStylesURL : undefined);
+const scriptTagId = 'ontime-stylesheet-override';
+function OverrideStyles() {
+ 'use memo';
+ const { data: settings } = useViewSettings();
+ const { overrideStyles } = settings;
+ const { data: css } = useCssOverride(overrideStyles);
+ const cssBlob = URL.createObjectURL(new Blob([css], { type: 'text/css' }));
+
+ //@ts-expect-error disabled exists on link when rel='stylesheet' https://react.dev/reference/react-dom/components/link#props
+ return ;
+}
+
+export default function ViewLoader({ children }: PropsWithChildren) {
+ 'use memo';
// we need to be able to override the background colour with the key param
const searchParams = new URLSearchParams(window.location.search);
const colourFromParams = searchParams.get('keyColour') ?? '#101010';
- // eventually we would want to leverage suspense here
- // while the feature is not ready, we simply trigger a loader
- // suspense would have the advantage of being triggered also by react-query
-
- if (!shouldRender) {
- return (
- <>
-
-
- >
- );
- }
-
return (
- <>
-
+
+
+
+ >
+ }
+ >
+
{children}
- >
+
);
}
diff --git a/apps/server/src/api-data/assets/assets.router.ts b/apps/server/src/api-data/assets/assets.router.ts
index 2a3ca199d..c664edccc 100644
--- a/apps/server/src/api-data/assets/assets.router.ts
+++ b/apps/server/src/api-data/assets/assets.router.ts
@@ -24,6 +24,7 @@ router.post('/css', validatePostCss, async (req: Request, res: Response) => {
try {
await writeCssFile(defaultCss);
+ sendRefetch(RefetchKey.CssOverride);
res.status(200).send(defaultCss);
} catch (error) {
const message = getErrorMessage(error);
diff --git a/packages/types/src/api/websocket/refetch.type.ts b/packages/types/src/api/websocket/refetch.type.ts
index fdaac6b75..b78f5bf9a 100644
--- a/packages/types/src/api/websocket/refetch.type.ts
+++ b/packages/types/src/api/websocket/refetch.type.ts
@@ -6,6 +6,7 @@ export enum RefetchKey {
Rundown = 'rundown',
UrlPresets = 'url-presets',
ViewSettings = 'view-settings',
+ CssOverride = 'css-override',
Translation = 'translation',
Settings = 'settings',
}