From 1c80d5675f31a8da73f072ba5acf32d87fef35ec Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 4 Jul 2021 17:56:18 +0100 Subject: [PATCH] Feature: Font selector and ligature toggle. --- external/lang | 2 +- package.json | 17 +- src/components/common/Tooltip.tsx | 4 +- .../attachments/Attachment.module.scss | 2 +- src/components/markdown/Markdown.module.scss | 6 +- src/components/ui/Button.tsx | 2 +- src/components/ui/ComboBox.tsx | 1 + src/components/ui/InputBox.tsx | 1 + src/components/ui/TextArea.tsx | 6 +- src/context/Theme.tsx | 167 +++++++++++++++++- .../intermediate/modals/Prompt.module.scss | 2 +- src/pages/settings/Settings.module.scss | 2 +- src/pages/settings/panes/Appearance.tsx | 38 +++- src/redux/reducers/settings.ts | 2 +- src/styles/_fonts.scss | 6 - src/styles/_page.scss | 4 +- src/styles/_variables.scss | 3 + src/styles/index.scss | 1 - yarn.lock | 81 ++++++++- 19 files changed, 315 insertions(+), 32 deletions(-) delete mode 100644 src/styles/_fonts.scss diff --git a/external/lang b/external/lang index 24766f8f..6ccd5908 160000 --- a/external/lang +++ b/external/lang @@ -1 +1 @@ -Subproject commit 24766f8f5c2147ba866af922e3f5f42ad3ea44e4 +Subproject commit 6ccd590846c35e8d3b948e9203510ccf8718a79c diff --git a/package.json b/package.json index 595b73b7..eea55162 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,23 @@ "preact": "^10.5.13" }, "devDependencies": { - "@fontsource/fira-mono": "^4.4.5", + "@fontsource/atkinson-hyperlegible": "^4.4.5", + "@fontsource/bree-serif": "^4.4.5", + "@fontsource/comic-neue": "^4.4.5", + "@fontsource/fira-code": "^4.4.5", + "@fontsource/inter": "^4.4.5", + "@fontsource/lato": "^4.4.5", + "@fontsource/montserrat": "^4.4.5", + "@fontsource/noto-sans": "^4.4.5", "@fontsource/open-sans": "^4.4.5", + "@fontsource/poppins": "^4.4.5", + "@fontsource/raleway": "^4.4.5", + "@fontsource/roboto": "^4.4.5", + "@fontsource/roboto-mono": "^4.4.5", + "@fontsource/source-code-pro": "^4.4.5", + "@fontsource/space-mono": "^4.4.5", + "@fontsource/ubuntu": "^4.4.5", + "@fontsource/ubuntu-mono": "^4.4.5", "@hcaptcha/react-hcaptcha": "^0.3.6", "@preact/preset-vite": "^2.0.0", "@rollup/plugin-replace": "^2.4.2", diff --git a/src/components/common/Tooltip.tsx b/src/components/common/Tooltip.tsx index c8497e40..7a9957f4 100644 --- a/src/components/common/Tooltip.tsx +++ b/src/components/common/Tooltip.tsx @@ -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); } `; diff --git a/src/components/common/messaging/attachments/Attachment.module.scss b/src/components/common/messaging/attachments/Attachment.module.scss index 4f23a898..d71e3a67 100644 --- a/src/components/common/messaging/attachments/Attachment.module.scss +++ b/src/components/common/messaging/attachments/Attachment.module.scss @@ -71,7 +71,7 @@ } pre code { - font-family: "Fira Mono", sans-serif; + font-family: var(--monoscape-font), sans-serif; } &[data-loading="true"] { diff --git a/src/components/markdown/Markdown.module.scss b/src/components/markdown/Markdown.module.scss index de439a34..202ce12e 100644 --- a/src/components/markdown/Markdown.module.scss +++ b/src/components/markdown/Markdown.module.scss @@ -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; diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx index 8582a193..870e7ed2 100644 --- a/src/components/ui/Button.tsx +++ b/src/components/ui/Button.tsx @@ -10,7 +10,7 @@ export default styled.button` 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; diff --git a/src/components/ui/ComboBox.tsx b/src/components/ui/ComboBox.tsx index ef9ba9f9..6551c9ca 100644 --- a/src/components/ui/ComboBox.tsx +++ b/src/components/ui/ComboBox.tsx @@ -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); diff --git a/src/components/ui/InputBox.tsx b/src/components/ui/InputBox.tsx index ac374646..75e3510b 100644 --- a/src/components/ui/InputBox.tsx +++ b/src/components/ui/InputBox.tsx @@ -9,6 +9,7 @@ export default styled.input` padding: 8px 16px; border-radius: 6px; + font-family: inherit; color: var(--foreground); background: var(--primary-background); transition: 0.2s ease background-color; diff --git a/src/components/ui/TextArea.tsx b/src/components/ui/TextArea.tsx index d61e43c7..88f5959d 100644 --- a/src/components/ui/TextArea.tsx +++ b/src/components/ui/TextArea.tsx @@ -39,8 +39,10 @@ export default styled.textarea` } ${ 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); `; diff --git a/src/context/Theme.tsx b/src/context/Theme.tsx index f0e6db40..5ce7fe32 100644 --- a/src/context/Theme.tsx +++ b/src/context/Theme.tsx @@ -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; } +export const FONTS: Record 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 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 && (