Compare commits
No commits in common. "85ac9a236b1e9c50b69f36768ef7f63d1593c79f" and "b4f7a863a2abf08b906594a4ed64032fa588dfbd" have entirely different histories.
85ac9a236b
...
b4f7a863a2
16 changed files with 93 additions and 366 deletions
|
@ -28,13 +28,8 @@ jobs:
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: pnpm i
|
run: pnpm i
|
||||||
|
|
||||||
- name: Build Dist (Staging)
|
|
||||||
run: pnpm dist -m staging
|
|
||||||
if: env.GITHUB_REF_NAME == 'master'
|
|
||||||
|
|
||||||
- name: Build Dist
|
- name: Build Dist
|
||||||
run: pnpm dist
|
run: pnpm dist
|
||||||
if: env.GITHUB_REF_NAME != 'master'
|
|
||||||
|
|
||||||
- name: Depoly to Preview
|
- name: Depoly to Preview
|
||||||
uses: https://github.com/cloudflare/wrangler-action@v3
|
uses: https://github.com/cloudflare/wrangler-action@v3
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.2",
|
||||||
"typescript": "^5.5.2",
|
"typescript": "^5.5.2",
|
||||||
"vite": "^5.3.2",
|
"vite": "^5.3.2",
|
||||||
"vite-plugin-package-version": "^1.1.0",
|
|
||||||
"vite-plugin-pwa": "^0.20.0",
|
"vite-plugin-pwa": "^0.20.0",
|
||||||
"vite-plugin-solid": "^2.10.2",
|
"vite-plugin-solid": "^2.10.2",
|
||||||
"vite-plugin-solid-styled": "^0.11.1",
|
"vite-plugin-solid-styled": "^0.11.1",
|
||||||
|
|
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
|
@ -69,9 +69,6 @@ importers:
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.3.2
|
specifier: ^5.3.2
|
||||||
version: 5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2)
|
version: 5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2)
|
||||||
vite-plugin-package-version:
|
|
||||||
specifier: ^1.1.0
|
|
||||||
version: 1.1.0(vite@5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2))
|
|
||||||
vite-plugin-pwa:
|
vite-plugin-pwa:
|
||||||
specifier: ^0.20.0
|
specifier: ^0.20.0
|
||||||
version: 0.20.0(vite@5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.1.0)
|
version: 0.20.0(vite@5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.1.0)
|
||||||
|
@ -2492,11 +2489,6 @@ packages:
|
||||||
validate-html-nesting@1.2.2:
|
validate-html-nesting@1.2.2:
|
||||||
resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==}
|
resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==}
|
||||||
|
|
||||||
vite-plugin-package-version@1.1.0:
|
|
||||||
resolution: {integrity: sha512-TPoFZXNanzcaKCIrC3e2L/TVRkkRLB6l4RPN/S7KbG7rWfyLcCEGsnXvxn6qR7fyZwXalnnSN/I9d6pSFjHpEA==}
|
|
||||||
peerDependencies:
|
|
||||||
vite: '>=2.0.0-beta.69'
|
|
||||||
|
|
||||||
vite-plugin-pwa@0.20.0:
|
vite-plugin-pwa@0.20.0:
|
||||||
resolution: {integrity: sha512-/kDZyqF8KqoXRpMUQtR5Atri/7BWayW8Gp7Kz/4bfstsV6zSFTxjREbXZYL7zSuRL40HGA+o2hvUAFRmC+bL7g==}
|
resolution: {integrity: sha512-/kDZyqF8KqoXRpMUQtR5Atri/7BWayW8Gp7Kz/4bfstsV6zSFTxjREbXZYL7zSuRL40HGA+o2hvUAFRmC+bL7g==}
|
||||||
engines: {node: '>=16.0.0'}
|
engines: {node: '>=16.0.0'}
|
||||||
|
@ -5288,10 +5280,6 @@ snapshots:
|
||||||
|
|
||||||
validate-html-nesting@1.2.2: {}
|
validate-html-nesting@1.2.2: {}
|
||||||
|
|
||||||
vite-plugin-package-version@1.1.0(vite@5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2)):
|
|
||||||
dependencies:
|
|
||||||
vite: 5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2)
|
|
||||||
|
|
||||||
vite-plugin-pwa@0.20.0(vite@5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.1.0):
|
vite-plugin-pwa@0.20.0(vite@5.3.2(@types/node@20.14.10)(lightningcss@1.25.1)(terser@5.31.2))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.5
|
debug: 4.3.5
|
||||||
|
|
12
src/App.css
12
src/App.css
|
@ -1,4 +1,14 @@
|
||||||
:root {
|
html,
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100vh;
|
||||||
|
height: 100dvh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
overflow: hidden hidden;
|
||||||
|
height: 100vh;
|
||||||
|
height: 100dvh;
|
||||||
background-color: var(--tutu-color-surface, transparent);
|
background-color: var(--tutu-color-surface, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,15 +22,11 @@ const AccountMastodonOAuth2Callback = lazy(
|
||||||
() => import("./accounts/MastodonOAuth2Callback.js"),
|
() => import("./accounts/MastodonOAuth2Callback.js"),
|
||||||
);
|
);
|
||||||
const TimelineHome = lazy(() => import("./timelines/Home.js"));
|
const TimelineHome = lazy(() => import("./timelines/Home.js"));
|
||||||
const Settings = lazy(() => import("./settings/Settings.js"));
|
|
||||||
|
|
||||||
const Routing: Component = () => {
|
const Routing: Component = () => {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<Route path="/" component={TimelineHome}>
|
<Route path="/" component={TimelineHome}></Route>
|
||||||
<Route path=""></Route>
|
|
||||||
<Route path="/settings" component={Settings}></Route>
|
|
||||||
</Route>
|
|
||||||
<Route path={"/accounts"}>
|
<Route path={"/accounts"}>
|
||||||
<Route path={"/sign-in"} component={AccountSignIn} />
|
<Route path={"/sign-in"} component={AccountSignIn} />
|
||||||
<Route
|
<Route
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
import { persistentAtom } from "@nanostores/persistent";
|
import { persistentAtom } from "@nanostores/persistent";
|
||||||
import {
|
import { createOAuthAPIClient, createRestAPIClient } from "masto";
|
||||||
createOAuthAPIClient,
|
|
||||||
createRestAPIClient,
|
|
||||||
type mastodon,
|
|
||||||
} from "masto";
|
|
||||||
import { action } from "nanostores";
|
import { action } from "nanostores";
|
||||||
import { createMastoClientFor } from "../masto/clients";
|
|
||||||
|
|
||||||
export type Account = {
|
export type Account = {
|
||||||
site: string;
|
site: string;
|
||||||
|
@ -14,8 +9,6 @@ export type Account = {
|
||||||
tokenType: string;
|
tokenType: string;
|
||||||
scope: string;
|
scope: string;
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
|
|
||||||
inf?: mastodon.v1.AccountCredentials;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const $accounts = persistentAtom<Account[]>("accounts", [], {
|
export const $accounts = persistentAtom<Account[]>("accounts", [], {
|
||||||
|
@ -82,23 +75,6 @@ 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 = {
|
export type RegisteredApp = {
|
||||||
site: string;
|
site: string;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
|
|
|
@ -1,35 +1,10 @@
|
||||||
import { Accessor, createResource } from "solid-js";
|
import { Accessor, createResource } from "solid-js";
|
||||||
import type { mastodon } from "masto";
|
import type { mastodon } from "masto";
|
||||||
import { useSessions } from "./clients";
|
|
||||||
import { updateAcctInf } from "../accounts/stores";
|
|
||||||
|
|
||||||
export function useAcctProfile(client: Accessor<mastodon.rest.Client>) {
|
export function useAcctProfile(client: Accessor<mastodon.rest.Client>) {
|
||||||
return createResource(
|
return createResource(client, (client) => {
|
||||||
client,
|
return client.v1.accounts.verifyCredentials()
|
||||||
(client) => {
|
}, {
|
||||||
return client.v1.accounts.verifyCredentials();
|
name: "MastodonAccountProfile"
|
||||||
},
|
})
|
||||||
{
|
|
||||||
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;
|
return sessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useSessionsRw() {
|
export function useSessionsRw() {
|
||||||
const store = useContext(Context);
|
const store = useContext(Context);
|
||||||
if (!store) {
|
if (!store) {
|
||||||
throw new TypeError("sessions are not provided");
|
throw new TypeError("sessions are not provided");
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
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,6 +22,9 @@ const Scaffold: ParentComponent<ScaffoldProps> = (props) => {
|
||||||
css`
|
css`
|
||||||
.scaffold-content {
|
.scaffold-content {
|
||||||
--scaffold-topbar-height: ${(topbarSize.height?.toString() ?? 0) + "px"};
|
--scaffold-topbar-height: ${(topbarSize.height?.toString() ?? 0) + "px"};
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar {
|
.topbar {
|
||||||
|
|
10
src/overrides.d.ts
vendored
10
src/overrides.d.ts
vendored
|
@ -1,10 +0,0 @@
|
||||||
/// <reference types="vite/client" />
|
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
|
||||||
readonly BUILT_AT: string;
|
|
||||||
readonly PACKAGE_VERSION: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ImportMeta {
|
|
||||||
readonly env: ImportMetaEnv;
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
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,8 +6,6 @@ import {
|
||||||
Show,
|
Show,
|
||||||
untrack,
|
untrack,
|
||||||
onMount,
|
onMount,
|
||||||
type ParentComponent,
|
|
||||||
children,
|
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
import { useDocumentTitle } from "../utils";
|
import { useDocumentTitle } from "../utils";
|
||||||
import { useSessions } from "../masto/clients";
|
import { useSessions } from "../masto/clients";
|
||||||
|
@ -34,7 +32,6 @@ import Tab from "../material/Tab";
|
||||||
import { Create as CreateTootIcon } from "@suid/icons-material";
|
import { Create as CreateTootIcon } from "@suid/icons-material";
|
||||||
import { useTimeline } from "../masto/timelines";
|
import { useTimeline } from "../masto/timelines";
|
||||||
import { makeEventListener } from "@solid-primitives/event-listener";
|
import { makeEventListener } from "@solid-primitives/event-listener";
|
||||||
import BottomSheet from "../material/BottomSheet";
|
|
||||||
|
|
||||||
const TimelinePanel: Component<{
|
const TimelinePanel: Component<{
|
||||||
client: mastodon.rest.Client;
|
client: mastodon.rest.Client;
|
||||||
|
@ -148,7 +145,7 @@ const TimelinePanel: Component<{
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Home: ParentComponent = (props) => {
|
const Home: Component = () => {
|
||||||
let panelList: HTMLDivElement;
|
let panelList: HTMLDivElement;
|
||||||
useDocumentTitle("Timelines");
|
useDocumentTitle("Timelines");
|
||||||
const now = createTimeSource();
|
const now = createTimeSource();
|
||||||
|
@ -165,8 +162,6 @@ const Home: ParentComponent = (props) => {
|
||||||
number,
|
number,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const child = children(() => props.children)
|
|
||||||
|
|
||||||
let scrollEventLockReleased = true;
|
let scrollEventLockReleased = true;
|
||||||
|
|
||||||
const recalculateTabIndicator = () => {
|
const recalculateTabIndicator = () => {
|
||||||
|
@ -226,7 +221,7 @@ const Home: ParentComponent = (props) => {
|
||||||
const onTabClick = (idx: number) => {
|
const onTabClick = (idx: number) => {
|
||||||
const items = panelList.querySelectorAll(".tab-panel");
|
const items = panelList.querySelectorAll(".tab-panel");
|
||||||
if (items.length > idx) {
|
if (items.length > idx) {
|
||||||
items.item(idx).scrollIntoView({ block: "nearest", behavior: "smooth" });
|
items.item(idx).scrollIntoView({ behavior: "smooth" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -240,6 +235,10 @@ const Home: ParentComponent = (props) => {
|
||||||
max-height: calc(100dvh - var(--scaffold-topbar-height, 0px));
|
max-height: calc(100dvh - var(--scaffold-topbar-height, 0px));
|
||||||
scroll-snap-align: center;
|
scroll-snap-align: center;
|
||||||
|
|
||||||
|
&:not(.active) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
@ -262,7 +261,6 @@ const Home: ParentComponent = (props) => {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<Scaffold
|
<Scaffold
|
||||||
topbar={
|
topbar={
|
||||||
<AppBar position="static">
|
<AppBar position="static">
|
||||||
|
@ -327,9 +325,7 @@ const Home: ParentComponent = (props) => {
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
</TimeSourceProvider>
|
</TimeSourceProvider>
|
||||||
<BottomSheet open={!!child()}>{child()}</BottomSheet>
|
|
||||||
</Scaffold>
|
</Scaffold>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ import {
|
||||||
Star as LikeIcon,
|
Star as LikeIcon,
|
||||||
FeaturedPlayList as ListIcon,
|
FeaturedPlayList as ListIcon,
|
||||||
} from "@suid/icons-material";
|
} from "@suid/icons-material";
|
||||||
import { A } from "@solidjs/router";
|
|
||||||
|
|
||||||
const ProfileMenuButton: ParentComponent<{
|
const ProfileMenuButton: ParentComponent<{
|
||||||
profile?: { displayName: string; avatar: string; username: string };
|
profile?: { displayName: string; avatar: string; username: string };
|
||||||
|
@ -108,7 +107,7 @@ const ProfileMenuButton: ParentComponent<{
|
||||||
{props.children}
|
{props.children}
|
||||||
<Divider />
|
<Divider />
|
||||||
</Show>
|
</Show>
|
||||||
<MenuItem component={A} href="/settings" onClick={onClose}>
|
<MenuItem>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|
|
@ -3,7 +3,6 @@ import solid from "vite-plugin-solid";
|
||||||
import solidStyled from "vite-plugin-solid-styled";
|
import solidStyled from "vite-plugin-solid-styled";
|
||||||
import suid from "@suid/vite-plugin";
|
import suid from "@suid/vite-plugin";
|
||||||
import { VitePWA } from "vite-plugin-pwa";
|
import { VitePWA } from "vite-plugin-pwa";
|
||||||
import version from "vite-plugin-package-version";
|
|
||||||
|
|
||||||
export default defineConfig(({ mode }) => ({
|
export default defineConfig(({ mode }) => ({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -18,11 +17,7 @@ export default defineConfig(({ mode }) => ({
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: "autoUpdate",
|
registerType: "autoUpdate",
|
||||||
}),
|
}),
|
||||||
version(),
|
|
||||||
],
|
],
|
||||||
define: {
|
|
||||||
"import.meta.env.BUILT_AT": `"${new Date().toISOString()}"`,
|
|
||||||
},
|
|
||||||
css: {
|
css: {
|
||||||
devSourcemap: true,
|
devSourcemap: true,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue