added settings
This commit is contained in:
		
							parent
							
								
									b4f7a863a2
								
							
						
					
					
						commit
						71b9a60b35
					
				
					 15 changed files with 359 additions and 91 deletions
				
			
		
							
								
								
									
										12
									
								
								src/App.css
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								src/App.css
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,14 +1,4 @@
 | 
			
		|||
html,
 | 
			
		||||
body {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  height: 100dvh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#root {
 | 
			
		||||
  overflow: hidden hidden;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  height: 100dvh;
 | 
			
		||||
:root {
 | 
			
		||||
  background-color: var(--tutu-color-surface, transparent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,11 +22,15 @@ const AccountMastodonOAuth2Callback = lazy(
 | 
			
		|||
  () => import("./accounts/MastodonOAuth2Callback.js"),
 | 
			
		||||
);
 | 
			
		||||
const TimelineHome = lazy(() => import("./timelines/Home.js"));
 | 
			
		||||
const Settings = lazy(() => import("./settings/Settings.js"));
 | 
			
		||||
 | 
			
		||||
const Routing: Component = () => {
 | 
			
		||||
  return (
 | 
			
		||||
    <Router>
 | 
			
		||||
      <Route path="/" component={TimelineHome}></Route>
 | 
			
		||||
      <Route path="/" component={TimelineHome}>
 | 
			
		||||
        <Route path=""></Route>
 | 
			
		||||
        <Route path="/settings" component={Settings}></Route>
 | 
			
		||||
      </Route>
 | 
			
		||||
      <Route path={"/accounts"}>
 | 
			
		||||
        <Route path={"/sign-in"} component={AccountSignIn} />
 | 
			
		||||
        <Route
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,11 @@
 | 
			
		|||
import { persistentAtom } from "@nanostores/persistent";
 | 
			
		||||
import { createOAuthAPIClient, createRestAPIClient } from "masto";
 | 
			
		||||
import {
 | 
			
		||||
  createOAuthAPIClient,
 | 
			
		||||
  createRestAPIClient,
 | 
			
		||||
  type mastodon,
 | 
			
		||||
} from "masto";
 | 
			
		||||
import { action } from "nanostores";
 | 
			
		||||
import { createMastoClientFor } from "../masto/clients";
 | 
			
		||||
 | 
			
		||||
export type Account = {
 | 
			
		||||
  site: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +14,8 @@ export type Account = {
 | 
			
		|||
  tokenType: string;
 | 
			
		||||
  scope: string;
 | 
			
		||||
  createdAt: number;
 | 
			
		||||
 | 
			
		||||
  inf?: mastodon.v1.AccountCredentials;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const $accounts = persistentAtom<Account[]>("accounts", [], {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +82,23 @@ export const acceptAccountViaAuthCode = action(
 | 
			
		|||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const updateAcctInf = action(
 | 
			
		||||
  $accounts,
 | 
			
		||||
  "updateAcctInf",
 | 
			
		||||
  async ($store, idx: number) => {
 | 
			
		||||
    const o = $store.get();
 | 
			
		||||
    const client = createMastoClientFor(o[idx]);
 | 
			
		||||
    const inf = await client.v1.accounts.verifyCredentials();
 | 
			
		||||
    o[idx].inf = inf;
 | 
			
		||||
    $store.set(o);
 | 
			
		||||
    return inf;
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const signOut = action($accounts, "signOut", ($store, predicate: (acct: Account) => boolean) => {
 | 
			
		||||
  $store.set($store.get().filter(a => !predicate(a)));
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export type RegisteredApp = {
 | 
			
		||||
  site: string;
 | 
			
		||||
  clientId: string;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,35 @@
 | 
			
		|||
import { Accessor, createResource } from "solid-js";
 | 
			
		||||
import type { mastodon } from "masto";
 | 
			
		||||
import { useSessions } from "./clients";
 | 
			
		||||
import { updateAcctInf } from "../accounts/stores";
 | 
			
		||||
 | 
			
		||||
export function useAcctProfile(client: Accessor<mastodon.rest.Client>) {
 | 
			
		||||
  return createResource(client, (client) => {
 | 
			
		||||
    return client.v1.accounts.verifyCredentials()
 | 
			
		||||
  }, {
 | 
			
		||||
    name: "MastodonAccountProfile"
 | 
			
		||||
  })
 | 
			
		||||
  return createResource(
 | 
			
		||||
    client,
 | 
			
		||||
    (client) => {
 | 
			
		||||
      return client.v1.accounts.verifyCredentials();
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: "MastodonAccountProfile",
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useSignedInProfiles() {
 | 
			
		||||
  const sessions = useSessions();
 | 
			
		||||
  const [accessor, tools] = createResource(sessions, async (all) => {
 | 
			
		||||
    return Promise.all(
 | 
			
		||||
      all.map(async (x, i) => ({ ...x, inf: await updateAcctInf(i) })),
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
  return [
 | 
			
		||||
    () => {
 | 
			
		||||
      if (accessor.loading) {
 | 
			
		||||
        accessor();
 | 
			
		||||
        return sessions().map((x) => ({ ...x, inf: x.account.inf }));
 | 
			
		||||
      }
 | 
			
		||||
      return accessor();
 | 
			
		||||
    },
 | 
			
		||||
    tools,
 | 
			
		||||
  ] as const;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ export function useSessions() {
 | 
			
		|||
  return sessions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useSessionsRw() {
 | 
			
		||||
function useSessionsRw() {
 | 
			
		||||
  const store = useContext(Context);
 | 
			
		||||
  if (!store) {
 | 
			
		||||
    throw new TypeError("sessions are not provided");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								src/material/BottomSheet.module.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/material/BottomSheet.module.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
.bottomSheet {
 | 
			
		||||
  composes: surface from 'material.module.css';
 | 
			
		||||
  border: none;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  top: 50%;
 | 
			
		||||
  transform: translate(-50%, -50%);
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  max-width: 560px;
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  overscroll-behavior: contain;
 | 
			
		||||
 | 
			
		||||
  box-shadow: var(--tutu-shadow-e16);
 | 
			
		||||
 | 
			
		||||
  :global(.MuiToolbar-root) > :global(.MuiButtonBase-root):first-child {
 | 
			
		||||
    color: white;
 | 
			
		||||
    margin-left: -0.5em;
 | 
			
		||||
    margin-right: 24px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @media (max-width: 560px) {
 | 
			
		||||
    & {
 | 
			
		||||
      left: 0;
 | 
			
		||||
      top: 0;
 | 
			
		||||
      transform: none;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      height: 100vh;
 | 
			
		||||
      height: 100dvh;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/material/BottomSheet.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/material/BottomSheet.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
import { createEffect, type ParentComponent } from "solid-js";
 | 
			
		||||
import styles from './BottomSheet.module.css'
 | 
			
		||||
 | 
			
		||||
export type BottomSheetProps = {
 | 
			
		||||
  open?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
 | 
			
		||||
  let element: HTMLDialogElement;
 | 
			
		||||
 | 
			
		||||
  createEffect(() => {
 | 
			
		||||
    if (props.open) {
 | 
			
		||||
      if (!element.open) {
 | 
			
		||||
        element.showModal();
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      if (element.open) {
 | 
			
		||||
        element.close();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return <dialog class={styles.bottomSheet} ref={element!}>{props.children}</dialog>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default BottomSheet;
 | 
			
		||||
| 
						 | 
				
			
			@ -22,9 +22,6 @@ const Scaffold: ParentComponent<ScaffoldProps> = (props) => {
 | 
			
		|||
  css`
 | 
			
		||||
    .scaffold-content {
 | 
			
		||||
      --scaffold-topbar-height: ${(topbarSize.height?.toString() ?? 0) + "px"};
 | 
			
		||||
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .topbar {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								src/overrides.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/overrides.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
/// <reference types="vite/client" />
 | 
			
		||||
 | 
			
		||||
interface ImportMetaEnv {
 | 
			
		||||
  readonly BUILT_AT: string;
 | 
			
		||||
  readonly PACKAGE_VERSION: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface ImportMeta {
 | 
			
		||||
  readonly env: ImportMetaEnv;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										137
									
								
								src/settings/Settings.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/settings/Settings.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,137 @@
 | 
			
		|||
import { createResource, For, type ParentComponent } from "solid-js";
 | 
			
		||||
import Scaffold from "../material/Scaffold.js";
 | 
			
		||||
import {
 | 
			
		||||
  AppBar,
 | 
			
		||||
  Divider,
 | 
			
		||||
  IconButton,
 | 
			
		||||
  List,
 | 
			
		||||
  ListItem,
 | 
			
		||||
  ListItemButton,
 | 
			
		||||
  ListItemSecondaryAction,
 | 
			
		||||
  ListItemText,
 | 
			
		||||
  ListSubheader,
 | 
			
		||||
  NativeSelect,
 | 
			
		||||
  Select,
 | 
			
		||||
  Switch,
 | 
			
		||||
  Toolbar,
 | 
			
		||||
} from "@suid/material";
 | 
			
		||||
import { Close as CloseIcon } from "@suid/icons-material";
 | 
			
		||||
import { useNavigate } from "@solidjs/router";
 | 
			
		||||
import { Title } from "../material/typography.jsx";
 | 
			
		||||
import { useSessions } from "../masto/clients.js";
 | 
			
		||||
import { css } from "solid-styled";
 | 
			
		||||
import { useSignedInProfiles } from "../masto/acct.js";
 | 
			
		||||
import { signOut, type Account } from "../accounts/stores.js";
 | 
			
		||||
import { intlFormat } from "date-fns";
 | 
			
		||||
 | 
			
		||||
const Settings: ParentComponent = () => {
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
 | 
			
		||||
  const [profiles] = useSignedInProfiles();
 | 
			
		||||
 | 
			
		||||
  const doSignOut = (acct: Account) => {
 | 
			
		||||
    signOut((a) => a.site === acct.site && a.accessToken === acct.accessToken);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  css`
 | 
			
		||||
    ul {
 | 
			
		||||
      padding: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .setting-list {
 | 
			
		||||
      padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 16px);
 | 
			
		||||
    }
 | 
			
		||||
  `;
 | 
			
		||||
  return (
 | 
			
		||||
    <Scaffold
 | 
			
		||||
      topbar={
 | 
			
		||||
        <AppBar position="static">
 | 
			
		||||
          <Toolbar variant="dense">
 | 
			
		||||
            <IconButton onClick={[navigate, -1]}>
 | 
			
		||||
              <CloseIcon />
 | 
			
		||||
            </IconButton>
 | 
			
		||||
            <Title>Settings</Title>
 | 
			
		||||
          </Toolbar>
 | 
			
		||||
        </AppBar>
 | 
			
		||||
      }
 | 
			
		||||
    >
 | 
			
		||||
      <List class="setting-list" use:solid-styled>
 | 
			
		||||
        <li>
 | 
			
		||||
          <ul>
 | 
			
		||||
            <ListSubheader>Accounts</ListSubheader>
 | 
			
		||||
            <ListItem>
 | 
			
		||||
              <ListItemText>All Notifications</ListItemText>
 | 
			
		||||
              <ListItemSecondaryAction>
 | 
			
		||||
                <Switch />
 | 
			
		||||
              </ListItemSecondaryAction>
 | 
			
		||||
            </ListItem>
 | 
			
		||||
            <ListItem>
 | 
			
		||||
              <ListItemText>Sign in...</ListItemText>
 | 
			
		||||
            </ListItem>
 | 
			
		||||
          </ul>
 | 
			
		||||
          <For each={profiles()}>
 | 
			
		||||
            {({ account: acct, inf }) => (
 | 
			
		||||
              <ul data-site={acct.site} data-username={inf?.username}>
 | 
			
		||||
                <ListSubheader>{`@${inf?.username ?? "..."}@${new URL(acct.site).host}`}</ListSubheader>
 | 
			
		||||
                <ListItem>
 | 
			
		||||
                  <ListItemText>Notifications</ListItemText>
 | 
			
		||||
                  <ListItemSecondaryAction>
 | 
			
		||||
                    <Switch />
 | 
			
		||||
                  </ListItemSecondaryAction>
 | 
			
		||||
                </ListItem>
 | 
			
		||||
                <ListItemButton onClick={[doSignOut, acct]}>
 | 
			
		||||
                  <ListItemText>Sign out</ListItemText>
 | 
			
		||||
                </ListItemButton>
 | 
			
		||||
              </ul>
 | 
			
		||||
            )}
 | 
			
		||||
          </For>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li>
 | 
			
		||||
          <ListSubheader>Reading</ListSubheader>
 | 
			
		||||
          <ListItem>
 | 
			
		||||
            <ListItemText secondary="Regular">Fonts</ListItemText>
 | 
			
		||||
          </ListItem>
 | 
			
		||||
          <ListItem>
 | 
			
		||||
            <ListItemText secondary="Tutu will download toots before you scroll to the position.">
 | 
			
		||||
              Prefetch Toots
 | 
			
		||||
            </ListItemText>
 | 
			
		||||
            <ListItemSecondaryAction>
 | 
			
		||||
              <Switch />
 | 
			
		||||
            </ListItemSecondaryAction>
 | 
			
		||||
          </ListItem>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li>
 | 
			
		||||
          <ListSubheader>Controls</ListSubheader>
 | 
			
		||||
          <ListItem>
 | 
			
		||||
            <ListItemText>Optimized UI</ListItemText>
 | 
			
		||||
            <ListItemSecondaryAction>
 | 
			
		||||
              <NativeSelect value="auto">
 | 
			
		||||
                <option value="auto">Tutu Decides (Mouse)</option>
 | 
			
		||||
                <option value="mouse">Mouse</option>
 | 
			
		||||
                <option value="touch">Touch</option>
 | 
			
		||||
                <option value="controlpad">Control Pad</option>
 | 
			
		||||
              </NativeSelect>
 | 
			
		||||
            </ListItemSecondaryAction>
 | 
			
		||||
          </ListItem>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li>
 | 
			
		||||
          <ListSubheader>This Application</ListSubheader>
 | 
			
		||||
          <ListItem>
 | 
			
		||||
            <ListItemText secondary="Comformtable tooting experience.">
 | 
			
		||||
              About Tutu
 | 
			
		||||
            </ListItemText>
 | 
			
		||||
          </ListItem>
 | 
			
		||||
          <ListItem>
 | 
			
		||||
            <ListItemText
 | 
			
		||||
              secondary={`Using v${import.meta.env.PACKAGE_VERSION} (built on ${intlFormat(import.meta.env.BUILT_AT)}, ${import.meta.env.MODE})`}
 | 
			
		||||
            >
 | 
			
		||||
              No updates
 | 
			
		||||
            </ListItemText>
 | 
			
		||||
          </ListItem>
 | 
			
		||||
        </li>
 | 
			
		||||
      </List>
 | 
			
		||||
    </Scaffold>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default Settings;
 | 
			
		||||
| 
						 | 
				
			
			@ -6,9 +6,11 @@ import {
 | 
			
		|||
  Show,
 | 
			
		||||
  untrack,
 | 
			
		||||
  onMount,
 | 
			
		||||
  type ParentComponent,
 | 
			
		||||
  children,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import { useDocumentTitle } from "../utils";
 | 
			
		||||
import {  useSessions } from "../masto/clients";
 | 
			
		||||
import { useSessions } from "../masto/clients";
 | 
			
		||||
import { type mastodon } from "masto";
 | 
			
		||||
import Scaffold from "../material/Scaffold";
 | 
			
		||||
import {
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +34,7 @@ import Tab from "../material/Tab";
 | 
			
		|||
import { Create as CreateTootIcon } from "@suid/icons-material";
 | 
			
		||||
import { useTimeline } from "../masto/timelines";
 | 
			
		||||
import { makeEventListener } from "@solid-primitives/event-listener";
 | 
			
		||||
import BottomSheet from "../material/BottomSheet";
 | 
			
		||||
 | 
			
		||||
const TimelinePanel: Component<{
 | 
			
		||||
  client: mastodon.rest.Client;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +148,7 @@ const TimelinePanel: Component<{
 | 
			
		|||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Home: Component = () => {
 | 
			
		||||
const Home: ParentComponent = (props) => {
 | 
			
		||||
  let panelList: HTMLDivElement;
 | 
			
		||||
  useDocumentTitle("Timelines");
 | 
			
		||||
  const now = createTimeSource();
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +165,8 @@ const Home: Component = () => {
 | 
			
		|||
    number,
 | 
			
		||||
  ]);
 | 
			
		||||
 | 
			
		||||
  const child = children(() => props.children)
 | 
			
		||||
 | 
			
		||||
  let scrollEventLockReleased = true;
 | 
			
		||||
 | 
			
		||||
  const recalculateTabIndicator = () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -221,7 +226,7 @@ const Home: Component = () => {
 | 
			
		|||
  const onTabClick = (idx: number) => {
 | 
			
		||||
    const items = panelList.querySelectorAll(".tab-panel");
 | 
			
		||||
    if (items.length > idx) {
 | 
			
		||||
      items.item(idx).scrollIntoView({ behavior: "smooth" });
 | 
			
		||||
      items.item(idx).scrollIntoView({ block: "nearest", behavior: "smooth" });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -235,10 +240,6 @@ const Home: Component = () => {
 | 
			
		|||
      max-height: calc(100dvh - var(--scaffold-topbar-height, 0px));
 | 
			
		||||
      scroll-snap-align: center;
 | 
			
		||||
 | 
			
		||||
      &:not(.active) {
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 600px) {
 | 
			
		||||
        padding: 0;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -261,71 +262,74 @@ const Home: Component = () => {
 | 
			
		|||
  `;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Scaffold
 | 
			
		||||
      topbar={
 | 
			
		||||
        <AppBar position="static">
 | 
			
		||||
          <Toolbar variant="dense" class="responsive">
 | 
			
		||||
            <Tabs onFocusChanged={setCurrentFocusOn} offset={panelOffset()}>
 | 
			
		||||
              <Tab focus={isTabFocus(0)} onClick={[onTabClick, 0]}>
 | 
			
		||||
                Home
 | 
			
		||||
              </Tab>
 | 
			
		||||
              <Tab focus={isTabFocus(1)} onClick={[onTabClick, 1]}>
 | 
			
		||||
                Trending
 | 
			
		||||
              </Tab>
 | 
			
		||||
              <Tab focus={isTabFocus(2)} onClick={[onTabClick, 2]}>
 | 
			
		||||
                Public
 | 
			
		||||
              </Tab>
 | 
			
		||||
            </Tabs>
 | 
			
		||||
            <ProfileMenuButton profile={profile()}>
 | 
			
		||||
              <MenuItem onClick={(e) => setPrefetching((x) => !x)}>
 | 
			
		||||
                <ListItemText>Prefetch Toots</ListItemText>
 | 
			
		||||
                <ListItemSecondaryAction>
 | 
			
		||||
                  <Switch checked={prefetching()}></Switch>
 | 
			
		||||
                </ListItemSecondaryAction>
 | 
			
		||||
              </MenuItem>
 | 
			
		||||
            </ProfileMenuButton>
 | 
			
		||||
          </Toolbar>
 | 
			
		||||
        </AppBar>
 | 
			
		||||
      }
 | 
			
		||||
      fab={
 | 
			
		||||
        <Fab color="secondary">
 | 
			
		||||
          <CreateTootIcon />
 | 
			
		||||
        </Fab>
 | 
			
		||||
      }
 | 
			
		||||
    >
 | 
			
		||||
      <TimeSourceProvider value={now}>
 | 
			
		||||
        <div class="panel-list" ref={panelList!}>
 | 
			
		||||
          <div class="tab-panel">
 | 
			
		||||
            <div>
 | 
			
		||||
              <TimelinePanel
 | 
			
		||||
                client={client()}
 | 
			
		||||
                name="home"
 | 
			
		||||
                prefetch={prefetching()}
 | 
			
		||||
              />
 | 
			
		||||
    <>
 | 
			
		||||
      <Scaffold
 | 
			
		||||
        topbar={
 | 
			
		||||
          <AppBar position="static">
 | 
			
		||||
            <Toolbar variant="dense" class="responsive">
 | 
			
		||||
              <Tabs onFocusChanged={setCurrentFocusOn} offset={panelOffset()}>
 | 
			
		||||
                <Tab focus={isTabFocus(0)} onClick={[onTabClick, 0]}>
 | 
			
		||||
                  Home
 | 
			
		||||
                </Tab>
 | 
			
		||||
                <Tab focus={isTabFocus(1)} onClick={[onTabClick, 1]}>
 | 
			
		||||
                  Trending
 | 
			
		||||
                </Tab>
 | 
			
		||||
                <Tab focus={isTabFocus(2)} onClick={[onTabClick, 2]}>
 | 
			
		||||
                  Public
 | 
			
		||||
                </Tab>
 | 
			
		||||
              </Tabs>
 | 
			
		||||
              <ProfileMenuButton profile={profile()}>
 | 
			
		||||
                <MenuItem onClick={(e) => setPrefetching((x) => !x)}>
 | 
			
		||||
                  <ListItemText>Prefetch Toots</ListItemText>
 | 
			
		||||
                  <ListItemSecondaryAction>
 | 
			
		||||
                    <Switch checked={prefetching()}></Switch>
 | 
			
		||||
                  </ListItemSecondaryAction>
 | 
			
		||||
                </MenuItem>
 | 
			
		||||
              </ProfileMenuButton>
 | 
			
		||||
            </Toolbar>
 | 
			
		||||
          </AppBar>
 | 
			
		||||
        }
 | 
			
		||||
        fab={
 | 
			
		||||
          <Fab color="secondary">
 | 
			
		||||
            <CreateTootIcon />
 | 
			
		||||
          </Fab>
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        <TimeSourceProvider value={now}>
 | 
			
		||||
          <div class="panel-list" ref={panelList!}>
 | 
			
		||||
            <div class="tab-panel">
 | 
			
		||||
              <div>
 | 
			
		||||
                <TimelinePanel
 | 
			
		||||
                  client={client()}
 | 
			
		||||
                  name="home"
 | 
			
		||||
                  prefetch={prefetching()}
 | 
			
		||||
                />
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="tab-panel">
 | 
			
		||||
            <div>
 | 
			
		||||
              <TimelinePanel
 | 
			
		||||
                client={client()}
 | 
			
		||||
                name="trends"
 | 
			
		||||
                prefetch={prefetching()}
 | 
			
		||||
              />
 | 
			
		||||
            <div class="tab-panel">
 | 
			
		||||
              <div>
 | 
			
		||||
                <TimelinePanel
 | 
			
		||||
                  client={client()}
 | 
			
		||||
                  name="trends"
 | 
			
		||||
                  prefetch={prefetching()}
 | 
			
		||||
                />
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="tab-panel">
 | 
			
		||||
            <div>
 | 
			
		||||
              <TimelinePanel
 | 
			
		||||
                client={client()}
 | 
			
		||||
                name="public"
 | 
			
		||||
                prefetch={prefetching()}
 | 
			
		||||
              />
 | 
			
		||||
            <div class="tab-panel">
 | 
			
		||||
              <div>
 | 
			
		||||
                <TimelinePanel
 | 
			
		||||
                  client={client()}
 | 
			
		||||
                  name="public"
 | 
			
		||||
                  prefetch={prefetching()}
 | 
			
		||||
                />
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div></div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </TimeSourceProvider>
 | 
			
		||||
    </Scaffold>
 | 
			
		||||
        </TimeSourceProvider>
 | 
			
		||||
        <BottomSheet open={!!child()}>{child()}</BottomSheet>
 | 
			
		||||
      </Scaffold>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ import {
 | 
			
		|||
  Star as LikeIcon,
 | 
			
		||||
  FeaturedPlayList as ListIcon,
 | 
			
		||||
} from "@suid/icons-material";
 | 
			
		||||
import { A } from "@solidjs/router";
 | 
			
		||||
 | 
			
		||||
const ProfileMenuButton: ParentComponent<{
 | 
			
		||||
  profile?: { displayName: string; avatar: string; username: string };
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +108,7 @@ const ProfileMenuButton: ParentComponent<{
 | 
			
		|||
          {props.children}
 | 
			
		||||
          <Divider />
 | 
			
		||||
        </Show>
 | 
			
		||||
        <MenuItem>
 | 
			
		||||
        <MenuItem component={A} href="/settings" onClick={onClose}>
 | 
			
		||||
          <ListItemIcon>
 | 
			
		||||
            <SettingsIcon />
 | 
			
		||||
          </ListItemIcon>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue