From 7a9a873271d9fae9615182a53d3b9c2bc8048917 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 1 Sep 2023 14:42:38 +0200 Subject: [PATCH] Compoundify the templates --- frontend/src/routing/Router.tsx | 21 ++- frontend/src/styles/cpd-button.css | 127 ++++++++++++++++++ frontend/src/styles/cpd-link.css | 51 +++++++ frontend/src/templates.css | 13 +- frontend/vite.config.ts | 7 +- templates/app.html | 5 +- templates/base.html | 3 +- templates/components/back_to_client.html | 6 +- templates/components/button.html | 43 ++---- templates/components/logout.html | 4 +- templates/components/navbar.html | 2 +- templates/pages/consent.html | 12 +- templates/pages/login.html | 2 +- templates/pages/policy_violation.html | 8 +- templates/pages/reauth.html | 4 +- templates/pages/register.html | 2 +- templates/pages/sso.html | 2 +- .../pages/upstream_oauth2/link_mismatch.html | 2 +- .../pages/upstream_oauth2/suggest_link.html | 2 +- 19 files changed, 242 insertions(+), 74 deletions(-) create mode 100644 frontend/src/styles/cpd-button.css create mode 100644 frontend/src/styles/cpd-link.css diff --git a/frontend/src/routing/Router.tsx b/frontend/src/routing/Router.tsx index 43d20df8..d4353458 100644 --- a/frontend/src/routing/Router.tsx +++ b/frontend/src/routing/Router.tsx @@ -13,9 +13,18 @@ // limitations under the License. import { useAtom, useAtomValue } from "jotai"; -import { lazy, useEffect } from "react"; +import { useEffect } from "react"; import LoadingSpinner from "../components/LoadingSpinner"; +import BrowserSession from "../pages/BrowserSession"; +import BrowserSessionList from "../pages/BrowserSessionList"; +import CompatSessionList from "../pages/CompatSessionList"; +import OAuth2Client from "../pages/OAuth2Client"; +import OAuth2SessionList from "../pages/OAuth2SessionList"; +import Profile from "../pages/Profile"; +import SessionDetail from "../pages/SessionDetail"; +import SessionsOverview from "../pages/SessionsOverview"; +import VerifyEmail from "../pages/VerifyEmail"; import { getRouteActionRedirection } from "./actions"; import { locationAtom, routeAtom } from "./atoms"; @@ -42,16 +51,6 @@ const useRouteWithRedirect = (): [Route, boolean] => { return [route, redirecting]; }; -const SessionsOverview = lazy(() => import("../pages/SessionsOverview")); -const SessionDetail = lazy(() => import("../pages/SessionDetail")); -const Profile = lazy(() => import("../pages/Profile")); -const OAuth2Client = lazy(() => import("../pages/OAuth2Client")); -const BrowserSession = lazy(() => import("../pages/BrowserSession")); -const BrowserSessionList = lazy(() => import("../pages/BrowserSessionList")); -const CompatSessionList = lazy(() => import("../pages/CompatSessionList")); -const OAuth2SessionList = lazy(() => import("../pages/OAuth2SessionList")); -const VerifyEmail = lazy(() => import("../pages/VerifyEmail")); - const Router: React.FC = () => { const [route, redirecting] = useRouteWithRedirect(); diff --git a/frontend/src/styles/cpd-button.css b/frontend/src/styles/cpd-button.css new file mode 100644 index 00000000..fa97155a --- /dev/null +++ b/frontend/src/styles/cpd-button.css @@ -0,0 +1,127 @@ +/* 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. + */ + +.cpd-button { + display: block; + text-align: center; + border-radius: var(--cpd-radius-pill-effect); + cursor: pointer; + -webkit-appearance: none; +} + +.cpd-button[disabled] { + cursor: not-allowed; + pointer-events: all !important; +} + +/** + * SIZES + */ + +.cpd-button[data-size="lg"] { + font: var(--cpd-font-body-lg-semibold); + padding: var(--cpd-space-3x) var(--cpd-space-10x); +} + +.cpd-button[data-size="sm"] { + font: var(--cpd-font-body-md-semibold); + padding: var(--cpd-space-1x) var(--cpd-space-6x); +} + +/** + * KINDS + */ + +.cpd-button[data-kind="primary"] { + color: var(--cpd-color-text-on-solid-primary); + background: var(--cpd-color-bg-action-primary-rest); + border-width: 0; +} + +.cpd-button[data-kind="primary"]:hover { + background: var(--cpd-color-bg-action-primary-hovered); +} + +.cpd-button[data-kind="primary"]:active { + background: var(--cpd-color-bg-action-primary-pressed); +} + +.cpd-button[data-kind="primary"][disabled] { + color: var(--cpd-color-text-disabled); + background: var(--cpd-color-bg-subtle-primary); +} + +.cpd-button[data-kind="secondary"] { + border: 1px solid var(--cpd-color-border-interactive-primary); + color: var(--cpd-color-text-primary); + background: var(--cpd-color-bg-canvas-default); +} + +.cpd-button[data-kind="secondary"]:hover { + border-color: var(--cpd-color-border-interactive-hovered); + background: var(--cpd-color-bg-subtle-secondary); +} + +.cpd-button[data-kind="secondary"]:active { + border-color: var(--cpd-color-border-interactive-hovered); + background: var(--cpd-color-bg-subtle-primary); +} + +.cpd-button[data-kind="secondary"][disabled] { + border-color: var(--cpd-color-border-interactive-secondary); + color: var(--cpd-color-text-disabled); + background: var(--cpd-color-bg-subtle-secondary); +} + +.cpd-button[data-kind="tertiary"] { + border: none; + color: var(--cpd-color-text-primary); + text-decoration: underline; + background: transparent; +} + +.cpd-button[data-kind="tertiary"]:hover { + background: var(--cpd-color-bg-subtle-secondary); +} + +.cpd-button[data-kind="tertiary"]:active { + background: var(--cpd-color-bg-subtle-primary); +} + +.cpd-button[data-kind="tertiary"][disabled] { + color: var(--cpd-color-text-disabled); +} + +.cpd-button[data-kind="destructive"] { + border: 1px solid var(--cpd-color-border-critical-primary); + color: var(--cpd-color-text-critical-primary); + background: var(--cpd-color-bg-canvas-default); +} + +.cpd-button[data-kind="destructive"]:hover { + border-color: var(--cpd-color-border-critical-hovered); + background: var(--cpd-color-bg-critical-subtle); +} + +.cpd-button[data-kind="destructive"]:active { + border-color: var(--cpd-color-border-critical-hovered); + background: var(--cpd-color-bg-critical-subtle-hovered); +} + +.cpd-button[data-kind="destructive"][disabled] { + border-color: var(--cpd-color-border-interactive-secondary); + color: var(--cpd-color-text-disabled); + background: var(--cpd-color-bg-subtle-secondary); +} diff --git a/frontend/src/styles/cpd-link.css b/frontend/src/styles/cpd-link.css new file mode 100644 index 00000000..d90135ac --- /dev/null +++ b/frontend/src/styles/cpd-link.css @@ -0,0 +1,51 @@ +/* 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. + */ + +.cpd-link { + display: inline-block; + text-decoration: underline; + color: var(--cpd-color-text-primary); + font-weight: var(--cpd-font-weight-medium); + border-radius: var(--cpd-radius-pill-effect); + padding-inline: 0.25rem; +} + +.cpd-link[data-kind="primary"] { + color: var(--cpd-color-text-primary); +} + +.cpd-link[data-kind="critical"] { + color: var(--cpd-color-text-critical-primary); +} + +.cpd-link[data-kind="primary"]:hover { + background: var(--cpd-color-gray-300); +} + +.cpd-link[data-kind="critical"]:hover { + background: var(--cpd-color-red-300); +} + +.cpd-link:active { + color: var(--cpd-color-text-on-solid-primary); +} + +.cpd-link[data-kind="primary"]:active { + background: var(--cpd-color-text-primary); +} + +.cpd-link[data-kind="critical"]:active { + background: var(--cpd-color-text-critical-primary); +} \ No newline at end of file diff --git a/frontend/src/templates.css b/frontend/src/templates.css index 43c616b4..843d66a2 100644 --- a/frontend/src/templates.css +++ b/frontend/src/templates.css @@ -19,9 +19,20 @@ @import "@fontsource/inter/700.css"; @import "@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css"; @import "@vector-im/compound-web/dist/style.css"; +@import "./styles/cpd-button.css"; +@import "./styles/cpd-link.css"; @config "../tailwind.templates.config.cjs"; @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +body { + /* XXX: I'm unsure why this is not part of the tokens */ + --cpd-radius-pill-effect: 9999px; + + font: var(--cpd-font-body-md-regular); + background: var(--cpd-color-bg-canvas-default); + color: var(--cpd-color-text-primary); +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 059d6c2b..524c3769 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -36,9 +36,10 @@ export default defineConfig((env) => ({ assetsInlineLimit: 0, sourcemap: true, modulePreload: false, - // We don't handle CSS code splitting well yet, so we disable it for now - // This means we have to load all the CSS through the `style.css` virtual entrypoint - cssCodeSplit: false, + + // We don't exactly handle CSS code splitting well if we're lazy loading components. + // We disabled lazy loading for now, but we should fix this at some point. + cssCodeSplit: true, rollupOptions: { input: [ diff --git a/templates/app.html b/templates/app.html index ea56c1a3..cf40187f 100644 --- a/templates/app.html +++ b/templates/app.html @@ -28,9 +28,9 @@ limitations under the License. const query = window.matchMedia("(prefers-color-scheme: dark)"); function handleChange(list) { if (list.matches) { - document.documentElement.classList.add("dark"); + document.documentElement.classList.add("cpd-theme-dark"); } else { - document.documentElement.classList.remove("dark"); + document.documentElement.classList.remove("cpd-theme-dark"); } } @@ -38,7 +38,6 @@ limitations under the License. handleChange(query); })(); - {{ include_asset(path='style.css') | indent(prefix=" ") | safe }} {{ include_asset(path='src/main.tsx') | indent(prefix=" ") | safe }} diff --git a/templates/base.html b/templates/base.html index 42593abc..a8716e63 100644 --- a/templates/base.html +++ b/templates/base.html @@ -28,10 +28,9 @@ limitations under the License. {% block title %}matrix-authentication-service{% endblock title %} - {{ include_asset(path='style.css') | indent(prefix=" ") | safe }} {{ include_asset(path='src/templates.css') | indent(prefix=" ") | safe }} - + {% block content %}{% endblock content %} diff --git a/templates/components/back_to_client.html b/templates/components/back_to_client.html index fb333c9b..4c807735 100644 --- a/templates/components/back_to_client.html +++ b/templates/components/back_to_client.html @@ -14,16 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. #} -{% macro link(text, class="", uri, mode, params) %} +{% macro link(text, uri, mode, params, kind="primary") %} {% if mode == "form_post" %}
{% for key, value in params %} {% endfor %} - +
{% elif mode == "fragment" or mode == "query" %} - {{ text }} + {{ text }} {% else %} {{ throw(message="Invalid mode") }} {% endif %} diff --git a/templates/components/button.html b/templates/components/button.html index 0c96811b..cbe649dd 100644 --- a/templates/components/button.html +++ b/templates/components/button.html @@ -1,5 +1,5 @@ {# -Copyright 2021 The Matrix.org Foundation C.I.C. +Copyright 2021-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. @@ -14,40 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. #} -{% macro common_class() -%} - px-4 py-2 border-2 rounded-lg font-medium text-center focus:ring-0 focus:outline-0 focus:border-black dark:focus:border-white -{%- endmacro %} - -{% macro plain_error_class() -%} - {{ self::common_class() }} border-alert bg-alert text-white hover:opacity-75 -{%- endmacro %} - -{% macro outline_error_class() -%} - {{ self::common_class() }} border-alert text-alert hover:bg-alert/10 -{%- endmacro %} - -{% macro plain_class() -%} - {{ self::common_class() }} border-accent bg-accent text-white hover:opacity-75 -{%- endmacro %} - -{% macro outline_class() -%} - {{ self::common_class() }} border-accent hover:bg-accent/10 text-accent -{%- endmacro %} - -{% macro text_class() -%} - {{ self::common_class() }} border-transparent hover:text-accent/70 text-accent -{%- endmacro %} - {% macro link(text, href="#", class="") %} - {{ text }} + {{ text }} {% endmacro %} {% macro link_text(text, href="#", class="") %} - {{ text }} + {{ text }} {% endmacro %} {% macro link_outline(text, href="#", class="") %} - {{ text }} + {{ text }} {% endmacro %} {% macro button( @@ -65,7 +41,9 @@ limitations under the License. value="{{ value }}" type="{{ type }}" {% if disabled %}disabled{% endif %} - class="{{ self::plain_class() }} {{ class }}" + class="cpd-button {{ class }}" + data-kind="primary" + data-size="lg" {% if autocapitalize %}autocapitilize="{{ autocapitilize }}"{% endif %} {% if autocomplete %}autocomplete="{{ autocomplete }}"{% endif %} {% if autocorrect %}autocorrect="{{ autocorrect }}"{% endif %} @@ -87,7 +65,8 @@ limitations under the License. value="{{ value }}" type="{{ type }}" {% if disabled %}disabled{% endif %} - class="{{ self::text_class() }} {{ class }}" + data-kind="primary" + class="cpd-link {{ class }}" {% if autocapitalize %}autocapitilize="{{ autocapitilize }}"{% endif %} {% if autocomplete %}autocomplete="{{ autocomplete }}"{% endif %} {% if autocorrect %}autocorrect="{{ autocorrect }}"{% endif %} @@ -108,10 +87,12 @@ limitations under the License. name="{{ name }}" value="{{ value }}" type="{{ type }}" + class="cpd-button {{ class }}" + data-kind="secondary" + data-size="lg" {% if disabled %}disabled{% endif %} {% if autocapitalize %}autocapitilize="{{ autocapitilize }}"{% endif %} {% if autocomplete %}autocomplete="{{ autocomplete }}"{% endif %} {% if autocorrect %}autocorrect="{{ autocorrect }}"{% endif %} - class="{{ self::outline_class() }} {{ class }}" >{{ text }} {% endmacro %} diff --git a/templates/components/logout.html b/templates/components/logout.html index 5c9b172f..f9c19aeb 100644 --- a/templates/components/logout.html +++ b/templates/components/logout.html @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. #} -{% macro button(text, class="", csrf_token, post_logout_action=false) %} +{% macro button(text, csrf_token, as_link=false, post_logout_action=false) %}
{% if post_logout_action %} @@ -22,7 +22,7 @@ limitations under the License. {% endfor %} {% endif %} - +
{% endmacro %} diff --git a/templates/components/navbar.html b/templates/components/navbar.html index 2e04285a..e98609f3 100644 --- a/templates/components/navbar.html +++ b/templates/components/navbar.html @@ -25,7 +25,7 @@ limitations under the License. {{ button::link(text="My account", href="/account/") }} - {{ logout::button(text="Sign out", class=button::outline_class(), csrf_token=csrf_token) }} + {{ logout::button(text="Sign out", csrf_token=csrf_token) }} {% else %} {{ button::link(text="Sign in", href="/login") }} {{ button::link_outline(text="Create an account", href="/register") }} diff --git a/templates/pages/consent.html b/templates/pages/consent.html index bf304472..5f3ca257 100644 --- a/templates/pages/consent.html +++ b/templates/pages/consent.html @@ -27,13 +27,13 @@ limitations under the License. {% endif %} -

{{ client.client_name | default(value=client.client_id) }}

+

{{ client.client_name | default(value=client.client_id) }}

at {{ grant.redirect_uri | simplify_url }}

wants to access your account

-

This will allow {{ client.client_name | default(value=client.client_id) }} to:

+

This will allow {{ client.client_name | default(value=client.client_id) }} to:

{{ scope::list(scopes=grant.scope) }} @@ -44,13 +44,13 @@ limitations under the License. {% if client.policy_uri or client.tos_uri %} Find out how {{ client.client_name }} will handle your data by reviewing it's {% if client.policy_uri %} - privacy policy{% if not client.tos_uri %}.{% endif %} + privacy policy{% if not client.tos_uri %}.{% endif %} {% endif %} {% if client.policy_uri and client.tos_uri%} and {% endif %} {% if client.tos_uri %} - terms of service. + terms of service. {% endif %} {% endif %}

@@ -63,7 +63,7 @@ limitations under the License.
{{ back_to_client::link( text="Cancel", - class=button::outline_error_class(), + kind="destructive", uri=grant.redirect_uri, mode=grant.response_mode, params=dict(error="access_denied", state=grant.state) @@ -73,7 +73,7 @@ limitations under the License.
Not {{ current_session.user.username }}? - {{ logout::button(text="Sign out", class=button::text_class(), csrf_token=csrf_token, post_logout_action=action) }} + {{ logout::button(text="Sign out", csrf_token=csrf_token, post_logout_action=action, as_link=true) }}
diff --git a/templates/pages/login.html b/templates/pages/login.html index ac5a467e..fca52e5b 100644 --- a/templates/pages/login.html +++ b/templates/pages/login.html @@ -47,7 +47,7 @@ limitations under the License.
{{ back_to_client::link( text="Cancel", - class=button::outline_error_class(), + kind="destructive", uri=next.grant.redirect_uri, mode=next.grant.response_mode, params=dict(error="access_denied", state=next.grant.state) diff --git a/templates/pages/policy_violation.html b/templates/pages/policy_violation.html index 7930b100..1adb233a 100644 --- a/templates/pages/policy_violation.html +++ b/templates/pages/policy_violation.html @@ -25,10 +25,10 @@ limitations under the License.
@@ -36,12 +36,12 @@ limitations under the License. Logged as {{ current_session.user.username }}
- {{ logout::button(text="Sign out", class=button::plain_error_class(), csrf_token=csrf_token, post_logout_action=action) }} + {{ logout::button(text="Sign out", csrf_token=csrf_token, post_logout_action=action) }}
{{ back_to_client::link( text="Cancel", - class=button::outline_error_class(), + kind="destructive", uri=grant.redirect_uri, mode=grant.response_mode, params=dict(error="access_denied", state=grant.state) diff --git a/templates/pages/reauth.html b/templates/pages/reauth.html index c919af1e..fe738c86 100644 --- a/templates/pages/reauth.html +++ b/templates/pages/reauth.html @@ -31,7 +31,7 @@ limitations under the License.
{{ back_to_client::link( text="Cancel", - class=button::outline_error_class(), + kind="destructive", uri=next.grant.redirect_uri, mode=next.grant.response_mode, params=dict(error="access_denied", state=next.grant.state) @@ -47,7 +47,7 @@ limitations under the License.
Not {{ current_session.user.username }}? {% set post_logout_action = next | safe_get(key="params") %} - {{ logout::button(text="Sign out", class=button::text_class(), csrf_token=csrf_token, post_logout_action=post_logout_action) }} + {{ logout::button(text="Sign out", csrf_token=csrf_token, post_logout_action=post_logout_action, as_link=true) }}
diff --git a/templates/pages/register.html b/templates/pages/register.html index c38b0cb4..e0fb6ea5 100644 --- a/templates/pages/register.html +++ b/templates/pages/register.html @@ -41,7 +41,7 @@ limitations under the License.
{{ back_to_client::link( text="Cancel", - class=button::outline_error_class(), + kind="destructive", uri=next.grant.redirect_uri, mode=next.grant.response_mode, params=dict(error="access_denied", state=next.grant.state) diff --git a/templates/pages/sso.html b/templates/pages/sso.html index b68a845f..73f1fd1e 100644 --- a/templates/pages/sso.html +++ b/templates/pages/sso.html @@ -44,7 +44,7 @@ limitations under the License.
Not {{ current_session.user.username }}? - {{ logout::button(text="Sign out", class=button::text_class(), csrf_token=csrf_token, post_logout_action=action) }} + {{ logout::button(text="Sign out", csrf_token=csrf_token, post_logout_action=action, as_link=true) }}
diff --git a/templates/pages/upstream_oauth2/link_mismatch.html b/templates/pages/upstream_oauth2/link_mismatch.html index 4c5cdf91..1a858db0 100644 --- a/templates/pages/upstream_oauth2/link_mismatch.html +++ b/templates/pages/upstream_oauth2/link_mismatch.html @@ -24,7 +24,7 @@ limitations under the License. This upstream account is already linked to another account. -
{{ logout::button(text="Logout", class=button::outline_class(), csrf_token=csrf_token) }}
+
{{ logout::button(text="Logout", csrf_token=csrf_token) }}
{% endblock content %} diff --git a/templates/pages/upstream_oauth2/suggest_link.html b/templates/pages/upstream_oauth2/suggest_link.html index d736804d..ca68dfe4 100644 --- a/templates/pages/upstream_oauth2/suggest_link.html +++ b/templates/pages/upstream_oauth2/suggest_link.html @@ -31,7 +31,7 @@ limitations under the License. {{ button::button(text="Link", class="flex-1") }} -
Or {{ logout::button(text="Logout", class=button::outline_class(), csrf_token=csrf_token, post_logout_action=post_logout_action) }}
+
Or {{ logout::button(text="Logout", csrf_token=csrf_token, post_logout_action=post_logout_action, as_link=true) }}
{% endblock content %}