Compare commits
No commits in common. "b4f7a863a2abf08b906594a4ed64032fa588dfbd" and "f82788495f33309332b00d7f6cad3d1d638b007d" have entirely different histories.
b4f7a863a2
...
f82788495f
6 changed files with 54 additions and 107 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "tutu",
|
"name": "tutu",
|
||||||
"version": "1.0.2",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
53
src/App.tsx
53
src/App.tsx
|
@ -1,27 +1,12 @@
|
||||||
import { Route, Router } from "@solidjs/router";
|
import { Route, Router } from "@solidjs/router";
|
||||||
import { ThemeProvider } from "@suid/material";
|
import { ThemeProvider } from "@suid/material";
|
||||||
import {
|
import { Component, lazy } from "solid-js";
|
||||||
Component,
|
|
||||||
createRenderEffect,
|
|
||||||
createSignal,
|
|
||||||
ErrorBoundary,
|
|
||||||
lazy,
|
|
||||||
} from "solid-js";
|
|
||||||
import { useRootTheme } from "./material/mui.js";
|
import { useRootTheme } from "./material/mui.js";
|
||||||
import {
|
import "./App.css"
|
||||||
Provider as ClientProvider,
|
|
||||||
createMastoClientFor,
|
|
||||||
type Session,
|
|
||||||
} from "./masto/clients.js";
|
|
||||||
import "./App.css";
|
|
||||||
import { $accounts } from "./accounts/stores.js";
|
|
||||||
import { useStore } from "@nanostores/solid";
|
|
||||||
|
|
||||||
const AccountSignIn = lazy(() => import("./accounts/SignIn.js"));
|
const AccountSignIn = lazy(() => import("./accounts/SignIn.js"));
|
||||||
const AccountMastodonOAuth2Callback = lazy(
|
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 Routing: Component = () => {
|
const Routing: Component = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -29,10 +14,7 @@ const Routing: Component = () => {
|
||||||
<Route path="/" component={TimelineHome}></Route>
|
<Route path="/" component={TimelineHome}></Route>
|
||||||
<Route path={"/accounts"}>
|
<Route path={"/accounts"}>
|
||||||
<Route path={"/sign-in"} component={AccountSignIn} />
|
<Route path={"/sign-in"} component={AccountSignIn} />
|
||||||
<Route
|
<Route path={"/oauth2/mastodon"} component={AccountMastodonOAuth2Callback} />
|
||||||
path={"/oauth2/mastodon"}
|
|
||||||
component={AccountMastodonOAuth2Callback}
|
|
||||||
/>
|
|
||||||
</Route>
|
</Route>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
@ -40,29 +22,10 @@ const Routing: Component = () => {
|
||||||
|
|
||||||
const App: Component = () => {
|
const App: Component = () => {
|
||||||
const theme = useRootTheme();
|
const theme = useRootTheme();
|
||||||
const accts = useStore($accounts);
|
|
||||||
const clientStore = createSignal<Session[]>([]);
|
|
||||||
|
|
||||||
createRenderEffect(() => {
|
|
||||||
const [, setClients] = clientStore;
|
|
||||||
setClients(
|
|
||||||
accts().map((x) => ({ account: x, client: createMastoClientFor(x) })),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary
|
<ThemeProvider theme={theme()}>
|
||||||
fallback={(err, reset) => {
|
<Routing />
|
||||||
console.error(err);
|
</ThemeProvider>
|
||||||
return <></>;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ThemeProvider theme={theme()}>
|
|
||||||
<ClientProvider value={clientStore}>
|
|
||||||
<Routing />
|
|
||||||
</ClientProvider>
|
|
||||||
</ThemeProvider>
|
|
||||||
</ErrorBoundary>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { persistentAtom } from "@nanostores/persistent";
|
import { persistentAtom } from "@nanostores/persistent";
|
||||||
|
import { useStore } from "@nanostores/solid";
|
||||||
|
import { useNavigate } from "@solidjs/router";
|
||||||
import { createOAuthAPIClient, createRestAPIClient } from "masto";
|
import { createOAuthAPIClient, createRestAPIClient } from "masto";
|
||||||
import { action } from "nanostores";
|
import { action } from "nanostores";
|
||||||
|
import { createRenderEffect } from "solid-js";
|
||||||
|
|
||||||
export type Account = {
|
export type Account = {
|
||||||
site: string;
|
site: string;
|
||||||
|
@ -172,3 +175,15 @@ export const getOrRegisterApp = action(
|
||||||
return all[site];
|
return all[site];
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export function useAccts() {
|
||||||
|
const accts = useStore($accounts);
|
||||||
|
const naviagte = useNavigate();
|
||||||
|
|
||||||
|
createRenderEffect(() => {
|
||||||
|
if (accts().length > 0) return;
|
||||||
|
naviagte("/accounts/sign-in");
|
||||||
|
});
|
||||||
|
|
||||||
|
return accts;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { Accessor, createResource } from "solid-js";
|
import { Accessor, createResource } from "solid-js";
|
||||||
import type { mastodon } from "masto";
|
import { Account } from "../accounts/stores";
|
||||||
|
import { useMastoClientFor } from "./clients";
|
||||||
|
|
||||||
export function useAcctProfile(client: Accessor<mastodon.rest.Client>) {
|
export function useAcctProfile(account: Accessor<Account>) {
|
||||||
|
const client = useMastoClientFor(account)
|
||||||
return createResource(client, (client) => {
|
return createResource(client, (client) => {
|
||||||
return client.v1.accounts.verifyCredentials()
|
return client.v1.accounts.verifyCredentials()
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -1,78 +1,41 @@
|
||||||
import {
|
import { Accessor, createMemo, createResource } from "solid-js";
|
||||||
Accessor,
|
|
||||||
createContext,
|
|
||||||
createRenderEffect,
|
|
||||||
createResource,
|
|
||||||
Signal,
|
|
||||||
useContext,
|
|
||||||
} from "solid-js";
|
|
||||||
import { Account } from "../accounts/stores";
|
import { Account } from "../accounts/stores";
|
||||||
import { createRestAPIClient, mastodon } from "masto";
|
import { createRestAPIClient, mastodon } from "masto";
|
||||||
import { useLocation, useNavigate } from "@solidjs/router";
|
|
||||||
|
|
||||||
const restfulCache: Record<string, mastodon.rest.Client> = {};
|
const restfulCache: Record<string, mastodon.rest.Client> = {}
|
||||||
|
|
||||||
export function createMastoClientFor(account: Account) {
|
export function createMastoClientFor(account: Account) {
|
||||||
const cacheKey = [account.site, account.accessToken].join("");
|
const cacheKey = [account.site, account.accessToken].join('')
|
||||||
const cache = restfulCache[cacheKey];
|
const cache = restfulCache[cacheKey]
|
||||||
if (cache) return cache;
|
if (cache) return cache;
|
||||||
|
|
||||||
const client = createRestAPIClient({
|
const client = createRestAPIClient({
|
||||||
url: account.site,
|
url: account.site,
|
||||||
accessToken: account.accessToken,
|
accessToken: account.accessToken,
|
||||||
});
|
})
|
||||||
restfulCache[cacheKey] = client;
|
restfulCache[cacheKey] = client
|
||||||
|
|
||||||
return client;
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMastoClientFor(account: Accessor<Account>) {
|
||||||
|
return createMemo(() => createMastoClientFor(account()))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createUnauthorizedClient(site: string) {
|
export function createUnauthorizedClient(site: string) {
|
||||||
const cache = restfulCache[site];
|
const cache = restfulCache[site]
|
||||||
if (cache) return cache;
|
if (cache) return cache;
|
||||||
|
|
||||||
const client = createRestAPIClient({
|
const client = createRestAPIClient({
|
||||||
url: site,
|
url: site
|
||||||
});
|
})
|
||||||
restfulCache[site] = client;
|
restfulCache[site] = client
|
||||||
|
|
||||||
return client;
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useInstance(client: Accessor<mastodon.rest.Client>) {
|
export function useInstance(client: Accessor<mastodon.rest.Client>) {
|
||||||
return createResource(client, async (client) => {
|
return createResource(client, async (client) => {
|
||||||
return await client.v2.instance.fetch();
|
return await client.v2.instance.fetch()
|
||||||
});
|
})
|
||||||
}
|
|
||||||
|
|
||||||
export type Session = {
|
|
||||||
account: Account;
|
|
||||||
client: mastodon.rest.Client;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Context = /* @__PURE__ */ createContext<Signal<Session[]>>();
|
|
||||||
|
|
||||||
export const Provider = Context.Provider;
|
|
||||||
|
|
||||||
export function useSessions() {
|
|
||||||
const [sessions] = useSessionsRw();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
createRenderEffect(() => {
|
|
||||||
if (sessions().length > 0) return;
|
|
||||||
navigate(
|
|
||||||
"/accounts/sign-in?back=" + encodeURIComponent(location.pathname),
|
|
||||||
{ replace: true },
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return sessions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSessionsRw() {
|
|
||||||
const store = useContext(Context);
|
|
||||||
if (!store) {
|
|
||||||
throw new TypeError("sessions are not provided");
|
|
||||||
}
|
|
||||||
return store;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,15 @@ import {
|
||||||
For,
|
For,
|
||||||
onCleanup,
|
onCleanup,
|
||||||
createSignal,
|
createSignal,
|
||||||
|
createEffect,
|
||||||
Show,
|
Show,
|
||||||
untrack,
|
untrack,
|
||||||
onMount,
|
onMount,
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
|
import { $accounts, useAccts } from "../accounts/stores";
|
||||||
import { useDocumentTitle } from "../utils";
|
import { useDocumentTitle } from "../utils";
|
||||||
import { useSessions } from "../masto/clients";
|
import { useStore } from "@nanostores/solid";
|
||||||
|
import { useMastoClientFor } from "../masto/clients";
|
||||||
import { type mastodon } from "masto";
|
import { type mastodon } from "masto";
|
||||||
import Scaffold from "../material/Scaffold";
|
import Scaffold from "../material/Scaffold";
|
||||||
import {
|
import {
|
||||||
|
@ -21,6 +24,7 @@ import {
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Switch,
|
Switch,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
|
Typography,
|
||||||
} 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";
|
||||||
|
@ -148,11 +152,11 @@ const TimelinePanel: Component<{
|
||||||
const Home: Component = () => {
|
const Home: Component = () => {
|
||||||
let panelList: HTMLDivElement;
|
let panelList: HTMLDivElement;
|
||||||
useDocumentTitle("Timelines");
|
useDocumentTitle("Timelines");
|
||||||
|
const accounts = useAccts();
|
||||||
const now = createTimeSource();
|
const now = createTimeSource();
|
||||||
|
|
||||||
const sessions = useSessions();
|
const client = useMastoClientFor(() => accounts()[0]);
|
||||||
const client = () => sessions()[0].client;
|
const [profile] = useAcctProfile(() => accounts()[0]);
|
||||||
const [profile] = useAcctProfile(client);
|
|
||||||
|
|
||||||
const [panelOffset, setPanelOffset] = createSignal(0);
|
const [panelOffset, setPanelOffset] = createSignal(0);
|
||||||
const [prefetching, setPrefetching] = createSignal(true);
|
const [prefetching, setPrefetching] = createSignal(true);
|
||||||
|
|
Loading…
Reference in a new issue