update app info part to be at bottom of settings on mobile

This commit is contained in:
Pas 2025-11-07 22:39:56 -07:00
parent 4f781f9736
commit 88f975885c
3 changed files with 133 additions and 113 deletions

View file

@ -39,6 +39,7 @@ import { useSubtitleStore } from "@/stores/subtitles";
import { usePreviewThemeStore, useThemeStore } from "@/stores/theme"; import { usePreviewThemeStore, useThemeStore } from "@/stores/theme";
import { SubPageLayout } from "./layouts/SubPageLayout"; import { SubPageLayout } from "./layouts/SubPageLayout";
import { AppInfoPart } from "./parts/settings/AppInfoPart";
import { PreferencesPart } from "./parts/settings/PreferencesPart"; import { PreferencesPart } from "./parts/settings/PreferencesPart";
function SettingsLayout(props: { function SettingsLayout(props: {
@ -106,6 +107,9 @@ function SettingsLayout(props: {
> >
<SidebarPart /> <SidebarPart />
<div>{props.children}</div> <div>{props.children}</div>
<div className="block lg:hidden">
<AppInfoPart />
</div>
</div> </div>
</WideContainer> </WideContainer>
); );

View file

@ -0,0 +1,123 @@
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { useAsync } from "react-use";
import { getBackendMeta } from "@/backend/accounts/meta";
import { Button } from "@/components/buttons/Button";
import { Icon, Icons } from "@/components/Icon";
import { SidebarSection } from "@/components/layout/Sidebar";
import { useBackendUrl } from "@/hooks/auth/useBackendUrl";
import { conf } from "@/setup/config";
import { useAuthStore } from "@/stores/auth";
function SecureBadge(props: { url: string | null }) {
const { t } = useTranslation();
const secure = props.url ? props.url.startsWith("https://") : false;
return (
<div className="flex items-center gap-1 -mx-1 ml-3 px-1 rounded bg-largeCard-background font-bold">
<Icon icon={secure ? Icons.LOCK : Icons.UNLOCK} />
{t(
secure
? "settings.sidebar.info.secure"
: "settings.sidebar.info.insecure",
)}
</div>
);
}
export function AppInfoPart() {
const { t } = useTranslation();
const { account } = useAuthStore();
// eslint-disable-next-line no-restricted-globals
const hostname = location.hostname;
const navigate = useNavigate();
const backendUrl = useBackendUrl();
const backendMeta = useAsync(async () => {
if (!backendUrl) return;
return getBackendMeta(backendUrl);
}, [backendUrl]);
return (
<SidebarSection
className="text-sm"
title={t("settings.sidebar.info.title")}
>
<div className="px-3 py-3.5 rounded-lg bg-largeCard-background bg-opacity-50 grid grid-cols-2 gap-4">
{/* Hostname */}
<div className="col-span-2 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.sidebar.info.hostname")}
</p>
<p className="text-white">{hostname}</p>
</div>
{/* Backend URL */}
<div className="col-span-2 space-y-1">
<div className="text-type-dimmed font-medium flex items-center">
<p>{t("settings.sidebar.info.backendUrl")}</p>
<SecureBadge url={backendUrl} />
</div>
<p className="text-white">
{backendUrl?.replace(/https?:\/\//, "") ?? "—"}
</p>
</div>
{/* User ID */}
<div className="col-span-2 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.sidebar.info.userId")}
</p>
<p className="text-white">
{account?.userId ?? t("settings.sidebar.info.notLoggedIn")}
</p>
</div>
{/* App version */}
<div className="col-span-1 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.sidebar.info.appVersion")}
</p>
<p className="text-type-dimmed px-2 py-1 rounded bg-settings-sidebar-badge inline-block">
{conf().APP_VERSION}
</p>
</div>
{/* Backend version */}
<div className="col-span-1 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.sidebar.info.backendVersion")}
</p>
<p className="text-type-dimmed px-2 py-1 rounded bg-settings-sidebar-badge inline-flex items-center gap-1">
{backendMeta.error ? (
<Icon
icon={Icons.WARNING}
className="text-type-danger text-base"
/>
) : null}
{backendMeta.loading ? (
<span className="block h-4 w-12 bg-type-dimmed/20 rounded" />
) : (
backendMeta?.value?.version ||
t("settings.sidebar.info.unknownVersion")
)}
</p>
</div>
<div className="col-span-2 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.account.admin.title")}
</p>
<Button
theme="secondary"
onClick={() => navigate("/admin")}
className="w-full !p-2 text-xs"
>
{t("settings.account.admin.text")}
</Button>
</div>
</div>
</SidebarSection>
);
}

View file

@ -1,44 +1,20 @@
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import Sticky from "react-sticky-el"; import Sticky from "react-sticky-el";
import { useAsync } from "react-use";
import { getBackendMeta } from "@/backend/accounts/meta"; import { Icons } from "@/components/Icon";
import { Button } from "@/components/buttons/Button";
import { Icon, Icons } from "@/components/Icon";
import { SidebarLink, SidebarSection } from "@/components/layout/Sidebar"; import { SidebarLink, SidebarSection } from "@/components/layout/Sidebar";
import { Divider } from "@/components/utils/Divider"; import { Divider } from "@/components/utils/Divider";
import { useBackendUrl } from "@/hooks/auth/useBackendUrl";
import { useIsMobile } from "@/hooks/useIsMobile"; import { useIsMobile } from "@/hooks/useIsMobile";
import { conf } from "@/setup/config";
import { useAuthStore } from "@/stores/auth"; import { AppInfoPart } from "./AppInfoPart";
const rem = 16; const rem = 16;
function SecureBadge(props: { url: string | null }) {
const { t } = useTranslation();
const secure = props.url ? props.url.startsWith("https://") : false;
return (
<div className="flex items-center gap-1 -mx-1 ml-3 px-1 rounded bg-largeCard-background font-bold">
<Icon icon={secure ? Icons.LOCK : Icons.UNLOCK} />
{t(
secure
? "settings.sidebar.info.secure"
: "settings.sidebar.info.insecure",
)}
</div>
);
}
export function SidebarPart() { export function SidebarPart() {
const { t } = useTranslation(); const { t } = useTranslation();
const { isMobile } = useIsMobile(); const { isMobile } = useIsMobile();
const { account } = useAuthStore();
// eslint-disable-next-line no-restricted-globals
const hostname = location.hostname;
const [activeLink, setActiveLink] = useState(""); const [activeLink, setActiveLink] = useState("");
const navigate = useNavigate();
const settingLinks = [ const settingLinks = [
{ {
@ -68,13 +44,6 @@ export function SidebarPart() {
}, },
]; ];
const backendUrl = useBackendUrl();
const backendMeta = useAsync(async () => {
if (!backendUrl) return;
return getBackendMeta(backendUrl);
}, [backendUrl]);
useEffect(() => { useEffect(() => {
function recheck() { function recheck() {
const windowHeight = const windowHeight =
@ -143,85 +112,9 @@ export function SidebarPart() {
</SidebarSection> </SidebarSection>
<Divider /> <Divider />
</div> </div>
<SidebarSection <div className="hidden lg:block">
className="text-sm" <AppInfoPart />
title={t("settings.sidebar.info.title")} </div>
>
<div className="px-3 py-3.5 rounded-lg bg-largeCard-background bg-opacity-50 grid grid-cols-2 gap-4">
{/* Hostname */}
<div className="col-span-2 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.sidebar.info.hostname")}
</p>
<p className="text-white">{hostname}</p>
</div>
{/* Backend URL */}
<div className="col-span-2 space-y-1">
<div className="text-type-dimmed font-medium flex items-center">
<p>{t("settings.sidebar.info.backendUrl")}</p>
<SecureBadge url={backendUrl} />
</div>
<p className="text-white">
{backendUrl?.replace(/https?:\/\//, "") ?? "—"}
</p>
</div>
{/* User ID */}
<div className="col-span-2 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.sidebar.info.userId")}
</p>
<p className="text-white">
{account?.userId ?? t("settings.sidebar.info.notLoggedIn")}
</p>
</div>
{/* App version */}
<div className="col-span-1 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.sidebar.info.appVersion")}
</p>
<p className="text-type-dimmed px-2 py-1 rounded bg-settings-sidebar-badge inline-block">
{conf().APP_VERSION}
</p>
</div>
{/* Backend version */}
<div className="col-span-1 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.sidebar.info.backendVersion")}
</p>
<p className="text-type-dimmed px-2 py-1 rounded bg-settings-sidebar-badge inline-flex items-center gap-1">
{backendMeta.error ? (
<Icon
icon={Icons.WARNING}
className="text-type-danger text-base"
/>
) : null}
{backendMeta.loading ? (
<span className="block h-4 w-12 bg-type-dimmed/20 rounded" />
) : (
backendMeta?.value?.version ||
t("settings.sidebar.info.unknownVersion")
)}
</p>
</div>
<div className="col-span-2 space-y-1">
<p className="text-type-dimmed font-medium">
{t("settings.account.admin.title")}
</p>
<Button
theme="secondary"
onClick={() => navigate("/admin")}
className="w-full !p-2 text-xs"
>
{t("settings.account.admin.text")}
</Button>
</div>
</div>
</SidebarSection>
</Sticky> </Sticky>
</div> </div>
); );