feat: remove dark mode toggle, switch to prefers-color-scheme
This means it's not possible to manually change the theme, but all major operating systems support global dark mode now, so it shouldn't be a huge problem. Will re-add the dark mode toggle if the Sec-CH-Prefers-Color-Scheme header gets added to Firefox and Safari.
This commit is contained in:
parent
862a64840e
commit
0f3ab19f6f
9 changed files with 25 additions and 64 deletions
|
@ -1,20 +1,7 @@
|
|||
$font-family-sans-serif:
|
||||
"FiraGO",
|
||||
system-ui,
|
||||
-apple-system,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
"Helvetica Neue",
|
||||
"Noto Sans",
|
||||
"Liberation Sans",
|
||||
Arial,
|
||||
sans-serif,
|
||||
"Apple Color Emoji",
|
||||
"Segoe UI Emoji",
|
||||
"Segoe UI Symbol",
|
||||
"Noto Color Emoji" !default;
|
||||
|
||||
@import "bootstrap/scss/bootstrap";
|
||||
@use "bootstrap/scss/bootstrap" with (
|
||||
$color-mode-type: media-query,
|
||||
$font-family-sans-serif: ("FiraGO", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"),
|
||||
);
|
||||
|
||||
@import "@fontsource/firago/400.css";
|
||||
@import "@fontsource/firago/400-italic.css";
|
||||
|
|
|
@ -3,9 +3,9 @@ import { Nav, Navbar } from "react-bootstrap";
|
|||
import { Link } from "@remix-run/react";
|
||||
import Logo from "~/components/nav/Logo";
|
||||
|
||||
export default function BaseNavbar({ children, theme }: { children?: ReactNode; theme: string }) {
|
||||
export default function BaseNavbar({ children }: { children?: ReactNode; }) {
|
||||
return (
|
||||
<Navbar expand="lg" className={`mb-4 mx-2 bg-${theme}`} color={theme} variant={theme}>
|
||||
<Navbar expand="lg" className={`mb-4 mx-2`}>
|
||||
<Navbar.Brand to="/" as={Link}>
|
||||
<Logo />
|
||||
</Navbar.Brand>
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
import { Link, useFetcher } from "@remix-run/react";
|
||||
import Meta from "~/lib/api/meta";
|
||||
import { User, UserSettings } from "~/lib/api/user";
|
||||
import { User } from "~/lib/api/user";
|
||||
|
||||
import { Nav, NavDropdown } from "react-bootstrap";
|
||||
import { BrightnessHigh, BrightnessHighFill, MoonFill } from "react-bootstrap-icons";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import BaseNavbar from "~/components/nav/BaseNavbar";
|
||||
|
||||
export default function MainNavbar({
|
||||
user,
|
||||
settings,
|
||||
}: {
|
||||
meta: Meta;
|
||||
user?: User;
|
||||
settings: UserSettings;
|
||||
}) {
|
||||
const fetcher = useFetcher();
|
||||
const { t } = useTranslation();
|
||||
|
@ -39,38 +36,9 @@ export default function MainNavbar({
|
|||
</Nav.Link>
|
||||
);
|
||||
|
||||
const ThemeIcon =
|
||||
settings.dark_mode === null
|
||||
? BrightnessHigh
|
||||
: settings.dark_mode
|
||||
? MoonFill
|
||||
: BrightnessHighFill;
|
||||
|
||||
const theme = settings.dark_mode ? "dark" : "light";
|
||||
|
||||
return (
|
||||
<BaseNavbar theme={theme}>
|
||||
<BaseNavbar>
|
||||
{userMenu}
|
||||
<fetcher.Form method="POST" action="/dark-mode">
|
||||
<NavDropdown
|
||||
title={
|
||||
<>
|
||||
<ThemeIcon /> {t("navbar.theme")}
|
||||
</>
|
||||
}
|
||||
align="end"
|
||||
>
|
||||
<NavDropdown.Item as="button" name="theme" value="auto" type="submit">
|
||||
{t("navbar.theme-auto")}
|
||||
</NavDropdown.Item>
|
||||
<NavDropdown.Item as="button" name="theme" value="dark" type="submit">
|
||||
{t("navbar.theme-dark")}
|
||||
</NavDropdown.Item>
|
||||
<NavDropdown.Item as="button" name="theme" value="light" type="submit">
|
||||
{t("navbar.theme-light")}
|
||||
</NavDropdown.Item>
|
||||
</NavDropdown>
|
||||
</fetcher.Form>
|
||||
</BaseNavbar>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
|
|||
};
|
||||
|
||||
export function Layout({ children }: { children: ReactNode }) {
|
||||
const { locale, settings } = useRouteLoaderData<typeof loader>("root") || {
|
||||
const { locale } = useRouteLoaderData<typeof loader>("root") || {
|
||||
meta: {
|
||||
users: {
|
||||
total: 0,
|
||||
|
@ -77,7 +77,6 @@ export function Layout({ children }: { children: ReactNode }) {
|
|||
return (
|
||||
<html
|
||||
lang={locale || "en"}
|
||||
data-bs-theme={settings?.dark_mode ? "dark" : "light"}
|
||||
dir={i18n.dir()}
|
||||
>
|
||||
<head>
|
||||
|
@ -119,10 +118,10 @@ export function ErrorBoundary() {
|
|||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
{data?.meUser && data?.settings && data?.meta ? (
|
||||
<Navbar meta={data.meta} user={data.meUser} settings={data.settings} />
|
||||
{data?.meUser && data?.meta ? (
|
||||
<Navbar meta={data.meta} user={data.meUser} />
|
||||
) : (
|
||||
<BaseNavbar theme="light" />
|
||||
<BaseNavbar />
|
||||
)}
|
||||
<Container>{errorElem}</Container>
|
||||
<Scripts />
|
||||
|
|
|
@ -13,7 +13,7 @@ import PronounLink from "~/components/PronounLink";
|
|||
export const meta: MetaFunction<typeof loader> = ({ data }) => {
|
||||
const { user } = data!;
|
||||
|
||||
return [{ title: `@${user.username} - pronouns.cc` }];
|
||||
return [{ title: `@${user.username} • pronouns.cc` }];
|
||||
};
|
||||
|
||||
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
||||
|
|
|
@ -21,7 +21,7 @@ import ErrorAlert from "~/components/ErrorAlert";
|
|||
import i18n from "~/i18next.server";
|
||||
|
||||
export const meta: MetaFunction<typeof loader> = ({ data }) => {
|
||||
return [{ title: `${data?.meta.title || "Log in"} - pronouns.cc` }];
|
||||
return [{ title: `${data?.meta.title || "Log in"} • pronouns.cc` }];
|
||||
};
|
||||
|
||||
export const shouldRevalidate: ShouldRevalidateFunction = ({ actionResult }) => {
|
||||
|
|
|
@ -21,7 +21,7 @@ import ErrorAlert from "~/components/ErrorAlert";
|
|||
import { User } from "~/lib/api/user";
|
||||
|
||||
export const meta: MetaFunction<typeof loader> = ({ data }) => {
|
||||
return [{ title: `${data?.meta.title || "Log in"} - pronouns.cc` }];
|
||||
return [{ title: `${data?.meta.title || "Log in"} • pronouns.cc` }];
|
||||
};
|
||||
|
||||
export const shouldRevalidate: ShouldRevalidateFunction = ({ actionResult }) => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Link, useLoaderData } from "@remix-run/react";
|
|||
import { Button } from "react-bootstrap";
|
||||
|
||||
export const meta: MetaFunction<typeof loader> = ({ data }) => {
|
||||
return [{ title: `${data?.meta.title || "Welcome"} - pronouns.cc` }];
|
||||
return [{ title: `${data?.meta.title || "Welcome"} • pronouns.cc` }];
|
||||
};
|
||||
|
||||
export const loader = async ({ request }: LoaderFunctionArgs) => {
|
||||
|
|
|
@ -4,6 +4,13 @@ import serverRequest, { getCookie, writeCookie } from "~/lib/request.server";
|
|||
|
||||
// Handles theme switching
|
||||
// Remix itself handles redirecting back to the original page after the setting is set
|
||||
//
|
||||
// Note: this function is currently unused. Bootstrap only lets us switch themes with either prefers-color-scheme
|
||||
// *or* a programmatic switch using data-bs-theme, not both.
|
||||
// If the Sec-CH-Prefers-Color-Scheme header (https://caniuse.com/mdn-http_headers_sec-ch-prefers-color-scheme)
|
||||
// is added to Firefox and Safari, the dark mode setting should be reworked to use it instead.
|
||||
// As it stands, using prefers-color-scheme is the only way
|
||||
// to respect the operating system's dark mode setting without using JavaScript.
|
||||
export const action: ActionFunction = async ({ request }) => {
|
||||
const body = await request.formData();
|
||||
const theme = (body.get("theme") as string | null) || "auto";
|
||||
|
@ -13,7 +20,7 @@ export const action: ActionFunction = async ({ request }) => {
|
|||
await serverRequest<UserSettings>("PATCH", "/users/@me/settings", {
|
||||
token,
|
||||
body: {
|
||||
dark_mode: theme === "auto" ? null : theme === "dark" ? true : false,
|
||||
dark_mode: theme === "auto" ? null : theme === "dark",
|
||||
},
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue