✨ Use uni-token
💄 A lot of optimization
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
:root {
|
||||
--bs-body-font-family: "IBM Plex Serif", "Noto Serif SC", sans-serif !important;
|
||||
--bs-body-font-family: "IBM Plex Sans", "Noto Serif SC", sans-serif !important;
|
||||
}
|
||||
|
||||
html,
|
||||
@@ -7,130 +7,117 @@ body {
|
||||
font-family: var(--bs-body-font-family);
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-100 - latin */
|
||||
/* ibm-plex-sans-100 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: url("./ibm-plex-serif-v19-latin-100.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-100.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-100italic - latin */
|
||||
/* ibm-plex-sans-100italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
src: url("./ibm-plex-serif-v19-latin-100italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-100italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-200 - latin */
|
||||
/* ibm-plex-sans-200 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url("./ibm-plex-serif-v19-latin-200.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-200.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-200italic - latin */
|
||||
/* ibm-plex-sans-200italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
src: url("./ibm-plex-serif-v19-latin-200italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-200italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-300 - latin */
|
||||
/* ibm-plex-sans-300 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url("./ibm-plex-serif-v19-latin-300.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-300italic - latin */
|
||||
/* ibm-plex-sans-300italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: url("./ibm-plex-serif-v19-latin-300italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-300italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-regular - latin */
|
||||
/* ibm-plex-sans-regular - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url("./ibm-plex-serif-v19-latin-regular.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-italic - latin */
|
||||
/* ibm-plex-sans-italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: url("./ibm-plex-serif-v19-latin-italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-500 - latin */
|
||||
/* ibm-plex-sans-500 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url("./ibm-plex-serif-v19-latin-500.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-500italic - latin */
|
||||
/* ibm-plex-sans-500italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
src: url("./ibm-plex-serif-v19-latin-500italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-500italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-600 - latin */
|
||||
/* ibm-plex-sans-600 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url("./ibm-plex-serif-v19-latin-600.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-600italic - latin */
|
||||
/* ibm-plex-sans-600italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: url("./ibm-plex-serif-v19-latin-600italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-600italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-700 - latin */
|
||||
/* ibm-plex-sans-700 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url("./ibm-plex-serif-v19-latin-700.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-serif-700italic - latin */
|
||||
/* ibm-plex-sans-700italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: "IBM Plex Serif";
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: url("./ibm-plex-serif-v19-latin-700italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
src: url('./ibm-plex-sans-v19-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* noto-serif-sc-200 - chinese-simplified */
|
||||
|
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-100.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-100.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-100italic.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-100italic.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-200.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-200.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-200italic.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-200italic.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-300.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-300.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-300italic.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-300italic.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-500.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-500.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-500italic.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-500italic.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-600.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-600.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-600italic.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-600italic.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-700.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-700.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-700italic.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-700italic.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-italic.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-italic.woff2
Executable file
Binary file not shown.
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-regular.woff2
Executable file
BIN
pkg/view/src/assets/fonts/ibm-plex-sans-v19-latin-regular.woff2
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
22
pkg/view/src/components/Avatar.tsx
Normal file
22
pkg/view/src/components/Avatar.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Show } from "solid-js";
|
||||
|
||||
export default function Avatar(props: { user: any }) {
|
||||
return (
|
||||
<Show
|
||||
when={props.user?.avatar}
|
||||
fallback={
|
||||
<div class="avatar placeholder">
|
||||
<div class="w-12 h-12 bg-neutral text-neutral-content">
|
||||
<span class="text-xl uppercase">{props.user?.name?.substring(0, 1)}</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div class="avatar">
|
||||
<div class="w-12">
|
||||
<img alt="avatar" src={props.user?.avatar} />
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
);
|
||||
}
|
@@ -4,6 +4,7 @@ import { request } from "../../scripts/request.ts";
|
||||
import PostAttachments from "./PostAttachments.tsx";
|
||||
import * as marked from "marked";
|
||||
import DOMPurify from "dompurify";
|
||||
import Avatar from "../Avatar.tsx";
|
||||
|
||||
export default function PostItem(props: {
|
||||
post: any;
|
||||
@@ -28,7 +29,7 @@ export default function PostItem(props: {
|
||||
setReacting(true);
|
||||
const res = await request(`/api/posts/${item.id}/react/${type}`, {
|
||||
method: "POST",
|
||||
headers: { Authorization: `Bearer ${getAtk()}` },
|
||||
headers: { Authorization: `Bearer ${getAtk()}` }
|
||||
});
|
||||
if (res.status !== 201 && res.status !== 204) {
|
||||
props.onError(await res.text());
|
||||
@@ -46,15 +47,8 @@ export default function PostItem(props: {
|
||||
<Show when={!props.noAuthor}>
|
||||
<a href={`/accounts/${props.post.author.name}`}>
|
||||
<div class="flex bg-base-200">
|
||||
<div class="avatar pl-[20px]">
|
||||
<div class="w-12">
|
||||
<Show
|
||||
when={props.post.author.avatar}
|
||||
fallback={<span class="text-3xl">{props.post.author.name.substring(0, 1)}</span>}
|
||||
>
|
||||
<img alt="avatar" src={props.post.author.avatar} />
|
||||
</Show>
|
||||
</div>
|
||||
<div class="pl-[20px]">
|
||||
<Avatar user={props.post.author} />
|
||||
</div>
|
||||
<div class="flex items-center px-5">
|
||||
<div>
|
||||
@@ -122,7 +116,8 @@ export default function PostItem(props: {
|
||||
<Show when={!props.noControl}>
|
||||
<div class="relative">
|
||||
<Show when={!userinfo?.isLoggedIn}>
|
||||
<div class="px-7 py-2.5 h-12 w-full opacity-0 transition-opacity hover:opacity-100 bg-base-100 border-t border-base-200 z-[1] absolute top-0 left-0">
|
||||
<div
|
||||
class="px-7 py-2.5 h-12 w-full opacity-0 transition-opacity hover:opacity-100 bg-base-100 border-t border-base-200 z-[1] absolute top-0 left-0">
|
||||
<b>Login!</b> To access entire platform.
|
||||
</div>
|
||||
</Show>
|
||||
|
@@ -4,6 +4,7 @@ import { request } from "../../scripts/request.ts";
|
||||
|
||||
import styles from "./PostPublish.module.css";
|
||||
import PostEditActions from "./PostEditActions.tsx";
|
||||
import Avatar from "../Avatar.tsx";
|
||||
|
||||
export default function PostPublish(props: {
|
||||
replying?: any,
|
||||
@@ -100,7 +101,7 @@ export default function PostPublish(props: {
|
||||
categories: categories(),
|
||||
tags: tags(),
|
||||
realm_id: props.realmId,
|
||||
published_at: publishedAt() ? new Date(publishedAt()) : new Date(),
|
||||
published_at: publishedAt() ? new Date(publishedAt()) : new Date()
|
||||
})
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
@@ -124,13 +125,8 @@ export default function PostPublish(props: {
|
||||
<>
|
||||
<form id="publish" onSubmit={(evt) => (props.editing ? doEdit : doPost)(evt)} onReset={() => resetForm()}>
|
||||
<div id="publish-identity" class="flex border-y border-base-200">
|
||||
<div class="avatar pl-[20px]">
|
||||
<div class="w-12">
|
||||
<Show when={userinfo?.profiles?.avatar}
|
||||
fallback={<span class="text-3xl">{userinfo?.displayName.substring(0, 1)}</span>}>
|
||||
<img alt="avatar" src={userinfo?.profiles?.avatar} />
|
||||
</Show>
|
||||
</div>
|
||||
<div class="pl-[20px]">
|
||||
<Avatar user={userinfo?.profiles} />
|
||||
</div>
|
||||
<div class="flex flex-grow">
|
||||
<input name="title" value={props.editing?.title ?? ""}
|
||||
|
@@ -37,8 +37,6 @@ const router = (basename?: string) => (
|
||||
<Route path="/publish" component={lazy(() => import("./pages/creators/publish.tsx"))} />
|
||||
<Route path="/edit/:postId" component={lazy(() => import("./pages/creators/edit.tsx"))} />
|
||||
</Route>
|
||||
<Route path="/auth" component={lazy(() => import("./pages/auth/callout.tsx"))} />
|
||||
<Route path="/auth/callback" component={lazy(() => import("./pages/auth/callback.tsx"))} />
|
||||
</Router>
|
||||
</UserinfoProvider>
|
||||
</WellKnownProvider>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { For, Match, Switch } from "solid-js";
|
||||
import { createMemo, For, Match, Switch } from "solid-js";
|
||||
import { clearUserinfo, useUserinfo } from "../../stores/userinfo.tsx";
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import { useWellKnown } from "../../stores/wellKnown.tsx";
|
||||
@@ -20,9 +20,11 @@ export default function Navigator() {
|
||||
const userinfo = useUserinfo();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const endpoint = createMemo(() => wellKnown?.components?.identity)
|
||||
|
||||
function logout() {
|
||||
clearUserinfo();
|
||||
navigate("/auth/login");
|
||||
navigate("/");
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -54,7 +56,7 @@ export default function Navigator() {
|
||||
</button>
|
||||
</Match>
|
||||
<Match when={!userinfo?.isLoggedIn}>
|
||||
<a href="/auth" class="btn btn-sm btn-primary">
|
||||
<a href={`${endpoint()}/auth/login?redirect_uri=${window.location}`} class="btn btn-sm btn-primary">
|
||||
Login
|
||||
</a>
|
||||
</Match>
|
||||
|
@@ -1,65 +0,0 @@
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import { readProfiles } from "../../stores/userinfo.tsx";
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import Cookie from "universal-cookie";
|
||||
import { request } from "../../scripts/request.ts";
|
||||
|
||||
export default function AuthCallback() {
|
||||
const [error, setError] = createSignal<string | null>(null);
|
||||
const [status, setStatus] = createSignal("Communicating with Goatpass...");
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
async function callback() {
|
||||
const res = await request(`/api/auth/callback${location.search}`);
|
||||
if (res.status !== 200) {
|
||||
setError(await res.text());
|
||||
} else {
|
||||
const data = await res.json();
|
||||
new Cookie().set("access_token", data["access_token"], { path: "/", maxAge: undefined });
|
||||
new Cookie().set("refresh_token", data["refresh_token"], { path: "/", maxAge: undefined });
|
||||
setStatus("Pulling your personal data...");
|
||||
await readProfiles();
|
||||
setStatus("Redirecting...")
|
||||
setTimeout(() => navigate("/"), 1850)
|
||||
}
|
||||
}
|
||||
|
||||
callback();
|
||||
|
||||
return (
|
||||
<div class="w-full h-full flex justify-center items-center">
|
||||
<div class="card w-[480px] max-w-screen shadow-xl">
|
||||
<div class="card-body">
|
||||
<div id="header" class="text-center mb-5">
|
||||
<h1 class="text-xl font-bold">Authenticate</h1>
|
||||
<p>Via your Goatpass account</p>
|
||||
</div>
|
||||
|
||||
<div class="pt-16 text-center">
|
||||
<div class="text-center">
|
||||
<div>
|
||||
<span class="loading loading-lg loading-bars"></span>
|
||||
</div>
|
||||
<span>{status()}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Show when={error()} fallback={<div class="mt-16"></div>}>
|
||||
<div id="alerts" class="mt-16">
|
||||
<div role="alert" class="alert alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span class="capitalize">{error()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import { request } from "../../scripts/request.ts";
|
||||
|
||||
export default function AuthCallout() {
|
||||
const [error, setError] = createSignal<string | null>(null);
|
||||
const [status, setStatus] = createSignal("Communicating with Goatpass...");
|
||||
|
||||
async function communicate() {
|
||||
const res = await request(`/api/auth${location.search}`);
|
||||
if (res.status !== 200) {
|
||||
setError(await res.text());
|
||||
} else {
|
||||
const data = await res.json();
|
||||
setStatus("Got you! Now redirecting...");
|
||||
window.open(data["target"], "_self");
|
||||
}
|
||||
}
|
||||
|
||||
communicate();
|
||||
|
||||
return (
|
||||
<div class="w-full h-full flex justify-center items-center">
|
||||
<div class="card w-[480px] max-w-screen shadow-xl">
|
||||
<div class="card-body">
|
||||
<div id="header" class="text-center mb-5">
|
||||
<h1 class="text-xl font-bold">Authenticate</h1>
|
||||
<p>Via your Goatpass account</p>
|
||||
</div>
|
||||
|
||||
<div class="pt-16 text-center">
|
||||
<div class="text-center">
|
||||
<div>
|
||||
<span class="loading loading-lg loading-bars"></span>
|
||||
</div>
|
||||
<span>{status()}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Show when={error()} fallback={<div class="mt-16"></div>}>
|
||||
<div id="alerts" class="mt-16">
|
||||
<div role="alert" class="alert alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span class="capitalize">{error()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,92 +1,73 @@
|
||||
import Cookie from "universal-cookie";
|
||||
import {createContext, useContext} from "solid-js";
|
||||
import {createStore} from "solid-js/store";
|
||||
import { createContext, useContext } from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { request } from "../scripts/request.ts";
|
||||
|
||||
export interface Userinfo {
|
||||
isLoggedIn: boolean,
|
||||
displayName: string,
|
||||
profiles: any,
|
||||
isLoggedIn: boolean,
|
||||
displayName: string,
|
||||
profiles: any,
|
||||
}
|
||||
|
||||
const UserinfoContext = createContext<Userinfo>();
|
||||
|
||||
const defaultUserinfo: Userinfo = {
|
||||
isLoggedIn: false,
|
||||
displayName: "Citizen",
|
||||
profiles: null,
|
||||
isLoggedIn: false,
|
||||
displayName: "Citizen",
|
||||
profiles: null
|
||||
};
|
||||
|
||||
const [userinfo, setUserinfo] = createStore<Userinfo>(structuredClone(defaultUserinfo));
|
||||
|
||||
export function getAtk(): string {
|
||||
return new Cookie().get("access_token");
|
||||
}
|
||||
|
||||
export async function refreshAtk() {
|
||||
const rtk = new Cookie().get("refresh_token");
|
||||
|
||||
const res = await request("/api/auth/refresh", {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify({
|
||||
refresh_token: rtk,
|
||||
})
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
console.error(await res.text())
|
||||
} else {
|
||||
const data = await res.json();
|
||||
new Cookie().set("access_token", data["access_token"], {path: "/", maxAge: undefined});
|
||||
new Cookie().set("refresh_token", data["refresh_token"], {path: "/", maxAge: undefined});
|
||||
}
|
||||
return new Cookie().get("identity_auth_key");
|
||||
}
|
||||
|
||||
function checkLoggedIn(): boolean {
|
||||
return new Cookie().get("access_token");
|
||||
return new Cookie().get("identity_auth_key");
|
||||
}
|
||||
|
||||
export async function readProfiles(recovering = true) {
|
||||
if (!checkLoggedIn()) return;
|
||||
export async function readProfiles() {
|
||||
if (!checkLoggedIn()) return;
|
||||
|
||||
const res = await request("/api/users/me", {
|
||||
headers: {"Authorization": `Bearer ${getAtk()}`}
|
||||
});
|
||||
const res = await request("/api/users/me", {
|
||||
headers: { "Authorization": `Bearer ${getAtk()}` }
|
||||
});
|
||||
|
||||
if (res.status !== 200) {
|
||||
if (recovering) {
|
||||
// Auto retry after refresh access token
|
||||
await refreshAtk();
|
||||
return await readProfiles(false);
|
||||
} else {
|
||||
clearUserinfo();
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
if (res.status !== 200) {
|
||||
clearUserinfo();
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
const data = await res.json();
|
||||
|
||||
setUserinfo({
|
||||
isLoggedIn: true,
|
||||
displayName: data["name"],
|
||||
profiles: data,
|
||||
});
|
||||
setUserinfo({
|
||||
isLoggedIn: true,
|
||||
displayName: data["name"],
|
||||
profiles: data
|
||||
});
|
||||
}
|
||||
|
||||
export function clearUserinfo() {
|
||||
new Cookie().remove("access_token", {path: "/", maxAge: undefined});
|
||||
new Cookie().remove("refresh_token", {path: "/", maxAge: undefined});
|
||||
setUserinfo(defaultUserinfo);
|
||||
const cookies = document.cookie.split(";");
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
const cookie = cookies[i];
|
||||
const eqPos = cookie.indexOf("=");
|
||||
const name = eqPos > -1 ? cookie.substring(0, eqPos) : cookie;
|
||||
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
|
||||
}
|
||||
|
||||
setUserinfo(defaultUserinfo);
|
||||
}
|
||||
|
||||
export function UserinfoProvider(props: any) {
|
||||
return (
|
||||
<UserinfoContext.Provider value={userinfo}>
|
||||
{props.children}
|
||||
</UserinfoContext.Provider>
|
||||
);
|
||||
return (
|
||||
<UserinfoContext.Provider value={userinfo}>
|
||||
{props.children}
|
||||
</UserinfoContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useUserinfo() {
|
||||
return useContext(UserinfoContext);
|
||||
return useContext(UserinfoContext);
|
||||
}
|
Reference in New Issue
Block a user