remove utils
All checks were successful
/ depoly (push) Successful in 1m22s

* add ~platform/DocumentTitle
* add titles for some pages
This commit is contained in:
thislight 2025-01-02 22:43:37 +08:00
parent 1115135380
commit 1c8a3f0bbb
No known key found for this signature in database
GPG key ID: FCFE5192241CCD4E
12 changed files with 843 additions and 823 deletions

View file

@ -8,13 +8,13 @@ import {
} from "solid-js";
import { acceptAccountViaAuthCode } from "./stores";
import { $settings } from "../settings/stores";
import { useDocumentTitle } from "../utils";
import cards from "~material/cards.module.css";
import { LinearProgress } from "@suid/material";
import Img from "~material/Img";
import { createRestAPIClient } from "masto";
import { Title } from "~material/typography";
import { useNavigator } from "~platform/StackedRouter";
import DocumentTitle from "~platform/DocumentTitle";
type OAuth2CallbackParams = {
code?: string;
@ -27,13 +27,12 @@ const MastodonOAuth2Callback: Component = () => {
const titleId = createUniqueId();
const [params] = useSearchParams<OAuth2CallbackParams>();
const { push: navigate } = useNavigator();
const setDocumentTitle = useDocumentTitle("Back from Mastodon...");
const [siteImg, setSiteImg] = createSignal<{
src: string;
srcset?: string;
blurhash: string;
}>();
const [siteTitle, setSiteTitle] = createSignal("the Mastodon server");
const [siteTitle, setSiteTitle] = createSignal("Mastodon");
onMount(async () => {
const onGoingOAuth2Process = $settings.get().onGoingOAuth2Process;
@ -42,7 +41,6 @@ const MastodonOAuth2Callback: Component = () => {
url: onGoingOAuth2Process,
});
const ins = await client.v2.instance.fetch();
setDocumentTitle(`Back from ${ins.title}...`);
setSiteTitle(ins.title);
const srcset = [];
@ -93,6 +91,8 @@ const MastodonOAuth2Callback: Component = () => {
});
});
return (
<>
<DocumentTitle>Back from {siteTitle()}</DocumentTitle>
<div class={cards.layoutCentered}>
<div class={cards.card} aria-busy="true" aria-describedby={progressId}>
<LinearProgress
@ -129,6 +129,7 @@ const MastodonOAuth2Callback: Component = () => {
</p>
</div>
</div>
</>
);
};

View file

@ -2,7 +2,6 @@ import {
Component,
Show,
createEffect,
createSelector,
createSignal,
createUniqueId,
onMount,
@ -10,15 +9,14 @@ import {
import cards from "~material/cards.module.css";
import TextField from "~material/TextField.js";
import Button from "~material/Button.js";
import { useDocumentTitle } from "../utils";
import { Title } from "~material/typography";
import { css } from "solid-styled";
import { LinearProgress } from "@suid/material";
import { createRestAPIClient } from "masto";
import { getOrRegisterApp } from "./stores";
import { useSearchParams } from "@solidjs/router";
import { $settings } from "../settings/stores";
import "./SignIn.css";
import DocumentTitle from "~platform/DocumentTitle";
type ErrorParams = {
error: string;
@ -36,8 +34,6 @@ const SignIn: Component = () => {
const [serverUrlError, setServerUrlError] = createSignal(false);
const [targetSiteTitle, setTargetSiteTitle] = createSignal("");
useDocumentTitle("Sign In");
const serverUrl = () => {
const url = rawServerUrl();
if (url.length === 0 || /^%w:/.test(url)) {
@ -115,6 +111,8 @@ const SignIn: Component = () => {
};
return (
<>
<DocumentTitle>Sign In</DocumentTitle>
<main class="SignIn">
<Show when={params.error || params.errorDescription}>
<div class={cards.card} style={{ "margin-bottom": "20px" }}>
@ -164,6 +162,7 @@ const SignIn: Component = () => {
</form>
</div>
</main>
</>
);
};

View file

@ -3,14 +3,12 @@ import {
splitProps,
Component,
createSignal,
createEffect,
onMount,
createRenderEffect,
Show,
} from "solid-js";
import { css } from "solid-styled";
import { decode } from "blurhash";
import { mergeClass } from "../utils";
type ImgProps = {
blurhash?: string;
@ -24,6 +22,7 @@ const Img: Component<ImgProps> = (props) => {
"blurhash",
"keepBlur",
"class",
"classList",
"style",
]);
const [isImgLoaded, setIsImgLoaded] = createSignal(false);
@ -61,21 +60,21 @@ const Img: Component<ImgProps> = (props) => {
const onImgLoaded = () => {
setIsImgLoaded(true);
setImgSize({
width: imgE.width,
height: imgE.height,
width: imgE!.width,
height: imgE!.height,
});
};
const onMetadataLoaded = () => {
setImgSize({
width: imgE.width,
height: imgE.height,
width: imgE!.width,
height: imgE!.height,
});
};
onMount(() => {
setImgSize((x) => {
const parent = imgE.parentElement;
const parent = imgE!.parentElement;
if (!parent) return x;
return x
? x
@ -87,7 +86,14 @@ const Img: Component<ImgProps> = (props) => {
});
return (
<div class={mergeClass(managed.class, "img-root")} style={managed.style}>
<div
classList={{
...managed.classList,
[managed.class ?? ""]: true,
"img-root": true,
}}
style={managed.style}
>
<Show when={managed.blurhash}>
<canvas
ref={(canvas) => {

View file

@ -0,0 +1,22 @@
import { children, createRenderEffect, onCleanup, type JSX } from "solid-js";
/**
* Document title.
*
* The `children` must be plain text.
*/
export default function (props: { children?: JSX.Element }) {
let otitle: string | undefined;
createRenderEffect(() => (otitle = document.title));
const title = children(() => props.children);
createRenderEffect(
() => (document.title = (title.toArray() as string[]).join("")),
);
onCleanup(() => (document.title = otitle!));
return <></>;
}

View file

@ -65,6 +65,7 @@ import {
} from "../timelines/toots/ItemSelectionProvider";
import AppTopBar from "~material/AppTopBar";
import type { Account } from "../accounts/stores";
import DocumentTitle from "~platform/DocumentTitle";
const Profile: Component = () => {
const { pop } = useNavigator();
@ -216,6 +217,8 @@ const Profile: Component = () => {
};
return (
<>
<DocumentTitle>{profile()?.displayName ?? "Someone"}</DocumentTitle>
<Scaffold
topbar={
<AppTopBar
@ -389,7 +392,9 @@ const Profile: Component = () => {
aria-label={`${relationship()?.following ? "Unfollow" : "Follow"} on your home timeline`}
>
<ListItemAvatar>
<Avatar src={(session().account as Account).inf?.avatar}></Avatar>
<Avatar
src={(session().account as Account).inf?.avatar}
></Avatar>
</ListItemAvatar>
<ListItemText
secondary={
@ -565,6 +570,7 @@ const Profile: Component = () => {
</Show>
</div>
</Scaffold>
</>
);
};

View file

@ -26,6 +26,7 @@ import { useStore } from "@nanostores/solid";
import { $settings } from "./stores";
import { useNavigator } from "~platform/StackedRouter";
import AppTopBar from "~material/AppTopBar";
import DocumentTitle from "~platform/DocumentTitle";
const ChooseLang: Component = () => {
const { pop } = useNavigator();
@ -53,6 +54,8 @@ const ChooseLang: Component = () => {
};
return (
<>
<DocumentTitle>{t("Choose Language")}</DocumentTitle>
<Scaffold
topbar={
<AppTopBar>
@ -114,6 +117,7 @@ const ChooseLang: Component = () => {
</List>
</List>
</Scaffold>
</>
);
};

View file

@ -19,6 +19,7 @@ import { useStore } from "@nanostores/solid";
import { $settings } from "./stores";
import { useNavigator } from "~platform/StackedRouter";
import AppTopBar from "~material/AppTopBar";
import DocumentTitle from "~platform/DocumentTitle";
const Motions: Component = () => {
const { pop } = useNavigator();
@ -30,6 +31,8 @@ const Motions: Component = () => {
);
const settings = useStore($settings);
return (
<>
<DocumentTitle>{t("motions")}</DocumentTitle>
<Scaffold
topbar={
<AppTopBar>
@ -79,6 +82,7 @@ const Motions: Component = () => {
</li>
</List>
</Scaffold>
</>
);
};

View file

@ -24,6 +24,7 @@ import { $settings } from "./stores";
import { useStore } from "@nanostores/solid";
import { useNavigator } from "~platform/StackedRouter";
import AppTopBar from "~material/AppTopBar";
import DocumentTitle from "~platform/DocumentTitle";
const ChooseRegion: Component = () => {
const { pop } = useNavigator();
@ -48,6 +49,8 @@ const ChooseRegion: Component = () => {
};
return (
<>
<DocumentTitle>{t("Choose Region")}</DocumentTitle>
<Scaffold
topbar={
<AppTopBar>
@ -101,6 +104,7 @@ const ChooseRegion: Component = () => {
</List>
</List>
</Scaffold>
</>
);
};

View file

@ -41,6 +41,7 @@ import { makeAcctText, useSessions } from "../masto/clients.js";
import { useNavigator } from "~platform/StackedRouter.jsx";
import AppTopBar from "~material/AppTopBar.jsx";
import MastodonLogo from "./MastodonLogo.jsx";
import DocumentTitle from "~platform/DocumentTitle.jsx";
type Inset = {
top?: number;
@ -197,6 +198,8 @@ const Settings: Component = () => {
}
`;
return (
<>
<DocumentTitle>{t("Settings")}</DocumentTitle>
<Scaffold
topbar={
<AppTopBar>
@ -416,6 +419,7 @@ const Settings: Component = () => {
)}
</List>
</Scaffold>
</>
);
};

View file

@ -5,7 +5,6 @@ import {
createEffect,
useTransition,
} from "solid-js";
import { useDocumentTitle } from "../utils";
import Scaffold from "~material/Scaffold";
import {
ListItemSecondaryAction,
@ -30,6 +29,7 @@ import {
import AppTopBar from "~material/AppTopBar";
import { createTranslator } from "~platform/i18n";
import { useWindowSize } from "@solid-primitives/resize-observer";
import DocumentTitle from "~platform/DocumentTitle";
type StringRes = Record<
"tabs.home" | "tabs.trending" | "tabs.public" | "set.prefetch-toots",
@ -38,7 +38,6 @@ type StringRes = Record<
const Home: ParentComponent = (props) => {
let panelList: HTMLDivElement;
useDocumentTitle("Timelines");
const [t] = createTranslator(
(code) => import(`./i18n/${code}.json`) as Promise<{ default: StringRes }>,
);
@ -179,6 +178,7 @@ const Home: ParentComponent = (props) => {
return (
<>
<DocumentTitle>Timelines</DocumentTitle>
<Scaffold
topbar={
<AppTopBar>

View file

@ -14,7 +14,6 @@ import cards from "~material/cards.module.css";
import { css } from "solid-styled";
import { createTimeSource, TimeSourceProvider } from "~platform/timesrc";
import TootComposer from "./TootComposer";
import { useDocumentTitle } from "../utils";
import { createTimelineControlsForArray } from "../masto/timelines";
import TootList from "./TootList";
import "./TootBottomSheet.css";
@ -26,6 +25,7 @@ import ItemSelectionProvider, {
import AppTopBar from "~material/AppTopBar";
import { fetchStatus } from "../masto/statuses";
import { type Account } from "../accounts/stores";
import DocumentTitle from "~platform/DocumentTitle";
const TootBottomSheet: Component = (props) => {
const params = useParams<{ acct: string; id: string }>();
@ -65,11 +65,11 @@ const TootBottomSheet: Component = (props) => {
() => tootContext()?.descendants,
);
useDocumentTitle(() => {
const documentTitle = () => {
const t = toot()?.reblog ?? toot();
const name = t?.account.displayName ?? "Someone";
return `${name}'s toot`;
});
};
const tootDisplayName = () => {
const t = toot()?.reblog ?? toot();
@ -163,6 +163,7 @@ const TootBottomSheet: Component = (props) => {
}
class="TootBottomSheet"
>
<DocumentTitle>{documentTitle()}</DocumentTitle>
<div class="Scrollable">
<TimeSourceProvider value={time}>
<ItemSelectionProvider value={selectionState}>

View file

@ -1,31 +0,0 @@
import {
createRenderEffect,
onCleanup,
type Accessor,
} from "solid-js";
export function useDocumentTitle(newTitle?: string | Accessor<string>) {
const capturedTitle = document.title;
createRenderEffect(() => {
if (newTitle)
document.title = typeof newTitle === "string" ? newTitle : newTitle();
});
onCleanup(() => {
document.title = capturedTitle;
});
return (x: ((x: string) => string) | string) =>
(document.title = typeof x === "string" ? x : x(document.title));
}
export function mergeClass(c1: string | undefined, c2: string | undefined) {
if (!c1) {
return c2;
}
if (!c2) {
return c1;
}
return [c1, c2].join(" ");
}