* add ~platform/DocumentTitle * add titles for some pages
This commit is contained in:
parent
1115135380
commit
1c8a3f0bbb
12 changed files with 843 additions and 823 deletions
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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) => {
|
||||
|
|
22
src/platform/DocumentTitle.tsx
Normal file
22
src/platform/DocumentTitle.tsx
Normal 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 <></>;
|
||||
}
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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(" ");
|
||||
}
|
Loading…
Add table
Reference in a new issue