Feature: Font selector and ligature toggle.

This commit is contained in:
Paul
2021-07-04 17:56:18 +01:00
parent d5c3f9e0ab
commit 720bc263a5
19 changed files with 315 additions and 32 deletions

View File

@@ -24,14 +24,16 @@ const PermissionTooltipBase = styled.div`
display: flex;
align-items: center;
flex-direction: column;
span {
font-weight: 700;
text-transform: uppercase;
color: var(--secondary-foreground);
font-size: 11px;
}
code {
font-family: 'Fira Mono';
font-family: var(--monoscape-font);
}
`;

View File

@@ -71,7 +71,7 @@
}
pre code {
font-family: "Fira Mono", sans-serif;
font-family: var(--monoscape-font), sans-serif;
}
&[data-loading="true"] {

View File

@@ -1,5 +1,3 @@
@import "@fontsource/fira-mono/400.css";
.markdown {
:global(.emoji) {
height: 1.25em;
@@ -89,7 +87,7 @@
font-size: 90%;
border-radius: 4px;
background: var(--block);
font-family: "Fira Mono", monospace;
font-family: var(--monoscape-font), monospace;
}
input[type="checkbox"] {
@@ -136,7 +134,7 @@
}
:global(.code) {
font-family: "Fira Mono", monospace;
font-family: var(--monoscape-font), monospace;
:global(.lang) {
// height: 8px;

View File

@@ -10,7 +10,7 @@ export default styled.button<Props>`
padding: 8px;
font-size: 16px;
text-align: center;
font-family: 'Open Sans', sans-serif;
font-family: inherit;
transition: 0.2s ease opacity;
transition: 0.2s ease background-color;

View File

@@ -3,6 +3,7 @@ import styled from "styled-components";
export default styled.select`
padding: 8px;
border-radius: 2px;
font-family: inherit;
color: var(--secondary-foreground);
background: var(--secondary-background);

View File

@@ -9,6 +9,7 @@ export default styled.input<Props>`
padding: 8px 16px;
border-radius: 6px;
font-family: inherit;
color: var(--foreground);
background: var(--primary-background);
transition: 0.2s ease background-color;

View File

@@ -39,8 +39,10 @@ export default styled.textarea<TextAreaProps>`
}
${ props => props.code ? css`
font-family: 'Fira Mono', 'Courier New', Courier, monospace;
font-family: var(--monoscape-font-font), monospace;
` : css`
font-family: 'Open Sans', sans-serif;
font-family: inherit;
` }
font-variant-ligatures: var(--ligatures);
`;

View File

@@ -32,18 +32,158 @@ export type Variables =
| "status-streaming"
| "status-invisible";
export type Fonts = 'Open Sans' | 'Inter' | 'Atkinson Hyperlegible' | 'Roboto' | 'Noto Sans' | 'Lato' | 'Bree Serif' | 'Montserrat' | 'Poppins' | 'Raleway' | 'Ubuntu' | 'Comic Neue';
export type MonoscapeFonts = 'Fira Code' | 'Roboto Mono' | 'Source Code Pro' | 'Space Mono' | 'Ubuntu Mono';
export type Theme = {
[variable in Variables]: string;
} & {
light?: boolean;
font?: Fonts;
css?: string;
monoscapeFont?: MonoscapeFonts;
};
export interface ThemeOptions {
preset?: string;
ligatures?: boolean;
custom?: Partial<Theme>;
}
export const FONTS: Record<Fonts, { name: string, load: () => void }> = {
"Open Sans": {
name: "Open Sans",
load: async () => {
await import("@fontsource/open-sans/300.css");
await import("@fontsource/open-sans/400.css");
await import("@fontsource/open-sans/600.css");
await import("@fontsource/open-sans/700.css");
await import("@fontsource/open-sans/400-italic.css");
}
},
Inter: {
name: "Inter",
load: async () => {
await import("@fontsource/inter/300.css");
await import("@fontsource/inter/400.css");
await import("@fontsource/inter/600.css");
await import("@fontsource/inter/700.css");
}
},
"Atkinson Hyperlegible": {
name: "Atkinson Hyperlegible",
load: async () => {
await import("@fontsource/atkinson-hyperlegible/400.css");
await import("@fontsource/atkinson-hyperlegible/700.css");
await import("@fontsource/atkinson-hyperlegible/400-italic.css");
}
},
"Roboto": {
name: "Roboto",
load: async () => {
await import("@fontsource/roboto/400.css");
await import("@fontsource/roboto/700.css");
await import("@fontsource/roboto/400-italic.css");
}
},
"Noto Sans": {
name: "Noto Sans",
load: async () => {
await import("@fontsource/noto-sans/400.css");
await import("@fontsource/noto-sans/700.css");
await import("@fontsource/noto-sans/400-italic.css");
}
},
"Bree Serif": {
name: "Bree Serif",
load: () => import("@fontsource/bree-serif/400.css")
},
"Lato": {
name: "Lato",
load: async () => {
await import("@fontsource/lato/300.css");
await import("@fontsource/lato/400.css");
await import("@fontsource/lato/700.css");
await import("@fontsource/lato/400-italic.css");
}
},
"Montserrat": {
name: "Montserrat",
load: async () => {
await import("@fontsource/montserrat/300.css");
await import("@fontsource/montserrat/400.css");
await import("@fontsource/montserrat/600.css");
await import("@fontsource/montserrat/700.css");
await import("@fontsource/montserrat/400-italic.css");
}
},
"Poppins": {
name: "Poppins",
load: async () => {
await import("@fontsource/poppins/300.css");
await import("@fontsource/poppins/400.css");
await import("@fontsource/poppins/600.css");
await import("@fontsource/poppins/700.css");
await import("@fontsource/poppins/400-italic.css");
}
},
"Raleway": {
name: "Raleway",
load: async () => {
await import("@fontsource/raleway/300.css");
await import("@fontsource/raleway/400.css");
await import("@fontsource/raleway/600.css");
await import("@fontsource/raleway/700.css");
await import("@fontsource/raleway/400-italic.css");
}
},
"Ubuntu": {
name: "Ubuntu",
load: async () => {
await import("@fontsource/ubuntu/300.css");
await import("@fontsource/ubuntu/400.css");
await import("@fontsource/ubuntu/500.css");
await import("@fontsource/ubuntu/700.css");
await import("@fontsource/ubuntu/400-italic.css");
}
},
"Comic Neue": {
name: "Comic Neue",
load: async () => {
await import("@fontsource/comic-neue/300.css");
await import("@fontsource/comic-neue/400.css");
await import("@fontsource/comic-neue/700.css");
await import("@fontsource/comic-neue/400-italic.css");
}
}
};
export const MONOSCAPE_FONTS: Record<MonoscapeFonts, { name: string, load: () => void }> = {
"Fira Code": {
name: "Fira Code",
load: () => import("@fontsource/fira-code/400.css")
},
"Roboto Mono": {
name: "Roboto Mono",
load: () => import("@fontsource/roboto-mono/400.css")
},
"Source Code Pro": {
name: "Source Code Pro",
load: () => import("@fontsource/source-code-pro/400.css")
},
"Space Mono": {
name: "Space Mono",
load: () => import("@fontsource/space-mono/400.css")
},
"Ubuntu Mono": {
name: "Ubuntu Mono",
load: () => import("@fontsource/ubuntu-mono/400.css")
}
};
export const FONT_KEYS = Object.keys(FONTS).sort();
export const MONOSCAPE_FONT_KEYS = Object.keys(MONOSCAPE_FONTS).sort();
// Generated from https://gitlab.insrt.uk/revolt/community/themes
export const PRESETS: { [key: string]: Theme } = {
light: {
@@ -120,15 +260,32 @@ interface Props {
options?: ThemeOptions;
}
function Theme(props: Props) {
function Theme({ children, options }: Props) {
const theme: Theme = {
...PRESETS["dark"],
...(PRESETS as any)[props.options?.preset as any],
...props.options?.custom
...(PRESETS as any)[options?.preset as any],
...options?.custom
};
const root = document.documentElement.style;
useEffect(() => {
const resize = () => document.documentElement.style.setProperty('--app-height', `${window.innerHeight}px`);
const font = theme.font ?? 'Inter';
root.setProperty('--font', `"${font}"`);
FONTS[font].load();
}, [ theme.font ]);
useEffect(() => {
const font = theme.monoscapeFont ?? 'Fira Code';
root.setProperty('--monoscape-font', `"${font}"`);
MONOSCAPE_FONTS[font].load();
}, [ theme.monoscapeFont ]);
useEffect(() => {
root.setProperty('--ligatures', options?.ligatures ? 'normal' : 'none');
}, [ options?.ligatures ]);
useEffect(() => {
const resize = () => root.setProperty('--app-height', `${window.innerHeight}px`);
resize();
window.addEventListener('resize', resize);
@@ -151,7 +308,7 @@ function Theme(props: Props) {
{theme.css && (
<style dangerouslySetInnerHTML={{ __html: theme.css }} />
)}
{props.children}
{ children }
</ThemeContext.Provider>
);
}

View File

@@ -7,7 +7,7 @@
user-select: all;
font-size: 1.4em;
text-align: center;
font-family: "Fira Mono";
font-family: var(--monoscape-font);
}
}

View File

@@ -93,7 +93,7 @@
margin: 1rem 12px 0;
font-size: 10px;
color: var(--secondary-foreground);
font-family: "Fira Mono", monospace;
font-family: var(--monoscape-font), monospace;
user-select: text;
display: grid;

View File

@@ -2,15 +2,18 @@ import { Text } from "preact-i18n";
import styles from "./Panes.module.scss";
import { debounce } from "../../../lib/debounce";
import Button from "../../../components/ui/Button";
import Checkbox from "../../../components/ui/Checkbox";
import ComboBox from "../../../components/ui/ComboBox";
import InputBox from "../../../components/ui/InputBox";
import { connectState } from "../../../redux/connector";
import { WithDispatcher } from "../../../redux/reducers";
import TextAreaAutoSize from "../../../lib/TextAreaAutoSize";
import ColourSwatches from "../../../components/ui/ColourSwatches";
import { EmojiPacks, Settings } from "../../../redux/reducers/settings";
import { Theme, ThemeContext, ThemeOptions } from "../../../context/Theme";
import { useCallback, useContext, useEffect, useState } from "preact/hooks";
import { useIntermediate } from "../../../context/intermediate/Intermediate";
import CollapsibleSection from "../../../components/common/CollapsibleSection";
import { FONTS, FONT_KEYS, MONOSCAPE_FONTS, MONOSCAPE_FONT_KEYS, Theme, ThemeContext, ThemeOptions } from "../../../context/Theme";
// @ts-ignore
import pSBC from 'shade-blend-color';
@@ -22,7 +25,6 @@ import mutantSVG from '../assets/mutant_emoji.svg';
import notoSVG from '../assets/noto_emoji.svg';
import openmojiSVG from '../assets/openmoji_emoji.svg';
import twemojiSVG from '../assets/twemoji_emoji.svg';
import CollapsibleSection from "../../../components/common/CollapsibleSection";
interface Props {
settings: Settings;
@@ -130,6 +132,25 @@ export function Component(props: Props & WithDispatcher) {
</Radio>
</div>*/}
<h3>
<Text id="app.settings.pages.appearance.font" />
</h3>
<ComboBox value={theme.font} onChange={e => setTheme({ custom: { font: e.currentTarget.value as any } })}>
{
FONT_KEYS
.map(key =>
<option value={key}>{ FONTS[key as keyof typeof FONTS].name }</option>
)
}
</ComboBox>
<p>
<Checkbox checked={props.settings.theme?.ligatures === true}
onChange={() => setTheme({ ligatures: !props.settings.theme?.ligatures })}
description={<Text id="app.settings.pages.appearance.ligatures_desc" />}>
<Text id="app.settings.pages.appearance.ligatures" />
</Checkbox>
</p>
<h3>
<Text id="app.settings.pages.appearance.emoji_pack" />
</h3>
@@ -260,6 +281,19 @@ export function Component(props: Props & WithDispatcher) {
</div>
))}
</div>
<h3>
<Text id="app.settings.pages.appearance.mono_font" />
</h3>
<ComboBox value={theme.monoscapeFont} onChange={e => setTheme({ custom: { monoscapeFont: e.currentTarget.value as any } })}>
{
MONOSCAPE_FONT_KEYS
.map(key =>
<option value={key}>{ MONOSCAPE_FONTS[key as keyof typeof MONOSCAPE_FONTS].name }</option>
)
}
</ComboBox>
<h3>
<Text id="app.settings.pages.appearance.custom_css" />
</h3>

View File

@@ -65,7 +65,7 @@ export function settings(
return {
...state,
theme: {
...filter(state.theme, ["custom", "preset"]),
...filter(state.theme, ["custom", "preset", "ligatures"]),
...action.theme,
},
};

View File

@@ -1,6 +0,0 @@
@import "@fontsource/open-sans/300.css";
@import "@fontsource/open-sans/400.css";
@import "@fontsource/open-sans/600.css";
@import "@fontsource/open-sans/700.css";
@import "@fontsource/open-sans/400-italic.css";

View File

@@ -18,7 +18,9 @@ html,
body {
margin: 0;
height: 100%;
font-family: "Open Sans", sans-serif;
font-family: var(--font), sans-serif;
font-variant-ligatures: var(--ligatures);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
caret-color: var(--accent);

View File

@@ -1,4 +1,7 @@
:root {
--ligatures: none;
--font: "Open Sans";
--app-height: 100vh;
--codeblock-font: "Fira Code";
--sidebar-active: var(--secondary-background);
}

View File

@@ -1,7 +1,6 @@
@import "variables";
@import "context-menu";
@import "elements";
@import "fonts";
@import "page";
@import "react-overlapping-panels/dist";