Compare commits
2 commits
af9f111b27
...
1115135380
Author | SHA1 | Date | |
---|---|---|---|
|
1115135380 | ||
|
2e13fcacb5 |
5 changed files with 86 additions and 30 deletions
|
@ -15,6 +15,8 @@ import {
|
||||||
useContext,
|
useContext,
|
||||||
onCleanup,
|
onCleanup,
|
||||||
type Accessor,
|
type Accessor,
|
||||||
|
useTransition,
|
||||||
|
getOwner,
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
import { createStore, unwrap } from "solid-js/store";
|
import { createStore, unwrap } from "solid-js/store";
|
||||||
import "./StackedRouter.css";
|
import "./StackedRouter.css";
|
||||||
|
@ -79,8 +81,8 @@ export type NewFrameOptions<T> = (T extends undefined
|
||||||
export type FramePusher<T, K extends keyof T = keyof T> = T[K] extends
|
export type FramePusher<T, K extends keyof T = keyof T> = T[K] extends
|
||||||
| undefined
|
| undefined
|
||||||
| any
|
| any
|
||||||
? (path: K, state?: Readonly<NewFrameOptions<T[K]>>) => Readonly<StackFrame>
|
? (path: K, state?: Readonly<NewFrameOptions<T[K]>>) => Promise<Readonly<StackFrame>>
|
||||||
: (path: K, state: Readonly<NewFrameOptions<T[K]>>) => Readonly<StackFrame>;
|
: (path: K, state: Readonly<NewFrameOptions<T[K]>>) => Promise<Readonly<StackFrame>>;
|
||||||
|
|
||||||
export type Navigator<PushGuide = Record<string, any>> = {
|
export type Navigator<PushGuide = Record<string, any>> = {
|
||||||
frames: readonly StackFrame[];
|
frames: readonly StackFrame[];
|
||||||
|
@ -465,6 +467,8 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
|
||||||
const [stack, mutStack] = createStore([] as StackFrame[], { name: "stack" });
|
const [stack, mutStack] = createStore([] as StackFrame[], { name: "stack" });
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
|
const [, startTransition] = useTransition();
|
||||||
|
|
||||||
if (import.meta.hot) {
|
if (import.meta.hot) {
|
||||||
const saveStack = () => {
|
const saveStack = () => {
|
||||||
import.meta.hot!.data[$StackedRouterSavedStack] = unwrap(stack);
|
import.meta.hot!.data[$StackedRouterSavedStack] = unwrap(stack);
|
||||||
|
@ -488,8 +492,8 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const pushFrame = (path: string, opts?: Readonly<NewFrameOptions<any>>) =>
|
const pushFrame = async (path: string, opts?: Readonly<NewFrameOptions<any>>) =>
|
||||||
untrack(() => {
|
await untrack(async () => {
|
||||||
const frame = {
|
const frame = {
|
||||||
path,
|
path,
|
||||||
state: opts?.state,
|
state: opts?.state,
|
||||||
|
@ -499,14 +503,17 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const replace = opts?.replace;
|
const replace = opts?.replace;
|
||||||
if (replace === "all" || stack.length === 0) {
|
const length = stack.length;
|
||||||
mutStack([frame]);
|
await startTransition(() => {
|
||||||
} else if (replace) {
|
if (replace === "all" || length === 0) {
|
||||||
const idx = stack.length - 1;
|
mutStack([frame]);
|
||||||
mutStack(idx, frame);
|
} else if (replace) {
|
||||||
} else {
|
const idx = length - 1;
|
||||||
mutStack(stack.length, frame);
|
mutStack(idx, frame);
|
||||||
}
|
} else {
|
||||||
|
mutStack(length, frame);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const savedStack = serializableStack(stack);
|
const savedStack = serializableStack(stack);
|
||||||
|
|
||||||
|
@ -515,6 +522,7 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
|
||||||
} else {
|
} else {
|
||||||
window.history.pushState(savedStack, "", path);
|
window.history.pushState(savedStack, "", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,23 @@
|
||||||
import {
|
import {
|
||||||
createSignal,
|
createSignal,
|
||||||
Show,
|
Show,
|
||||||
onMount,
|
|
||||||
type ParentComponent,
|
type ParentComponent,
|
||||||
createRenderEffect,
|
|
||||||
createEffect,
|
createEffect,
|
||||||
|
useTransition,
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
import { useDocumentTitle } from "../utils";
|
import { useDocumentTitle } from "../utils";
|
||||||
import Scaffold from "~material/Scaffold";
|
import Scaffold from "~material/Scaffold";
|
||||||
import {
|
import {
|
||||||
AppBar,
|
|
||||||
ListItemSecondaryAction,
|
ListItemSecondaryAction,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Switch,
|
Switch,
|
||||||
Toolbar,
|
|
||||||
} from "@suid/material";
|
} from "@suid/material";
|
||||||
import { css } from "solid-styled";
|
import { css } from "solid-styled";
|
||||||
import { TimeSourceProvider, createTimeSource } from "~platform/timesrc";
|
import { TimeSourceProvider, createTimeSource } from "~platform/timesrc";
|
||||||
import ProfileMenuButton from "./ProfileMenuButton";
|
import ProfileMenuButton from "./ProfileMenuButton";
|
||||||
import Tabs from "~material/Tabs";
|
import Tabs from "~material/Tabs";
|
||||||
import Tab from "~material/Tab";
|
import Tab from "~material/Tab";
|
||||||
import { makeEventListener } from "@solid-primitives/event-listener";
|
|
||||||
import { $settings } from "../settings/stores";
|
import { $settings } from "../settings/stores";
|
||||||
import { useStore } from "@nanostores/solid";
|
import { useStore } from "@nanostores/solid";
|
||||||
import TrendTimelinePanel from "./TrendTimelinePanel";
|
import TrendTimelinePanel from "./TrendTimelinePanel";
|
||||||
|
@ -32,10 +28,20 @@ import {
|
||||||
default as ItemSelectionProvider,
|
default as ItemSelectionProvider,
|
||||||
} from "./toots/ItemSelectionProvider";
|
} from "./toots/ItemSelectionProvider";
|
||||||
import AppTopBar from "~material/AppTopBar";
|
import AppTopBar from "~material/AppTopBar";
|
||||||
|
import { createTranslator } from "~platform/i18n";
|
||||||
|
import { useWindowSize } from "@solid-primitives/resize-observer";
|
||||||
|
|
||||||
|
type StringRes = Record<
|
||||||
|
"tabs.home" | "tabs.trending" | "tabs.public" | "set.prefetch-toots",
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
const Home: ParentComponent = (props) => {
|
const Home: ParentComponent = (props) => {
|
||||||
let panelList: HTMLDivElement;
|
let panelList: HTMLDivElement;
|
||||||
useDocumentTitle("Timelines");
|
useDocumentTitle("Timelines");
|
||||||
|
const [t] = createTranslator(
|
||||||
|
(code) => import(`./i18n/${code}.json`) as Promise<{ default: StringRes }>,
|
||||||
|
);
|
||||||
const now = createTimeSource();
|
const now = createTimeSource();
|
||||||
const [, selectionState] = createSingluarItemSelection(
|
const [, selectionState] = createSingluarItemSelection(
|
||||||
undefined as string | undefined,
|
undefined as string | undefined,
|
||||||
|
@ -98,10 +104,19 @@ const Home: ParentComponent = (props) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createEffect(() => {
|
const windowSize = useWindowSize();
|
||||||
makeEventListener(window, "resize", requestRecalculateTabIndicator);
|
createEffect((last) => {
|
||||||
|
if (last !== windowSize.width) {
|
||||||
|
requestRecalculateTabIndicator();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
requestAnimationFrame(recalculateTabIndicator);
|
const [inTransition] = useTransition();
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (!inTransition()) {
|
||||||
|
requestAnimationFrame(recalculateTabIndicator);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const isTabFocus = (idx: number) => {
|
const isTabFocus = (idx: number) => {
|
||||||
|
@ -169,13 +184,13 @@ const Home: ParentComponent = (props) => {
|
||||||
<AppTopBar>
|
<AppTopBar>
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab focus={isTabFocus(0)} onClick={[onTabClick, 0]}>
|
<Tab focus={isTabFocus(0)} onClick={[onTabClick, 0]}>
|
||||||
Home
|
{t("tabs.home")}
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab focus={isTabFocus(1)} onClick={[onTabClick, 1]}>
|
<Tab focus={isTabFocus(1)} onClick={[onTabClick, 1]}>
|
||||||
Trending
|
{t("tabs.trending")}
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab focus={isTabFocus(2)} onClick={[onTabClick, 2]}>
|
<Tab focus={isTabFocus(2)} onClick={[onTabClick, 2]}>
|
||||||
Public
|
{t("tabs.public")}
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<ProfileMenuButton profile={profiles()[0]}>
|
<ProfileMenuButton profile={profiles()[0]}>
|
||||||
|
@ -187,7 +202,7 @@ const Home: ParentComponent = (props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ListItemText>Prefetch Toots</ListItemText>
|
<ListItemText>{t("set.prefetch-toots")}</ListItemText>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<Switch checked={prefetching()}></Switch>
|
<Switch checked={prefetching()}></Switch>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
|
|
|
@ -16,6 +16,12 @@ import {
|
||||||
} from "@suid/icons-material";
|
} from "@suid/icons-material";
|
||||||
import A from "~platform/A";
|
import A from "~platform/A";
|
||||||
import Menu, { createManagedMenuState } from "~material/Menu";
|
import Menu, { createManagedMenuState } from "~material/Menu";
|
||||||
|
import { createTranslator } from "~platform/i18n";
|
||||||
|
|
||||||
|
type StringRes = Record<
|
||||||
|
"nav.bookmarks" | "nav.likes" | "nav.lists" | "nav.settings",
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
const ProfileMenuButton: ParentComponent<{
|
const ProfileMenuButton: ParentComponent<{
|
||||||
profile?: {
|
profile?: {
|
||||||
|
@ -32,6 +38,10 @@ const ProfileMenuButton: ParentComponent<{
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
const menuId = createUniqueId();
|
const menuId = createUniqueId();
|
||||||
const buttonId = createUniqueId();
|
const buttonId = createUniqueId();
|
||||||
|
const [t] = createTranslator(
|
||||||
|
async (code) =>
|
||||||
|
(await import(`./i18n/${code}.json`)) as { default: StringRes },
|
||||||
|
);
|
||||||
|
|
||||||
const [open, state] = createManagedMenuState();
|
const [open, state] = createManagedMenuState();
|
||||||
|
|
||||||
|
@ -84,19 +94,19 @@ const ProfileMenuButton: ParentComponent<{
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<BookmarkIcon />
|
<BookmarkIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>Bookmarks</ListItemText>
|
<ListItemText>{t("nav.bookmarks")}</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem disabled>
|
<MenuItem disabled>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<LikeIcon />
|
<LikeIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>Likes</ListItemText>
|
<ListItemText>{t("nav.likes")}</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem disabled>
|
<MenuItem disabled>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<ListIcon />
|
<ListIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>Lists</ListItemText>
|
<ListItemText>{t("nav.lists")}</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Show when={props.children}>
|
<Show when={props.children}>
|
||||||
|
@ -107,7 +117,7 @@ const ProfileMenuButton: ParentComponent<{
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>Settings</ListItemText>
|
<ListItemText>{t("nav.settings")}</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
{
|
{
|
||||||
"Choose Language": "Choose Language"
|
"Choose Language": "Choose Language",
|
||||||
|
|
||||||
|
"tabs.home": "Home",
|
||||||
|
"tabs.trending": "Trending",
|
||||||
|
"tabs.public": "Public",
|
||||||
|
|
||||||
|
"set.prefetch-toots": "Prefetch Toots",
|
||||||
|
|
||||||
|
"nav.bookmarks": "Bookmarks",
|
||||||
|
"nav.likes": "Likes",
|
||||||
|
"nav.lists": "Lists",
|
||||||
|
"nav.settings": "Settings"
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,3 +1,14 @@
|
||||||
{
|
{
|
||||||
"Choose Language": "选择语言"
|
"Choose Language": "选择语言",
|
||||||
|
|
||||||
|
"tabs.home": "主页",
|
||||||
|
"tabs.trending": "当下热门",
|
||||||
|
"tabs.public": "公开",
|
||||||
|
|
||||||
|
"set.prefetch-toots": "提前下载嘟文",
|
||||||
|
|
||||||
|
"nav.bookmarks": "所有书签",
|
||||||
|
"nav.likes": "喜欢的嘟文",
|
||||||
|
"nav.lists": "所有列表",
|
||||||
|
"nav.settings": "设置"
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue