mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-26 06:11:15 +00:00
Do most of the theme handling from the Theme component (#2390)
* Set data-bs-theme attribute from Theme component * Handle temporary theme changes in Theme component * Fetch theme list on AdminSettings component mount * Include CodeTheme in Theme component * Improve handling of browser-compact theme --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com>
This commit is contained in:
parent
201e5fcd53
commit
9a5f9dd18a
15 changed files with 205 additions and 145 deletions
|
@ -79,6 +79,12 @@ export async function createSsrHtml(
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ${helmet.htmlAttributes.toString()}>
|
<html ${helmet.htmlAttributes.toString()}>
|
||||||
<head>
|
<head>
|
||||||
|
<script nonce="${cspNonce}">
|
||||||
|
if (!document.documentElement.hasAttribute("data-bs-theme")) {
|
||||||
|
const light = window.matchMedia("(prefers-color-scheme: light)").matches;
|
||||||
|
document.documentElement.setAttribute("data-bs-theme", light ? "light" : "dark");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
${lazyScripts}
|
${lazyScripts}
|
||||||
<script nonce="${cspNonce}">window.isoData = ${serialize(isoData)}</script>
|
<script nonce="${cspNonce}">window.isoData = ${serialize(isoData)}</script>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { isAnonymousPath, isAuthPath, setIsoData } from "@utils/app";
|
import { isAnonymousPath, isAuthPath, setIsoData } from "@utils/app";
|
||||||
import { dataBsTheme } from "@utils/browser";
|
|
||||||
import { Component, RefObject, createRef, linkEvent } from "inferno";
|
import { Component, RefObject, createRef, linkEvent } from "inferno";
|
||||||
import { Provider } from "inferno-i18next-dess";
|
import { Provider } from "inferno-i18next-dess";
|
||||||
import { Route, Switch } from "inferno-router";
|
import { Route, Switch } from "inferno-router";
|
||||||
|
@ -14,7 +13,6 @@ import { Navbar } from "./navbar";
|
||||||
import "./styles.scss";
|
import "./styles.scss";
|
||||||
import { Theme } from "./theme";
|
import { Theme } from "./theme";
|
||||||
import AnonymousGuard from "../common/anonymous-guard";
|
import AnonymousGuard from "../common/anonymous-guard";
|
||||||
import { CodeTheme } from "./code-theme";
|
|
||||||
|
|
||||||
export class App extends Component<any, any> {
|
export class App extends Component<any, any> {
|
||||||
private isoData: IsoDataOptionalSite = setIsoData(this.context);
|
private isoData: IsoDataOptionalSite = setIsoData(this.context);
|
||||||
|
@ -36,11 +34,7 @@ export class App extends Component<any, any> {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Provider i18next={I18NextService.i18n}>
|
<Provider i18next={I18NextService.i18n}>
|
||||||
<div
|
<div id="app" className="lemmy-site">
|
||||||
id="app"
|
|
||||||
className="lemmy-site"
|
|
||||||
data-bs-theme={dataBsTheme(siteRes)}
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn skip-link bg-light position-absolute start-0 z-3"
|
className="btn skip-link bg-light position-absolute start-0 z-3"
|
||||||
|
@ -49,10 +43,7 @@ export class App extends Component<any, any> {
|
||||||
{I18NextService.i18n.t("jump_to_content", "Jump to content")}
|
{I18NextService.i18n.t("jump_to_content", "Jump to content")}
|
||||||
</button>
|
</button>
|
||||||
{siteView && (
|
{siteView && (
|
||||||
<>
|
<Theme defaultTheme={siteView.local_site.default_theme} />
|
||||||
<Theme defaultTheme={siteView.local_site.default_theme} />
|
|
||||||
<CodeTheme defaultTheme={siteView.local_site.default_theme} />
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
<Navbar siteRes={siteRes} />
|
<Navbar siteRes={siteRes} />
|
||||||
<div className="mt-4 p-0 fl-1">
|
<div className="mt-4 p-0 fl-1">
|
||||||
|
|
|
@ -1,18 +1,34 @@
|
||||||
import { dataBsTheme } from "@utils/browser";
|
import { dataBsTheme } from "@utils/browser";
|
||||||
import { Component } from "inferno";
|
import { Component } from "inferno";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import { UserService } from "../../services";
|
|
||||||
|
|
||||||
interface CodeThemeProps {
|
interface CodeThemeProps {
|
||||||
defaultTheme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CodeTheme extends Component<CodeThemeProps, any> {
|
export class CodeTheme extends Component<CodeThemeProps, any> {
|
||||||
render() {
|
render() {
|
||||||
const user = UserService.Instance.myUserInfo;
|
const { theme } = this.props;
|
||||||
const userTheme = user?.local_user_view.local_user.theme;
|
const hasTheme = theme !== "browser" && theme !== "browser-compact";
|
||||||
const theme =
|
|
||||||
user && userTheme !== "browser" ? userTheme : this.props.defaultTheme;
|
if (!hasTheme) {
|
||||||
|
return (
|
||||||
|
<Helmet>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
type="text/css"
|
||||||
|
href={`/css/code-themes/atom-one-light.css`}
|
||||||
|
media="(prefers-color-scheme: light)"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
type="text/css"
|
||||||
|
href={`/css/code-themes/atom-one-dark.css`}
|
||||||
|
media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
|
||||||
|
/>
|
||||||
|
</Helmet>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Helmet>
|
<Helmet>
|
||||||
|
|
|
@ -1,76 +1,168 @@
|
||||||
import { Component } from "inferno";
|
import { Component } from "inferno";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import { UserService } from "../../services";
|
import { UserService } from "../../services";
|
||||||
|
import { dataBsTheme, isBrowser } from "@utils/browser";
|
||||||
|
import { CodeTheme } from "./code-theme";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
defaultTheme: string;
|
defaultTheme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Theme extends Component<Props> {
|
interface State {
|
||||||
render() {
|
themeOverride?: string;
|
||||||
const user = UserService.Instance.myUserInfo;
|
graceTheme?: string;
|
||||||
const hasTheme = user?.local_user_view.local_user.theme !== "browser";
|
}
|
||||||
|
|
||||||
if (user && hasTheme) {
|
export class Theme extends Component<Props, State> {
|
||||||
|
private lightQuery?: MediaQueryList;
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
if (isBrowser()) {
|
||||||
|
window.addEventListener("refresh-theme", this.eventListener);
|
||||||
|
window.addEventListener("set-theme-override", this.eventListener);
|
||||||
|
this.lightQuery = window.matchMedia("(prefers-color-scheme: light)");
|
||||||
|
this.lightQuery.addEventListener("change", this.eventListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private graceTimer;
|
||||||
|
private eventListener = e => {
|
||||||
|
if (e.type === "refresh-theme" || e.type === "change") {
|
||||||
|
this.forceUpdate();
|
||||||
|
} else if (e.type === "set-theme-override") {
|
||||||
|
if (e.detail?.theme) {
|
||||||
|
this.setState({
|
||||||
|
themeOverride: e.detail.theme,
|
||||||
|
graceTheme: this.state?.themeOverride ?? this.currentTheme(),
|
||||||
|
});
|
||||||
|
// Keep both themes enabled for one second. Avoids unstyled flashes.
|
||||||
|
clearTimeout(this.graceTimer);
|
||||||
|
this.graceTimer = setTimeout(() => {
|
||||||
|
this.setState({ graceTheme: undefined });
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
this.setState({ themeOverride: undefined, graceTheme: undefined });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
|
if (isBrowser()) {
|
||||||
|
window.removeEventListener("refresh-theme", this.eventListener);
|
||||||
|
this.lightQuery?.removeEventListener("change", this.eventListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTheme(): string {
|
||||||
|
const user = UserService.Instance.myUserInfo;
|
||||||
|
const userTheme = user?.local_user_view.local_user.theme;
|
||||||
|
return userTheme ?? "browser";
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state?.themeOverride) {
|
||||||
|
if (!this.state.graceTheme) {
|
||||||
|
return this.renderTheme(this.state.themeOverride);
|
||||||
|
}
|
||||||
|
// Render both themes to prevent rendering without theme.
|
||||||
|
return [
|
||||||
|
this.renderTheme(this.state.graceTheme ?? this.currentTheme()),
|
||||||
|
this.renderTheme(this.state.themeOverride),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.renderTheme(this.currentTheme());
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTheme(theme: string) {
|
||||||
|
const hasTheme = theme !== "browser" && theme !== "browser-compact";
|
||||||
|
|
||||||
|
const detectedBsTheme = {};
|
||||||
|
if (this.lightQuery) {
|
||||||
|
detectedBsTheme["data-bs-theme"] = this.lightQuery.matches
|
||||||
|
? "light"
|
||||||
|
: "dark";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theme && hasTheme) {
|
||||||
return (
|
return (
|
||||||
<Helmet>
|
<>
|
||||||
<link
|
<Helmet htmlAttributes={{ "data-bs-theme": dataBsTheme(theme) }}>
|
||||||
rel="stylesheet"
|
<link
|
||||||
type="text/css"
|
rel="stylesheet"
|
||||||
href={`/css/themes/${user.local_user_view.local_user.theme}.css`}
|
type="text/css"
|
||||||
/>
|
href={`/css/themes/${theme}.css`}
|
||||||
</Helmet>
|
/>
|
||||||
|
</Helmet>
|
||||||
|
<CodeTheme theme={theme} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.props.defaultTheme !== "browser" &&
|
this.props.defaultTheme !== "browser" &&
|
||||||
this.props.defaultTheme !== "browser-compact"
|
this.props.defaultTheme !== "browser-compact"
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<Helmet>
|
<>
|
||||||
<link
|
<Helmet
|
||||||
rel="stylesheet"
|
htmlAttributes={{
|
||||||
type="text/css"
|
"data-bs-theme": dataBsTheme(this.props.defaultTheme),
|
||||||
href={`/css/themes/${this.props.defaultTheme}.css`}
|
}}
|
||||||
/>
|
>
|
||||||
</Helmet>
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
type="text/css"
|
||||||
|
href={`/css/themes/${this.props.defaultTheme}.css`}
|
||||||
|
/>
|
||||||
|
</Helmet>
|
||||||
|
<CodeTheme theme={this.props.defaultTheme} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
} else if (this.props.defaultTheme === "browser-compact") {
|
} else if (
|
||||||
|
this.props.defaultTheme === "browser-compact" ||
|
||||||
|
theme === "browser-compact"
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<Helmet>
|
<>
|
||||||
<link
|
<Helmet htmlAttributes={detectedBsTheme}>
|
||||||
rel="stylesheet"
|
<link
|
||||||
type="text/css"
|
rel="stylesheet"
|
||||||
href="/css/themes/litely-compact.css"
|
type="text/css"
|
||||||
id="default-light"
|
href="/css/themes/litely-compact.css"
|
||||||
media="(prefers-color-scheme: light)"
|
id="default-light"
|
||||||
/>
|
media="(prefers-color-scheme: light)"
|
||||||
<link
|
/>
|
||||||
rel="stylesheet"
|
<link
|
||||||
type="text/css"
|
rel="stylesheet"
|
||||||
href="/css/themes/darkly-compact.css"
|
type="text/css"
|
||||||
id="default-dark"
|
href="/css/themes/darkly-compact.css"
|
||||||
media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
|
id="default-dark"
|
||||||
/>
|
media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
|
||||||
</Helmet>
|
/>
|
||||||
|
</Helmet>
|
||||||
|
<CodeTheme theme="browser-compact" />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Helmet>
|
<>
|
||||||
<link
|
<Helmet htmlAttributes={detectedBsTheme}>
|
||||||
rel="stylesheet"
|
<link
|
||||||
type="text/css"
|
rel="stylesheet"
|
||||||
href="/css/themes/litely.css"
|
type="text/css"
|
||||||
id="default-light"
|
href="/css/themes/litely.css"
|
||||||
media="(prefers-color-scheme: light)"
|
id="default-light"
|
||||||
/>
|
media="(prefers-color-scheme: light)"
|
||||||
<link
|
/>
|
||||||
rel="stylesheet"
|
<link
|
||||||
type="text/css"
|
rel="stylesheet"
|
||||||
href="/css/themes/darkly.css"
|
type="text/css"
|
||||||
id="default-dark"
|
href="/css/themes/darkly.css"
|
||||||
media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
|
id="default-dark"
|
||||||
/>
|
media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
|
||||||
</Helmet>
|
/>
|
||||||
|
</Helmet>
|
||||||
|
<CodeTheme theme="browser" />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,9 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
if (!this.state.isIsomorphic) {
|
if (!this.state.isIsomorphic) {
|
||||||
await this.fetchData();
|
await this.fetchData();
|
||||||
|
} else {
|
||||||
|
const themeList = await fetchThemeList();
|
||||||
|
this.setState({ themeList });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { setIsoData } from "@utils/app";
|
import { setIsoData } from "@utils/app";
|
||||||
import { isBrowser, updateDataBsTheme } from "@utils/browser";
|
import { isBrowser, refreshTheme } from "@utils/browser";
|
||||||
import { getQueryParams } from "@utils/helpers";
|
import { getQueryParams } from "@utils/helpers";
|
||||||
import { Component, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
import { RouteComponentProps } from "inferno-router/dist/Route";
|
import { RouteComponentProps } from "inferno-router/dist/Route";
|
||||||
|
@ -47,7 +47,7 @@ async function handleLoginSuccess(i: Login, loginRes: LoginResponse) {
|
||||||
|
|
||||||
if (site.state === "success") {
|
if (site.state === "success") {
|
||||||
UserService.Instance.myUserInfo = site.data.my_user;
|
UserService.Instance.myUserInfo = site.data.my_user;
|
||||||
updateDataBsTheme(site.data);
|
refreshTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
const { prev } = getLoginQueryParams();
|
const { prev } = getLoginQueryParams();
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {
|
||||||
myAuth,
|
myAuth,
|
||||||
personToChoice,
|
personToChoice,
|
||||||
setIsoData,
|
setIsoData,
|
||||||
setTheme,
|
|
||||||
showLocal,
|
showLocal,
|
||||||
updateCommunityBlock,
|
updateCommunityBlock,
|
||||||
updateInstanceBlock,
|
updateInstanceBlock,
|
||||||
|
@ -67,7 +66,7 @@ import { PersonListing } from "./person-listing";
|
||||||
import { InitialFetchRequest } from "../../interfaces";
|
import { InitialFetchRequest } from "../../interfaces";
|
||||||
import TotpModal from "../common/totp-modal";
|
import TotpModal from "../common/totp-modal";
|
||||||
import { LoadingEllipses } from "../common/loading-ellipses";
|
import { LoadingEllipses } from "../common/loading-ellipses";
|
||||||
import { updateDataBsTheme } from "../../utils/browser";
|
import { refreshTheme, setThemeOverride } from "../../utils/browser";
|
||||||
import { getHttpBaseInternal } from "../../utils/env";
|
import { getHttpBaseInternal } from "../../utils/env";
|
||||||
|
|
||||||
type SettingsData = RouteDataResponse<{
|
type SettingsData = RouteDataResponse<{
|
||||||
|
@ -342,6 +341,7 @@ export class Settings extends Component<any, SettingsState> {
|
||||||
componentWillUnmount(): void {
|
componentWillUnmount(): void {
|
||||||
// In case `interface_language` change wasn't saved.
|
// In case `interface_language` change wasn't saved.
|
||||||
loadUserLanguage();
|
loadUserLanguage();
|
||||||
|
setThemeOverride(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async fetchInitialData({
|
static async fetchInitialData({
|
||||||
|
@ -1453,7 +1453,7 @@ export class Settings extends Component<any, SettingsState> {
|
||||||
|
|
||||||
handleThemeChange(i: Settings, event: any) {
|
handleThemeChange(i: Settings, event: any) {
|
||||||
i.setState(s => ((s.saveUserSettingsForm.theme = event.target.value), s));
|
i.setState(s => ((s.saveUserSettingsForm.theme = event.target.value), s));
|
||||||
setTheme(event.target.value, true);
|
setThemeOverride(event.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleInterfaceLangChange(i: Settings, event: any) {
|
handleInterfaceLangChange(i: Settings, event: any) {
|
||||||
|
@ -1571,6 +1571,7 @@ export class Settings extends Component<any, SettingsState> {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setThemeOverride(undefined);
|
||||||
i.setState({ saveRes });
|
i.setState({ saveRes });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1665,7 +1666,7 @@ export class Settings extends Component<any, SettingsState> {
|
||||||
} = siteRes.data.my_user!.local_user_view;
|
} = siteRes.data.my_user!.local_user_view;
|
||||||
|
|
||||||
UserService.Instance.myUserInfo = siteRes.data.my_user;
|
UserService.Instance.myUserInfo = siteRes.data.my_user;
|
||||||
updateDataBsTheme(siteRes.data);
|
refreshTheme();
|
||||||
|
|
||||||
i.setState(prev => ({
|
i.setState(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
|
|
@ -44,7 +44,6 @@ import postToCommentSortType from "./post-to-comment-sort-type";
|
||||||
import searchCommentTree from "./search-comment-tree";
|
import searchCommentTree from "./search-comment-tree";
|
||||||
import selectableLanguages from "./selectable-languages";
|
import selectableLanguages from "./selectable-languages";
|
||||||
import setIsoData from "./set-iso-data";
|
import setIsoData from "./set-iso-data";
|
||||||
import setTheme from "./set-theme";
|
|
||||||
import setupDateFns from "./setup-date-fns";
|
import setupDateFns from "./setup-date-fns";
|
||||||
import showAvatars from "./show-avatars";
|
import showAvatars from "./show-avatars";
|
||||||
import showLocal from "./show-local";
|
import showLocal from "./show-local";
|
||||||
|
@ -103,7 +102,6 @@ export {
|
||||||
searchCommentTree,
|
searchCommentTree,
|
||||||
selectableLanguages,
|
selectableLanguages,
|
||||||
setIsoData,
|
setIsoData,
|
||||||
setTheme,
|
|
||||||
setupDateFns,
|
setupDateFns,
|
||||||
showAvatars,
|
showAvatars,
|
||||||
showLocal,
|
showLocal,
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import { GetSiteResponse } from "lemmy-js-client";
|
import { GetSiteResponse } from "lemmy-js-client";
|
||||||
import { setupEmojiDataModel, setupMarkdown } from "../../markdown";
|
import { setupEmojiDataModel, setupMarkdown } from "../../markdown";
|
||||||
import { UserService } from "../../services";
|
import { UserService } from "../../services";
|
||||||
import { updateDataBsTheme } from "@utils/browser";
|
|
||||||
|
|
||||||
export default function initializeSite(site?: GetSiteResponse) {
|
export default function initializeSite(site?: GetSiteResponse) {
|
||||||
UserService.Instance.myUserInfo = site?.my_user;
|
UserService.Instance.myUserInfo = site?.my_user;
|
||||||
updateDataBsTheme(site);
|
|
||||||
if (site) {
|
if (site) {
|
||||||
setupEmojiDataModel(site.custom_emojis ?? []);
|
setupEmojiDataModel(site.custom_emojis ?? []);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import { fetchThemeList } from "@utils/app";
|
|
||||||
import { dataBsTheme, isBrowser, loadCss } from "@utils/browser";
|
|
||||||
|
|
||||||
export default async function setTheme(theme: string, forceReload = false) {
|
|
||||||
if (!isBrowser()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (theme === "browser" && !forceReload) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// This is only run on a force reload
|
|
||||||
if (theme === "browser") {
|
|
||||||
theme = "darkly";
|
|
||||||
}
|
|
||||||
|
|
||||||
const themeList = await fetchThemeList();
|
|
||||||
|
|
||||||
// Unload all the other themes
|
|
||||||
for (var i = 0; i < themeList.length; i++) {
|
|
||||||
const styleSheet = document.getElementById(themeList[i]);
|
|
||||||
if (styleSheet) {
|
|
||||||
styleSheet.setAttribute("disabled", "disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document
|
|
||||||
.getElementById("default-light")
|
|
||||||
?.setAttribute("disabled", "disabled");
|
|
||||||
document.getElementById("default-dark")?.setAttribute("disabled", "disabled");
|
|
||||||
|
|
||||||
// Load the theme dynamically
|
|
||||||
const cssLoc = `/css/themes/${theme}.css`;
|
|
||||||
|
|
||||||
loadCss(theme, cssLoc);
|
|
||||||
document
|
|
||||||
.getElementById("app")
|
|
||||||
?.setAttribute("data-bs-theme", dataBsTheme(theme));
|
|
||||||
document.getElementById(theme)?.removeAttribute("disabled");
|
|
||||||
}
|
|
|
@ -3,13 +3,13 @@ import clearAuthCookie from "./clear-auth-cookie";
|
||||||
import dataBsTheme from "./data-bs-theme";
|
import dataBsTheme from "./data-bs-theme";
|
||||||
import isBrowser from "./is-browser";
|
import isBrowser from "./is-browser";
|
||||||
import isDark from "./is-dark";
|
import isDark from "./is-dark";
|
||||||
import loadCss from "./load-css";
|
|
||||||
import platform from "./platform";
|
import platform from "./platform";
|
||||||
|
import refreshTheme from "./refresh-theme";
|
||||||
import restoreScrollPosition from "./restore-scroll-position";
|
import restoreScrollPosition from "./restore-scroll-position";
|
||||||
import saveScrollPosition from "./save-scroll-position";
|
import saveScrollPosition from "./save-scroll-position";
|
||||||
import setAuthCookie from "./set-auth-cookie";
|
import setAuthCookie from "./set-auth-cookie";
|
||||||
|
import setThemeOverride from "./set-theme-override";
|
||||||
import share from "./share";
|
import share from "./share";
|
||||||
import updateDataBsTheme from "./update-data-bs-theme";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
canShare,
|
canShare,
|
||||||
|
@ -17,11 +17,11 @@ export {
|
||||||
dataBsTheme,
|
dataBsTheme,
|
||||||
isBrowser,
|
isBrowser,
|
||||||
isDark,
|
isDark,
|
||||||
loadCss,
|
|
||||||
platform,
|
platform,
|
||||||
|
refreshTheme,
|
||||||
restoreScrollPosition,
|
restoreScrollPosition,
|
||||||
saveScrollPosition,
|
saveScrollPosition,
|
||||||
setAuthCookie,
|
setAuthCookie,
|
||||||
|
setThemeOverride,
|
||||||
share,
|
share,
|
||||||
updateDataBsTheme,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
export default function loadCss(id: string, loc: string) {
|
|
||||||
if (!document.getElementById(id)) {
|
|
||||||
var head = document.getElementsByTagName("head")[0];
|
|
||||||
var link = document.createElement("link");
|
|
||||||
link.id = id;
|
|
||||||
link.rel = "stylesheet";
|
|
||||||
link.type = "text/css";
|
|
||||||
link.href = loc;
|
|
||||||
link.media = "all";
|
|
||||||
head.appendChild(link);
|
|
||||||
}
|
|
||||||
}
|
|
7
src/shared/utils/browser/refresh-theme.tsx
Normal file
7
src/shared/utils/browser/refresh-theme.tsx
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { isBrowser } from ".";
|
||||||
|
|
||||||
|
export default function refreshTheme() {
|
||||||
|
if (isBrowser()) {
|
||||||
|
window.dispatchEvent(new CustomEvent("refresh-theme"));
|
||||||
|
}
|
||||||
|
}
|
10
src/shared/utils/browser/set-theme-override.ts
Normal file
10
src/shared/utils/browser/set-theme-override.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { isBrowser } from "@utils/browser";
|
||||||
|
|
||||||
|
export default async function setThemeOverride(theme?: string) {
|
||||||
|
if (!isBrowser()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("set-theme-override", { detail: { theme } }),
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
import { GetSiteResponse } from "lemmy-js-client";
|
|
||||||
import isBrowser from "./is-browser";
|
|
||||||
import dataBsTheme from "./data-bs-theme";
|
|
||||||
|
|
||||||
export default function updateDataBsTheme(siteRes?: GetSiteResponse) {
|
|
||||||
if (isBrowser()) {
|
|
||||||
document
|
|
||||||
.getElementById("app")
|
|
||||||
?.setAttribute("data-bs-theme", dataBsTheme(siteRes));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue