1
0
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:
Quentin Gliech
2022-11-16 15:14:40 +01:00
parent 8f4873b535
commit 408a7ba363
11 changed files with 102 additions and 66 deletions

View File

@@ -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;

View File

@@ -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

View 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;

View File

@@ -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>
);
};

View File

@@ -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>
);
};

View File

@@ -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>
);
};

View File

@@ -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>
);
};

View File

@@ -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>
);
};

View File

@@ -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>
);
};

View File

@@ -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;

View File

@@ -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} />