You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-11-19 00:26:27 +03:00
Add instance privacy policy, TOS and imprint, and loads of design cleanups
This commit is contained in:
@@ -23,7 +23,7 @@ limitations under the License.
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>matrix-authentication-service</title>
|
||||
<script type="application/javascript">
|
||||
window.APP_CONFIG = JSON.parse('{"root": "/account/", "graphqlEndpoint": "/graphql"}');
|
||||
window.APP_CONFIG = JSON.parse('{"root": "/account/", "graphqlEndpoint": "/graphql", "branding": {}}');
|
||||
(function () {
|
||||
const query = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
function handleChange(list) {
|
||||
|
||||
@@ -5,6 +5,16 @@
|
||||
"continue": "Continue",
|
||||
"save": "Save"
|
||||
},
|
||||
"branding": {
|
||||
"privacy_policy": {
|
||||
"alt": "Link to the service privacy policy",
|
||||
"link": "Privacy Policy"
|
||||
},
|
||||
"terms_and_conditions": {
|
||||
"alt": "Link to the service terms and conditions",
|
||||
"link": "Terms & Conditions"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"add": "Add",
|
||||
"error": "Error",
|
||||
|
||||
@@ -13,27 +13,28 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.container {
|
||||
box-sizing: border-box;
|
||||
max-width: calc(378px + var(--cpd-space-6x) * 2);
|
||||
margin: 0 auto;
|
||||
padding: var(--cpd-space-6x);
|
||||
}
|
||||
.legal-footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--cpd-space-2x);
|
||||
|
||||
.footer {
|
||||
margin-top: var(--cpd-space-6x);
|
||||
padding: var(--cpd-space-6x) 0;
|
||||
border-top: 1px solid var(--cpd-color-border-interactive-secondary);
|
||||
font: var(--cpd-font-body-sm-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-sm);
|
||||
|
||||
& nav {
|
||||
display: flex;
|
||||
gap: var(--cpd-space-2x);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
margin: var(--cpd-space-4x) 0;
|
||||
|
||||
& > ul {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
gap: var(--cpd-space-2x);
|
||||
& .separator {
|
||||
color: var(--cpd-color-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
& .imprint {
|
||||
color: var(--cpd-color-text-secondary);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
54
frontend/src/components/Footer/Footer.stories.tsx
Normal file
54
frontend/src/components/Footer/Footer.stories.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import Footer from "./Footer";
|
||||
|
||||
const meta = {
|
||||
title: "UI/Footer",
|
||||
component: Footer,
|
||||
tags: ["autodocs"],
|
||||
} satisfies Meta<typeof Footer>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Footer>;
|
||||
|
||||
export const Basic: Story = {
|
||||
args: {
|
||||
tosUri: "https://matrix.org/legal/terms-and-conditions/",
|
||||
policyUri: "https://matrix.org/legal/privacy-notice/",
|
||||
imprint: "The Matrix.org Foundation C.I.C.",
|
||||
},
|
||||
};
|
||||
|
||||
export const LinksOnly: Story = {
|
||||
args: {
|
||||
tosUri: "https://matrix.org/legal/terms-and-conditions/",
|
||||
policyUri: "https://matrix.org/legal/privacy-notice/",
|
||||
},
|
||||
};
|
||||
|
||||
export const ImprintOnly: Story = {
|
||||
args: {
|
||||
imprint: "The Matrix.org Foundation C.I.C.",
|
||||
},
|
||||
};
|
||||
|
||||
export const OneLink: Story = {
|
||||
args: {
|
||||
tosUri: "https://matrix.org/legal/terms-and-conditions/",
|
||||
imprint: "The Matrix.org Foundation C.I.C.",
|
||||
},
|
||||
};
|
||||
57
frontend/src/components/Footer/Footer.tsx
Normal file
57
frontend/src/components/Footer/Footer.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
import { Link } from "@vector-im/compound-web";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import styles from "./Footer.module.css";
|
||||
|
||||
type Props = {
|
||||
policyUri?: string;
|
||||
tosUri?: string;
|
||||
imprint?: string;
|
||||
};
|
||||
|
||||
const Footer: React.FC<Props> = ({ policyUri, tosUri, imprint }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<footer className={styles.legalFooter}>
|
||||
{(policyUri || tosUri) && (
|
||||
<nav>
|
||||
{policyUri && (
|
||||
<Link href={policyUri} title={t("branding.privacy_policy.alt")}>
|
||||
{t("branding.privacy_policy.link")}
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{policyUri && tosUri && (
|
||||
<div className={styles.separator} aria-hidden="true">
|
||||
•
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tosUri && (
|
||||
<Link href={tosUri} title={t("branding.terms_and_conditions.alt")}>
|
||||
{t("branding.terms_and_conditions.link")}
|
||||
</Link>
|
||||
)}
|
||||
</nav>
|
||||
)}
|
||||
|
||||
{imprint && <p className={styles.imprint}>{imprint}</p>}
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
15
frontend/src/components/Footer/index.ts
Normal file
15
frontend/src/components/Footer/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
export { default } from "./Footer";
|
||||
26
frontend/src/components/Layout/Layout.module.css
Normal file
26
frontend/src/components/Layout/Layout.module.css
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
.layout-container {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
max-width: calc(420px + var(--cpd-space-6x) * 2);
|
||||
min-height: 100vh;
|
||||
margin: 0 auto;
|
||||
padding: var(--cpd-space-6x);
|
||||
gap: var(--cpd-space-6x);
|
||||
}
|
||||
@@ -17,8 +17,8 @@
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it, vi, afterAll, beforeEach } from "vitest";
|
||||
|
||||
import { currentUserIdAtom, GqlResult } from "../atoms";
|
||||
import { WithLocation } from "../test-utils/WithLocation";
|
||||
import { currentUserIdAtom, GqlResult } from "../../atoms";
|
||||
import { WithLocation } from "../../test-utils/WithLocation";
|
||||
|
||||
import Layout from "./Layout";
|
||||
|
||||
@@ -15,19 +15,21 @@
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { currentUserIdAtom } from "../atoms";
|
||||
import { isErr, unwrapErr, unwrapOk } from "../result";
|
||||
import { routeAtom } from "../routing";
|
||||
import { currentUserIdAtom } from "../../atoms";
|
||||
import { isErr, unwrapErr, unwrapOk } from "../../result";
|
||||
import { appConfigAtom, routeAtom } from "../../routing";
|
||||
import Footer from "../Footer";
|
||||
import GraphQLError from "../GraphQLError";
|
||||
import NavBar from "../NavBar";
|
||||
import NavItem from "../NavItem";
|
||||
import NotLoggedIn from "../NotLoggedIn";
|
||||
import UserGreeting from "../UserGreeting";
|
||||
|
||||
import GraphQLError from "./GraphQLError";
|
||||
import styles from "./Layout.module.css";
|
||||
import NavBar from "./NavBar";
|
||||
import NavItem from "./NavItem";
|
||||
import NotLoggedIn from "./NotLoggedIn";
|
||||
import UserGreeting from "./UserGreeting";
|
||||
|
||||
const Layout: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
|
||||
const route = useAtomValue(routeAtom);
|
||||
const appConfig = useAtomValue(appConfigAtom);
|
||||
const result = useAtomValue(currentUserIdAtom);
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -45,7 +47,7 @@ const Layout: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.layoutContainer}>
|
||||
{shouldHideNavBar ? null : (
|
||||
<>
|
||||
<UserGreeting userId={userId} />
|
||||
@@ -63,18 +65,11 @@ const Layout: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
|
||||
|
||||
<main>{children}</main>
|
||||
|
||||
{/* TODO: the footer needs to be reworked to show configurable info not hardcoded links: https://github.com/matrix-org/matrix-authentication-service/issues/1675 */}
|
||||
{/* <footer className={styles.footer}>
|
||||
<nav className={styles.footerLinks}>
|
||||
<ul>
|
||||
<Link href="https://matrix.org/legal/copyright-notice">Info</Link>
|
||||
<Link href="https://matrix.org/legal/privacy-notice">Privacy</Link>
|
||||
<Link href="https://matrix.org/legal/terms-and-conditions">
|
||||
Terms & Conditions
|
||||
</Link>
|
||||
</ul>
|
||||
</nav>
|
||||
</footer> */}
|
||||
<Footer
|
||||
imprint={appConfig.branding?.imprint}
|
||||
tosUri={appConfig.branding?.tosUri}
|
||||
policyUri={appConfig.branding?.policyUri}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
15
frontend/src/components/Layout/index.ts
Normal file
15
frontend/src/components/Layout/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
export { default } from "./Layout";
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
.nav-bar {
|
||||
border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-gray-400);
|
||||
margin: var(--cpd-space-6x) 0;
|
||||
padding: 0 var(--cpd-space-10x);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.alert {
|
||||
margin-top: var(--cpd-space-4x);
|
||||
|
||||
> * {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
}
|
||||
.alert > * {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
export type AppConfig = {
|
||||
root: string;
|
||||
graphqlEndpoint: string;
|
||||
branding?: {
|
||||
tosUri?: string;
|
||||
policyUri?: string;
|
||||
imprint?: string;
|
||||
};
|
||||
};
|
||||
|
||||
interface IWindow {
|
||||
@@ -22,6 +27,10 @@ interface IWindow {
|
||||
}
|
||||
|
||||
const config: AppConfig = (typeof window !== "undefined" &&
|
||||
(window as IWindow).APP_CONFIG) || { root: "/", graphqlEndpoint: "/graphql" };
|
||||
(window as IWindow).APP_CONFIG) || {
|
||||
root: "/",
|
||||
graphqlEndpoint: "/graphql",
|
||||
branding: {},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
@import "./styles/cpd-form.css";
|
||||
@import "./styles/cpd-link.css";
|
||||
|
||||
@import "./components/Layout/Layout.module.css";
|
||||
@import "./components/Footer/Footer.module.css";
|
||||
|
||||
@config "../tailwind.templates.config.cjs";
|
||||
|
||||
@tailwind base;
|
||||
@@ -30,92 +33,111 @@
|
||||
@tailwind utilities;
|
||||
|
||||
.cpd-text-body-lg-regular {
|
||||
font: var(--cpd-font-body-lg-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-lg);
|
||||
font: var(--cpd-font-body-lg-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-lg);
|
||||
}
|
||||
|
||||
.cpd-text-heading-xl-semibold {
|
||||
font: var(--cpd-font-heading-xl-semibold);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-heading-xl);
|
||||
font: var(--cpd-font-heading-xl-semibold);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-heading-xl);
|
||||
}
|
||||
|
||||
.cpd-text-body-md-regular {
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-md);
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-md);
|
||||
}
|
||||
|
||||
.cpd-text-primary {
|
||||
color: var(--cpd-color-text-primary);
|
||||
color: var(--cpd-color-text-primary);
|
||||
}
|
||||
|
||||
.cpd-text-secondary {
|
||||
color: var(--cpd-color-text-secondary);
|
||||
color: var(--cpd-color-text-secondary);
|
||||
}
|
||||
|
||||
.consent-client-icon {
|
||||
display: block;
|
||||
display: block;
|
||||
height: var(--cpd-space-16x);
|
||||
width: var(--cpd-space-16x);
|
||||
margin: 0 auto;
|
||||
|
||||
&.generic {
|
||||
background-color: var(--cpd-color-bg-subtle-secondary);
|
||||
border-radius: var(--cpd-radius-pill-effect);
|
||||
color: var(--cpd-color-icon-primary);
|
||||
|
||||
& svg {
|
||||
margin: var(--cpd-space-4x);
|
||||
height: var(--cpd-space-8x);
|
||||
width: var(--cpd-space-8x);
|
||||
}
|
||||
}
|
||||
|
||||
&.image {
|
||||
height: var(--cpd-space-16x);
|
||||
width: var(--cpd-space-16x);
|
||||
margin: 0 auto;
|
||||
|
||||
&.generic {
|
||||
background-color: var(--cpd-color-bg-subtle-secondary);
|
||||
border-radius: var(--cpd-radius-pill-effect);
|
||||
color: var(--cpd-color-icon-primary);
|
||||
|
||||
& svg {
|
||||
margin: var(--cpd-space-4x);
|
||||
height: var(--cpd-space-8x);
|
||||
width: var(--cpd-space-8x);
|
||||
}
|
||||
}
|
||||
|
||||
&.image {
|
||||
height: var(--cpd-space-16x);
|
||||
width: var(--cpd-space-16x);
|
||||
border-radius: var(--cpd-space-2x);
|
||||
overflow: hidden;
|
||||
}
|
||||
border-radius: var(--cpd-space-2x);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.consent-scope-list {
|
||||
--border-radius: var(--cpd-space-4x);
|
||||
& ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--cpd-space-1x);
|
||||
--border-radius: var(--cpd-space-4x);
|
||||
& ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--cpd-space-1x);
|
||||
|
||||
& > li {
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-md);
|
||||
color: var(--cpd-color-text-primary);
|
||||
& > li {
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-md);
|
||||
color: var(--cpd-color-text-primary);
|
||||
|
||||
background-color: var(--cpd-color-bg-subtle-secondary);
|
||||
padding: var(--cpd-space-3x) var(--cpd-space-5x);
|
||||
display: flex;
|
||||
gap: var(--cpd-space-4x);
|
||||
line-height: var(--cpd-space-6x);
|
||||
background-color: var(--cpd-color-bg-subtle-secondary);
|
||||
padding: var(--cpd-space-3x) var(--cpd-space-5x);
|
||||
display: flex;
|
||||
gap: var(--cpd-space-4x);
|
||||
line-height: var(--cpd-space-6x);
|
||||
|
||||
&:first-of-type {
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-top-right-radius: var(--border-radius);
|
||||
}
|
||||
&:first-of-type {
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-top-right-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
border-bottom-right-radius: var(--border-radius);
|
||||
}
|
||||
&:last-of-type {
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
border-bottom-right-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
& > p {
|
||||
flex: 1;
|
||||
}
|
||||
& > p {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
& > svg {
|
||||
display: block;
|
||||
height: var(--cpd-space-6x);
|
||||
width: var(--cpd-space-6x);
|
||||
color: var(--cpd-color-icon-quaternary);
|
||||
}
|
||||
}
|
||||
& > svg {
|
||||
display: block;
|
||||
height: var(--cpd-space-6x);
|
||||
width: var(--cpd-space-6x);
|
||||
color: var(--cpd-color-icon-quaternary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
& hr {
|
||||
flex: 1;
|
||||
border: none;
|
||||
border-top: 1px solid var(--cpd-color-bg-subtle-primary);
|
||||
}
|
||||
|
||||
& p {
|
||||
margin-inline: var(--cpd-space-4x);
|
||||
text-transform: uppercase;
|
||||
font: var(--cpd-font-body-md-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-md);
|
||||
color: var(--cpd-color-text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user