Add URL params to control fonts

This was also a good chance to switch to the semantic font size names used in Compound.
This commit is contained in:
Robin Townsend 2022-12-09 14:25:02 -05:00
parent e6e18dd3f9
commit acc41c532e
19 changed files with 156 additions and 58 deletions

View file

@ -131,7 +131,7 @@
}
.leftNav h3 {
font-size: 18px;
font-size: var(--font-size-subtitle);
}
.nav {

View file

@ -19,7 +19,7 @@
padding: 8px 16px;
outline: none;
cursor: pointer;
font-size: 15px;
font-size: var(--font-size-body);
min-height: 32px;
}

View file

@ -12,7 +12,10 @@
align-items: center;
padding: 0 12px;
color: var(--primary-content);
font-size: 14px;
font-size: var(--font-size-body);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.menuItem > * {

View file

@ -29,7 +29,7 @@
.modalHeader h3 {
font-weight: 600;
font-size: 24px;
font-size: var(--font-size-title);
margin: 0;
}

View file

@ -8,7 +8,7 @@
border-radius: 8px;
max-width: 135px;
width: max-content;
font-size: 12px;
font-size: var(--font-size-caption);
font-weight: 500;
text-align: center;
}

View file

@ -21,30 +21,60 @@ export interface UrlParams {
roomAlias: string | null;
roomId: string | null;
viaServers: string[];
// Whether the app is running in embedded mode, and should keep the user
// confined to the current room
/**
* Whether the app is running in embedded mode, and should keep the user
* confined to the current room.
*/
isEmbedded: boolean;
// Whether the app should pause before joining the call until it sees an
// io.element.join widget action, allowing it to be preloaded
/**
* Whether the app should pause before joining the call until it sees an
* io.element.join widget action, allowing it to be preloaded.
*/
preload: boolean;
// Whether to hide the room header when in a call
/**
* Whether to hide the room header when in a call.
*/
hideHeader: boolean;
// Whether to hide the screen-sharing button
/**
* Whether to hide the screen-sharing button.
*/
hideScreensharing: boolean;
// Whether to start a walkie-talkie call instead of a video call
/**
* Whether to start a walkie-talkie call instead of a video call.
*/
isPtt: boolean;
// Whether to use end-to-end encryption
/**
* Whether to use end-to-end encryption.
*/
e2eEnabled: boolean;
// The user's ID (only used in matryoshka mode)
/**
* The user's ID (only used in matryoshka mode).
*/
userId: string | null;
// The display name to use for auto-registration
/**
* The display name to use for auto-registration.
*/
displayName: string | null;
// The device's ID (only used in matryoshka mode)
/**
* The device's ID (only used in matryoshka mode).
*/
deviceId: string | null;
// The base URL of the homeserver to use for media lookups in matryoshka mode
/**
* The base URL of the homeserver to use for media lookups in matryoshka mode.
*/
baseUrl: string | null;
// The BCP 47 code of the language the app should use
/**
* The BCP 47 code of the language the app should use.
*/
lang: string | null;
/**
* The fonts which the interface should use, if not empty.
*/
fonts: string[];
/**
* The factor by which to scale the interface's font size.
*/
fontScale: number | null;
}
/**
@ -81,6 +111,8 @@ export const getUrlParams = (
? fragment
: fragment.substring(0, fragmentQueryStart);
const fontScale = parseFloat(getParam("fontScale") ?? "");
return {
roomAlias: fragmentRoute.length > 1 ? fragmentRoute : null,
roomId: getParam("roomId"),
@ -96,6 +128,8 @@ export const getUrlParams = (
deviceId: getParam("deviceId"),
baseUrl: getParam("baseUrl"),
lang: getParam("lang"),
fonts: getAllParams("font"),
fontScale: Number.isNaN(fontScale) ? null : fontScale,
};
};

View file

@ -10,13 +10,13 @@
.avatar {
width: 24px;
height: 24px;
font-size: 12px;
font-size: var(--font-size-caption);
}
@media (min-width: 800px) {
.avatar {
width: 32px;
height: 32px;
font-size: 15px;
font-size: var(--font-size-body);
}
}

View file

@ -36,7 +36,7 @@
.formContainer h4 {
font-weight: normal;
font-size: 18px;
font-size: var(--font-size-subtitle);
margin-bottom: 0;
}
@ -48,7 +48,7 @@
.formContainer button {
height: 48px;
width: 100%;
font-size: 15px;
font-size: var(--font-size-body);
font-weight: 600;
}
@ -61,7 +61,7 @@
.authLinks {
margin-bottom: 100px;
font-size: 15px;
font-size: var(--font-size-body);
}
.authLinks a {

View file

@ -41,7 +41,7 @@ limitations under the License.
.copyButton {
padding: 7px 15px;
border-radius: 8px;
font-size: 14px;
font-size: var(--font-size-body);
font-weight: 700;
}
@ -142,7 +142,7 @@ limitations under the License.
.copyButton span {
font-weight: 600;
font-size: 15px;
font-size: var(--font-size-body);
margin-right: 10px;
overflow: hidden;
white-space: nowrap;

View file

@ -23,8 +23,20 @@ limitations under the License.
@import "normalize.css/normalize.css";
:root {
--font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
"Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
--inter-unicode-range: U+0000-20e2, U+20e4-23ce, U+23d0-24c1, U+24c3-259f,
U+25c2-2664, U+2666-2763, U+2765-2b05, U+2b07-2b1b, U+2b1d-10FFFF;
--font-scale: 1;
--font-size-micro: calc(10px * var(--font-scale));
--font-size-caption: calc(12px * var(--font-scale));
--font-size-body: calc(15px * var(--font-scale));
--font-size-subtitle: calc(18px * var(--font-scale));
--font-size-title: calc(24px * var(--font-scale));
--font-size-headline: calc(32px * var(--font-scale));
--accent: #0dbd8b;
--accent-20: #0dbd8b33;
--alert: #ff5b55;
@ -127,9 +139,7 @@ body {
color: var(--primary-content);
color-scheme: dark;
margin: 0;
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
font-family: var(--font-family);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@ -159,28 +169,31 @@ a {
/* Headline Semi Bold */
h1 {
font-weight: 600;
font-size: 32px;
line-height: 39px;
font-size: var(--font-size-headline);
}
/* Title */
h2 {
font-weight: 600;
font-size: 24px;
line-height: 29px;
font-size: var(--font-size-title);
}
/* Subtitle */
h3 {
font-weight: 400;
font-size: 18px;
line-height: 22px;
font-size: var(--font-size-subtitle);
}
h1,
h2,
h3 {
line-height: 1.2;
}
/* Body */
p {
font-size: 15px;
line-height: 24px;
font-size: var(--font-size-body);
line-height: var(--font-size-title);
}
a {
@ -202,21 +215,21 @@ hr {
text-align: center;
height: 5px;
font-weight: 600;
font-size: 15px;
font-size: var(--font-size-body);
line-height: 24px;
margin: 0 12px;
}
summary {
font-size: 14px;
font-size: var(--font-size-body);
}
details > :not(summary) {
margin-left: 16px;
margin-left: var(--font-size-body);
}
details[open] > summary {
margin-bottom: 16px;
margin-bottom: var(--font-size-body);
}
#root > [data-overlay-container] {

View file

@ -133,6 +133,21 @@ export class Initializer {
import.meta.env.VITE_THEME_BACKGROUND_85 as string
);
}
// Custom fonts
const { fonts, fontScale } = getUrlParams();
if (fontScale !== null) {
document.documentElement.style.setProperty(
"--font-scale",
fontScale.toString()
);
}
if (fonts.length > 0) {
document.documentElement.style.setProperty(
"--font-family",
fonts.map((f) => `"${f}"`).join(", ")
);
}
}
public static init(): Promise<void> | null {

View file

@ -32,7 +32,7 @@
.inputField input,
.inputField textarea {
font-weight: 400;
font-size: 15px;
font-size: var(--font-size-body);
border: none;
border-radius: 4px;
padding: 12px 9px 10px 9px;
@ -73,7 +73,7 @@
top 0.25s ease-out 0.1s, background-color 0.25s ease-out 0.1s;
color: var(--tertiary-content);
background-color: transparent;
font-size: 15px;
font-size: var(--font-size-body);
position: absolute;
left: 0;
top: 0;
@ -104,7 +104,7 @@
background-color: var(--system);
transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s,
top 0.25s ease-out 0s, background-color 0.25s ease-out 0s;
font-size: 10px;
font-size: var(--font-size-micro);
top: -13px;
padding: 0 2px;
pointer-events: auto;
@ -125,7 +125,7 @@
display: flex;
align-items: center;
flex-grow: 1;
font-size: 15px;
font-size: var(--font-size-body);
line-height: 24px;
}
@ -174,7 +174,7 @@
.errorMessage {
margin: 0;
font-size: 13px;
font-size: var(--font-size-caption);
color: var(--alert);
font-weight: 600;
}

View file

@ -7,7 +7,7 @@
.label {
font-weight: 600;
font-size: 18px;
font-size: var(--font-size-subtitle);
margin-top: 0;
margin-bottom: 12px;
}
@ -20,7 +20,7 @@
background-color: var(--background);
border-radius: 8px;
border: 1px solid var(--quinary-content);
font-size: 15px;
font-size: var(--font-size-body);
color: var(--primary-content);
height: 40px;
max-width: 100%;

View file

@ -19,7 +19,7 @@
}
.sequenceDiagramViewer :global(.messageText) {
font-size: 12px;
font-size: var(--font-size-caption);
fill: var(--primary-content) !important;
stroke: var(--primary-content) !important;
}

View file

@ -54,7 +54,7 @@ limitations under the License.
bottom: 86px;
left: 50%;
font-weight: 600;
font-size: 15px;
font-size: var(--font-size-body);
transform: translateX(-50%);
}

View file

@ -64,7 +64,7 @@
.actionTip {
margin-top: 20px;
margin-bottom: 20px;
font-size: 17px;
font-size: var(--font-size-subtitle);
}
.footer {

View file

@ -1,11 +1,11 @@
.caption {
font-size: 12px;
line-height: 15px;
font-size: var(--font-size-caption);
line-height: var(--font-size-body);
}
.micro {
font-size: 10px;
line-height: 12px;
font-size: var(--font-size-micro);
line-height: var(--font-size-caption);
}
.regular {

View file

@ -119,9 +119,9 @@
}
.memberName span {
font-size: 12px;
font-size: var(--font-size-caption);
font-weight: 400;
line-height: 16px;
line-height: var(--font-size-body);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
@ -152,8 +152,8 @@
align-items: center;
padding: 4px 8px;
font-weight: normal;
font-size: 12px;
line-height: 15px;
font-size: var(--font-size-caption);
line-height: var(--font-size-body);
}
.screensharePIP {

33
test/initializer-test.ts Normal file
View file

@ -0,0 +1,33 @@
/*
Copyright 2022 New Vector Ltd
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 { Initializer } from "../src/initializer";
test("initBeforeReact sets font family from URL param", () => {
window.location.hash = "#?font=DejaVu Sans";
Initializer.initBeforeReact();
expect(
getComputedStyle(document.documentElement).getPropertyValue("--font-family")
).toBe('"DejaVu Sans"');
});
test("initBeforeReact sets font scale from URL param", () => {
window.location.hash = "#?fontScale=1.2";
Initializer.initBeforeReact();
expect(
getComputedStyle(document.documentElement).getPropertyValue("--font-scale")
).toBe("1.2");
});