You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-11-21 23:00:50 +03:00
More components reuse
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect } from "react";
|
||||
import { useLayoutEffect } from "react";
|
||||
import "../src/index.css";
|
||||
|
||||
export const parameters = {
|
||||
@@ -35,12 +35,14 @@ export const globalTypes = {
|
||||
};
|
||||
|
||||
const ThemeSwitcher = ({ theme }) => {
|
||||
useEffect(() => {
|
||||
useLayoutEffect(() => {
|
||||
if (theme === "dark") {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
|
||||
return () => document.documentElement.classList.remove("dark");
|
||||
}, [theme]);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -36,7 +36,7 @@ export const Basic: Story = {
|
||||
<Block {...args}>
|
||||
<Title>Title</Title>
|
||||
<Subtitle>Subtitle</Subtitle>
|
||||
<Body>
|
||||
<Body justified>
|
||||
Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit
|
||||
enim labore culpa sint ad nisi Lorem pariatur mollit ex esse
|
||||
exercitation amet. Nisi anim cupidatat excepteur officia. Reprehenderit
|
||||
|
||||
23
frontend/src/components/BlockList.tsx
Normal file
23
frontend/src/components/BlockList.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const BlockList: React.FC<Props> = ({ children }) => {
|
||||
return <div className="grid grid-cols-1 gap-1 content-start">{children}</div>;
|
||||
};
|
||||
|
||||
export default BlockList;
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
import type { BrowserSession_session$key } from "./__generated__/BrowserSession_session.graphql";
|
||||
import { graphql, useFragment } from "react-relay";
|
||||
import Block from "./Block";
|
||||
import { Body, Code, Subtitle } from "./Typography";
|
||||
|
||||
type Props = {
|
||||
session: BrowserSession_session$key;
|
||||
@@ -35,19 +37,19 @@ const BrowserSession: React.FC<Props> = ({ session, isCurrent }) => {
|
||||
session
|
||||
);
|
||||
|
||||
const lastAuthentication = data.lastAuthentication?.createdAt || "never";
|
||||
const createdAt = data.createdAt;
|
||||
|
||||
return (
|
||||
<div className="p-2 my-1 bg-grey-50 dark:bg-grey-450 dark:text-white rounded">
|
||||
{isCurrent && <div className="font-bold">Current session</div>}
|
||||
<div>
|
||||
Started: <span className="font-mono text-sm">{data.createdAt}</span>
|
||||
</div>
|
||||
<div>
|
||||
Last authentication:{" "}
|
||||
<span className="font-semibold">
|
||||
{data.lastAuthentication?.createdAt || "never"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Block>
|
||||
{isCurrent && <Subtitle>Current session</Subtitle>}
|
||||
<Body>
|
||||
Started: <Code>{createdAt}</Code>
|
||||
</Body>
|
||||
<Body>
|
||||
Last authentication: <Code>{lastAuthentication}</Code>
|
||||
</Body>
|
||||
</Block>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { graphql, usePaginationFragment } from "react-relay";
|
||||
import BlockList from "./BlockList";
|
||||
import BrowserSession from "./BrowserSession";
|
||||
import Button from "./Button";
|
||||
import { Title } from "./Typography";
|
||||
|
||||
import { BrowserSessionList_user$key } from "./__generated__/BrowserSessionList_user.graphql";
|
||||
|
||||
@@ -44,8 +46,8 @@ const BrowserSessionList: React.FC<Props> = ({ user, currentSessionId }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-lg">List of browser sessions:</h2>
|
||||
<BlockList>
|
||||
<Title>List of browser sessions:</Title>
|
||||
{data.browserSessions.edges.map((n) => (
|
||||
<BrowserSession
|
||||
key={n.cursor}
|
||||
@@ -54,7 +56,7 @@ const BrowserSessionList: React.FC<Props> = ({ user, currentSessionId }) => {
|
||||
/>
|
||||
))}
|
||||
{hasNext && <Button onClick={() => loadNext(2)}>Load more</Button>}
|
||||
</div>
|
||||
</BlockList>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
import type { CompatSsoLogin_login$key } from "./__generated__/CompatSsoLogin_login.graphql";
|
||||
import { graphql, useFragment } from "react-relay";
|
||||
import Block from "./Block";
|
||||
import { Body, Bold, Code } from "./Typography";
|
||||
|
||||
type Props = {
|
||||
login: CompatSsoLogin_login$key;
|
||||
@@ -41,36 +43,31 @@ const CompatSsoLogin: React.FC<Props> = ({ login }) => {
|
||||
if (data.session) {
|
||||
info = (
|
||||
<>
|
||||
<div>
|
||||
Started:{" "}
|
||||
<span className="font-mono text-sm">{data.session.createdAt}</span>
|
||||
</div>
|
||||
<Body>
|
||||
Started: <Code>{data.session.createdAt}</Code>
|
||||
</Body>
|
||||
{data.session.finishedAt ? (
|
||||
<div className="text-alert">
|
||||
Finished:{" "}
|
||||
<span className="font-mono text-sm">{data.session.createdAt}</span>
|
||||
</div>
|
||||
<Body>
|
||||
Finished: <Code>{data.session.createdAt}</Code>
|
||||
</Body>
|
||||
) : null}
|
||||
<div>
|
||||
Device ID:{" "}
|
||||
<span className="font-mono text-sm font-semibold">
|
||||
{data.session.deviceId}
|
||||
</span>
|
||||
</div>
|
||||
<Body>
|
||||
Device ID: <Code>{data.session.deviceId}</Code>
|
||||
</Body>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-2 my-1 bg-grey-50 dark:bg-grey-450 dark:text-white rounded">
|
||||
<div>
|
||||
Requested: <span className="font-mono text-sm">{data.createdAt}</span>
|
||||
</div>
|
||||
<Block>
|
||||
<Body>
|
||||
Requested: <Code>{data.createdAt}</Code>
|
||||
</Body>
|
||||
{info}
|
||||
<div>
|
||||
Redirect URI: <span className="font-semibold">{data.redirectUri}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Body>
|
||||
Redirect URI: <Bold>{data.redirectUri}</Bold>
|
||||
</Body>
|
||||
</Block>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { graphql, usePaginationFragment } from "react-relay";
|
||||
import BlockList from "./BlockList";
|
||||
import Button from "./Button";
|
||||
import CompatSsoLogin from "./CompatSsoLogin";
|
||||
import { Title } from "./Typography";
|
||||
import { CompatSsoLoginList_user$key } from "./__generated__/CompatSsoLoginList_user.graphql";
|
||||
|
||||
type Props = {
|
||||
@@ -41,13 +43,13 @@ const CompatSsoLoginList: React.FC<Props> = ({ user }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-lg">List of compatibility sessions:</h2>
|
||||
<BlockList>
|
||||
<Title>List of compatibility sessions:</Title>
|
||||
{data.compatSsoLogins.edges.map((n) => (
|
||||
<CompatSsoLogin login={n.node} key={n.node.id} />
|
||||
))}
|
||||
{hasNext && <Button onClick={() => loadNext(2)}>Load more</Button>}
|
||||
</div>
|
||||
</BlockList>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
import type { OAuth2Session_session$key } from "./__generated__/OAuth2Session_session.graphql";
|
||||
import { graphql, useFragment } from "react-relay";
|
||||
import Typography, { Bold, Code } from "./Typography";
|
||||
import { Body, Bold, Code } from "./Typography";
|
||||
import Block from "./Block";
|
||||
|
||||
type Props = {
|
||||
session: OAuth2Session_session$key;
|
||||
@@ -38,21 +39,19 @@ const OAuth2Session: React.FC<Props> = ({ session }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="p-2 my-1 bg-grey-50 dark:bg-grey-450 dark:text-white rounded">
|
||||
<div>
|
||||
<Typography variant="body">
|
||||
<Block>
|
||||
<Body>
|
||||
Client ID: <Code>{data.client.clientId}</Code>
|
||||
</Typography>
|
||||
</div>
|
||||
</Body>
|
||||
{data.client.clientName && (
|
||||
<Typography variant="body">
|
||||
<Body>
|
||||
Client name: <Bold>{data.client.clientName}</Bold>
|
||||
</Typography>
|
||||
</Body>
|
||||
)}
|
||||
<Typography variant="body">
|
||||
<Body>
|
||||
Scope: <Code>{data.scope}</Code>
|
||||
</Typography>
|
||||
</div>
|
||||
</Body>
|
||||
</Block>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,8 +13,11 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { graphql, usePaginationFragment } from "react-relay";
|
||||
import Block from "./Block";
|
||||
import BlockList from "./BlockList";
|
||||
import Button from "./Button";
|
||||
import OAuth2Session from "./OAuth2Session";
|
||||
import { Title } from "./Typography";
|
||||
|
||||
import { OAuth2SessionList_user$key } from "./__generated__/OAuth2SessionList_user.graphql";
|
||||
|
||||
@@ -43,13 +46,13 @@ const OAuth2SessionList: React.FC<Props> = ({ user }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-lg">List of OAuth 2.0 sessions:</h2>
|
||||
<BlockList>
|
||||
<Title>List of OAuth 2.0 sessions:</Title>
|
||||
{data.oauth2Sessions.edges.map((n) => (
|
||||
<OAuth2Session key={n.cursor} session={n.node} />
|
||||
))}
|
||||
{hasNext && <Button onClick={() => loadNext(2)}>Load more</Button>}
|
||||
</div>
|
||||
</BlockList>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ type Props = {
|
||||
children: React.ReactNode;
|
||||
variant: Variant;
|
||||
bold?: boolean;
|
||||
justified?: boolean;
|
||||
};
|
||||
|
||||
const elementMap: Record<Variant, "h1" | "h2" | "h3" | "p" | "small"> = {
|
||||
@@ -35,22 +36,23 @@ const classMap: Record<Variant, string> = {
|
||||
headline: "text-3xl font-semibold",
|
||||
title: "text-2xl font-semibold",
|
||||
subtitle: "text-lg",
|
||||
body: "text-base text-justify",
|
||||
body: "text-base",
|
||||
caption: "text-sm",
|
||||
micro: "text-xs",
|
||||
};
|
||||
|
||||
const Typography = ({ variant, children, bold }: Props) => {
|
||||
const Typography = ({ variant, children, bold, justified }: Props) => {
|
||||
const element = elementMap[variant];
|
||||
const boldClass = bold ? "font-semibold" : "";
|
||||
const className = `text-black dark:text-white ${boldClass} ${classMap[variant]}`;
|
||||
const justifiedClass = justified ? "text-justify" : "";
|
||||
const className = `text-black dark:text-white ${boldClass} ${justifiedClass} ${classMap[variant]}`;
|
||||
return createElement(element, { className }, ...Children.toArray(children));
|
||||
};
|
||||
|
||||
type SimpleProps = { children: React.ReactNode };
|
||||
|
||||
export const Bold = ({ children }: SimpleProps) => (
|
||||
<em className="font-semibold">{children}</em>
|
||||
<strong className="font-semibold">{children}</strong>
|
||||
);
|
||||
|
||||
export const Code = ({ children }: SimpleProps) => (
|
||||
@@ -65,8 +67,12 @@ export const Subtitle = ({ children }: SimpleProps) => (
|
||||
<Typography variant="subtitle" children={children} />
|
||||
);
|
||||
|
||||
export const Body = ({ children }: SimpleProps) => (
|
||||
<Typography variant="body" children={children} />
|
||||
);
|
||||
export const Body = ({
|
||||
children,
|
||||
justified,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
justified?: boolean;
|
||||
}) => <Typography variant="body" children={children} justified={justified} />;
|
||||
|
||||
export default Typography;
|
||||
|
||||
@@ -47,7 +47,7 @@ const Home: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<Typography variant="headline">Hello {user.username}!</Typography>
|
||||
<div className="grid lg:grid-cols-3 gap-1">
|
||||
<div className="mt-4 grid lg:grid-cols-3 gap-1">
|
||||
<OAuth2SessionList user={user} />
|
||||
<CompatSsoLoginList user={user} />
|
||||
<BrowserSessionList user={user} currentSessionId={session.id} />
|
||||
|
||||
Reference in New Issue
Block a user