From ee5e558e9f79cf58aa9714143c5fbb07872dd7fb Mon Sep 17 00:00:00 2001 From: bree Date: Fri, 2 Jul 2021 22:37:45 -0400 Subject: [PATCH 01/21] fix long width image previews to fit into view --- src/components/common/messaging/bars/FilePreview.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/common/messaging/bars/FilePreview.tsx b/src/components/common/messaging/bars/FilePreview.tsx index 9f0a98c4..80f9fae5 100644 --- a/src/components/common/messaging/bars/FilePreview.tsx +++ b/src/components/common/messaging/bars/FilePreview.tsx @@ -101,6 +101,7 @@ const PreviewBox = styled.div` .icon { height: 100px; + width: 100%; margin-bottom: 4px; object-fit: contain; } From 036e9a330ad52f569f1b133245d7b4e5cb6bd79a Mon Sep 17 00:00:00 2001 From: bree Date: Fri, 2 Jul 2021 22:40:53 -0400 Subject: [PATCH 02/21] replace js image scaling with css for message attachments --- .../attachments/Attachment.module.scss | 8 ++++ .../messaging/attachments/Attachment.tsx | 38 +------------------ 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/components/common/messaging/attachments/Attachment.module.scss b/src/components/common/messaging/attachments/Attachment.module.scss index 4f23a898..92c3545b 100644 --- a/src/components/common/messaging/attachments/Attachment.module.scss +++ b/src/components/common/messaging/attachments/Attachment.module.scss @@ -2,6 +2,14 @@ border-radius: 6px; margin: .125rem 0 .125rem; + width: auto; + height: auto; + + max-height: 640px; + max-width: min(480px, 100%); + + object-fit: contain; + &[data-spoiler="true"] { filter: blur(30px); pointer-events: none; diff --git a/src/components/common/messaging/attachments/Attachment.tsx b/src/components/common/messaging/attachments/Attachment.tsx index eb144ebe..342a5984 100644 --- a/src/components/common/messaging/attachments/Attachment.tsx +++ b/src/components/common/messaging/attachments/Attachment.tsx @@ -15,55 +15,26 @@ interface Props { } const MAX_ATTACHMENT_WIDTH = 480; -const MAX_ATTACHMENT_HEIGHT = 640; export default function Attachment({ attachment, hasContent }: Props) { const client = useContext(AppContext); const { openScreen } = useIntermediate(); const { filename, metadata } = attachment; const [ spoiler, setSpoiler ] = useState(filename.startsWith("SPOILER_")); - const maxWidth = Math.min(useContext(MessageAreaWidthContext), MAX_ATTACHMENT_WIDTH); const url = client.generateFileURL(attachment, { width: MAX_ATTACHMENT_WIDTH * 1.5 }, true); - let width = 0, - height = 0; - - if (metadata.type === 'Image' || metadata.type === 'Video') { - let limitingWidth = Math.min( - maxWidth, - metadata.width - ); - let limitingHeight = Math.min( - MAX_ATTACHMENT_HEIGHT, - metadata.height - ); - - // Calculate smallest possible WxH. - width = Math.min( - limitingWidth, - limitingHeight * (metadata.width / metadata.height) - ); - - height = Math.min( - limitingHeight, - limitingWidth * (metadata.height / metadata.width) - ); - } switch (metadata.type) { case "Image": { return (
spoiler && setSpoiler(false)} > {spoiler && (
-
- -
+
)}
); @@ -102,13 +72,10 @@ export default function Attachment({ attachment, hasContent }: Props) { onClick={() => spoiler && setSpoiler(false)}> {spoiler && (
-
- -
+
)}
ev.button === 1 && window.open(url, "_blank") From b8216847334349c66f5c3199efc94f4d73447f9d Mon Sep 17 00:00:00 2001 From: bree Date: Sat, 3 Jul 2021 01:47:46 -0400 Subject: [PATCH 03/21] image attachments now have their width and height properly set --- src/components/common/messaging/attachments/Attachment.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/common/messaging/attachments/Attachment.tsx b/src/components/common/messaging/attachments/Attachment.tsx index 342a5984..15c42536 100644 --- a/src/components/common/messaging/attachments/Attachment.tsx +++ b/src/components/common/messaging/attachments/Attachment.tsx @@ -40,6 +40,8 @@ export default function Attachment({ attachment, hasContent }: Props) { {filename} Date: Sun, 4 Jul 2021 00:48:24 -0400 Subject: [PATCH 04/21] Fix: Chrome support for css image scaling --- .../common/messaging/attachments/Attachment.module.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/common/messaging/attachments/Attachment.module.scss b/src/components/common/messaging/attachments/Attachment.module.scss index 92c3545b..6836ea31 100644 --- a/src/components/common/messaging/attachments/Attachment.module.scss +++ b/src/components/common/messaging/attachments/Attachment.module.scss @@ -2,7 +2,6 @@ border-radius: 6px; margin: .125rem 0 .125rem; - width: auto; height: auto; max-height: 640px; From e0b9567c96bdd6cf00c56f065004b523ca027db5 Mon Sep 17 00:00:00 2001 From: nizune <9-nizune@users.noreply.gitlab.insrt.uk> Date: Sun, 4 Jul 2021 10:41:03 +0200 Subject: [PATCH 05/21] Fix: Small header fixes --- src/components/ui/Header.tsx | 2 +- src/pages/developer/Developer.tsx | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/ui/Header.tsx b/src/components/ui/Header.tsx index 37652397..d4e0e3f9 100644 --- a/src/components/ui/Header.tsx +++ b/src/components/ui/Header.tsx @@ -46,6 +46,6 @@ export default styled.div` ` } ${ props => props.borders && css` - border-end-start-radius: 8px; + border-start-start-radius: 8px; ` } `; diff --git a/src/pages/developer/Developer.tsx b/src/pages/developer/Developer.tsx index 1a392bc0..e8c3e187 100644 --- a/src/pages/developer/Developer.tsx +++ b/src/pages/developer/Developer.tsx @@ -4,6 +4,7 @@ import Header from "../../components/ui/Header"; import PaintCounter from "../../lib/PaintCounter"; import { AppContext } from "../../context/revoltjs/RevoltClient"; import { useUserPermission } from "../../context/revoltjs/hooks"; +import { Wrench } from "@styled-icons/boxicons-solid"; export default function Developer() { // const voice = useContext(VoiceContext); @@ -12,7 +13,10 @@ export default function Developer() { return (
-
Developer Tab
+
+ + Developer Tab +
From 12b04a98328e51cf06bacf5266f698cff62e574a Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 4 Jul 2021 09:52:34 +0100 Subject: [PATCH 06/21] Move details styling into its own component. --- src/components/ui/Details.tsx | 28 ++++++++++++++++++++++++++++ src/lib/TextAreaAutoSize.tsx | 1 + src/pages/friends/Friend.module.scss | 27 --------------------------- src/pages/friends/Friends.tsx | 5 +++-- 4 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 src/components/ui/Details.tsx diff --git a/src/components/ui/Details.tsx b/src/components/ui/Details.tsx new file mode 100644 index 00000000..8bf47059 --- /dev/null +++ b/src/components/ui/Details.tsx @@ -0,0 +1,28 @@ +import styled from "styled-components"; + +export default styled.details` + summary { + outline: none; + list-style: none; + transition: .2s opacity; + + &::marker, &::-webkit-details-marker { + display: none; + } + + svg { + flex-shrink: 0; + transition: .2s ease transform; + } + } + + &:not([open]) { + summary { + opacity: .7; + } + + summary svg { + transform: rotateZ(-90deg); + } + } +`; diff --git a/src/lib/TextAreaAutoSize.tsx b/src/lib/TextAreaAutoSize.tsx index bfc515b0..c6026554 100644 --- a/src/lib/TextAreaAutoSize.tsx +++ b/src/lib/TextAreaAutoSize.tsx @@ -23,6 +23,7 @@ export default function TextAreaAutoSize(props: TextAreaAutoSizeProps) { const ref = useRef(); useEffect(() => { + if (isTouchscreenDevice) return; autoFocus && ref.current.focus(); }, [value]); diff --git a/src/pages/friends/Friend.module.scss b/src/pages/friends/Friend.module.scss index af867b28..fe103bf7 100644 --- a/src/pages/friends/Friend.module.scss +++ b/src/pages/friends/Friend.module.scss @@ -39,33 +39,6 @@ } } - details { - summary { - outline: none; - list-style: none; - transition: .2s opacity; - - &::marker, &::-webkit-details-marker { - display: none; - } - - svg { - flex-shrink: 0; - transition: .2s ease transform; - } - } - - &:not([open]) { - summary { - opacity: .7; - } - - summary svg { - transform: rotateZ(-90deg); - } - } - } - &[data-empty="true"] { img { height: 120px; diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index 7ccf4761..607f6d8f 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -14,6 +14,7 @@ import { ChevronDown, ChevronRight, ListPlus } from "@styled-icons/boxicons-regu import { UserDetail, MessageAdd, UserPlus } from "@styled-icons/boxicons-solid"; import { TextReact } from "../../lib/i18n"; import { Children } from "../../types/Preact"; +import Details from "../../components/ui/Details"; export default function Friends() { const { openScreen } = useIntermediate(); @@ -112,7 +113,7 @@ export default function Friends() { if (list.length === 0) return; return ( -
+
@@ -122,7 +123,7 @@ export default function Friends() { { list.map(x => ) } -
+
) }) } From 86aa869ef753fc8ebf4dd59fdea66915acee66d5 Mon Sep 17 00:00:00 2001 From: nizune <9-nizune@users.noreply.gitlab.insrt.uk> Date: Sun, 4 Jul 2021 13:41:52 +0200 Subject: [PATCH 07/21] Fix: Small changes to profile context menu --- src/components/navigation/right/MemberSidebar.tsx | 1 + src/pages/friends/Friend.module.scss | 1 - src/pages/friends/Friends.tsx | 2 +- src/pages/settings/server/Roles.tsx | 2 +- src/styles/_context-menu.scss | 8 +++++++- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/navigation/right/MemberSidebar.tsx b/src/components/navigation/right/MemberSidebar.tsx index 96b3728f..e8cc3601 100644 --- a/src/components/navigation/right/MemberSidebar.tsx +++ b/src/components/navigation/right/MemberSidebar.tsx @@ -2,6 +2,7 @@ import { Text } from "preact-i18n"; import { useContext, useEffect, useState } from "preact/hooks"; import { User } from "revolt.js"; +import Details from "../../../components/ui/Details"; import Category from "../../ui/Category"; import { useParams } from "react-router"; import { UserButton } from "../items/ButtonItem"; diff --git a/src/pages/friends/Friend.module.scss b/src/pages/friends/Friend.module.scss index fe103bf7..d6338774 100644 --- a/src/pages/friends/Friend.module.scss +++ b/src/pages/friends/Friend.module.scss @@ -118,7 +118,6 @@ .divider { width: 1px; height: 24px; - margin: 0 8px; background: var(--primary-background); } diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index 607f6d8f..284641e7 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -57,7 +57,7 @@ export default function Friends() {
{/* openScreen({ id: 'special_input', type: 'create_group' })}> - +
*/} diff --git a/src/pages/settings/server/Roles.tsx b/src/pages/settings/server/Roles.tsx index db3887c3..0fea1988 100644 --- a/src/pages/settings/server/Roles.tsx +++ b/src/pages/settings/server/Roles.tsx @@ -49,7 +49,7 @@ export function Roles({ server }: Props) {

- + openScreen({ id: 'special_input', type: 'create_role', server: server._id, callback: id => setRole(id) })} />
{ [ 'default', ...Object.keys(roles) ] diff --git a/src/styles/_context-menu.scss b/src/styles/_context-menu.scss index 8f33978b..d5f15ee1 100644 --- a/src/styles/_context-menu.scss +++ b/src/styles/_context-menu.scss @@ -51,7 +51,13 @@ } .status { - font-size: .6rem; + max-width: 132px; + font-size: .625rem; + color: var(--secondary-foreground); + + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } } From 8e0e226ec6f9bcb6bcdb6a49751dcd4df411b4c1 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 4 Jul 2021 12:46:33 +0100 Subject: [PATCH 08/21] Fix: Defaults / dayjs will not always be present. --- src/context/Locale.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/Locale.tsx b/src/context/Locale.tsx index 0385745c..ea75394a 100644 --- a/src/context/Locale.tsx +++ b/src/context/Locale.tsx @@ -127,7 +127,7 @@ function Locale({ children, locale }: Props) { function transformLanguage(obj: { [key: string]: any }) { const dayjs = obj.dayjs; - const defaults = dayjs.defaults; + const defaults = dayjs?.defaults; const twelvehour = defaults?.twelvehour === 'yes' || true; const separator: '/' | '-' | '.' = defaults?.date_separator ?? '/'; From 4e28470d2dd23d8cb2aeb8e034f396dbaf4a2f92 Mon Sep 17 00:00:00 2001 From: nizune <9-nizune@users.noreply.gitlab.insrt.uk> Date: Sun, 4 Jul 2021 10:41:03 +0200 Subject: [PATCH 09/21] Fix: Small header fixes --- src/components/ui/Header.tsx | 2 +- src/pages/developer/Developer.tsx | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/ui/Header.tsx b/src/components/ui/Header.tsx index 37652397..d4e0e3f9 100644 --- a/src/components/ui/Header.tsx +++ b/src/components/ui/Header.tsx @@ -46,6 +46,6 @@ export default styled.div` ` } ${ props => props.borders && css` - border-end-start-radius: 8px; + border-start-start-radius: 8px; ` } `; diff --git a/src/pages/developer/Developer.tsx b/src/pages/developer/Developer.tsx index 1a392bc0..e8c3e187 100644 --- a/src/pages/developer/Developer.tsx +++ b/src/pages/developer/Developer.tsx @@ -4,6 +4,7 @@ import Header from "../../components/ui/Header"; import PaintCounter from "../../lib/PaintCounter"; import { AppContext } from "../../context/revoltjs/RevoltClient"; import { useUserPermission } from "../../context/revoltjs/hooks"; +import { Wrench } from "@styled-icons/boxicons-solid"; export default function Developer() { // const voice = useContext(VoiceContext); @@ -12,7 +13,10 @@ export default function Developer() { return (
-
Developer Tab
+
+ + Developer Tab +
From 1a08f50997c3900dc1c6a821242bb04e85b00729 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 4 Jul 2021 09:52:34 +0100 Subject: [PATCH 10/21] Move details styling into its own component. --- src/components/ui/Details.tsx | 28 ++++++++++++++++++++++++++++ src/lib/TextAreaAutoSize.tsx | 1 + src/pages/friends/Friend.module.scss | 27 --------------------------- src/pages/friends/Friends.tsx | 5 +++-- 4 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 src/components/ui/Details.tsx diff --git a/src/components/ui/Details.tsx b/src/components/ui/Details.tsx new file mode 100644 index 00000000..8bf47059 --- /dev/null +++ b/src/components/ui/Details.tsx @@ -0,0 +1,28 @@ +import styled from "styled-components"; + +export default styled.details` + summary { + outline: none; + list-style: none; + transition: .2s opacity; + + &::marker, &::-webkit-details-marker { + display: none; + } + + svg { + flex-shrink: 0; + transition: .2s ease transform; + } + } + + &:not([open]) { + summary { + opacity: .7; + } + + summary svg { + transform: rotateZ(-90deg); + } + } +`; diff --git a/src/lib/TextAreaAutoSize.tsx b/src/lib/TextAreaAutoSize.tsx index bfc515b0..c6026554 100644 --- a/src/lib/TextAreaAutoSize.tsx +++ b/src/lib/TextAreaAutoSize.tsx @@ -23,6 +23,7 @@ export default function TextAreaAutoSize(props: TextAreaAutoSizeProps) { const ref = useRef(); useEffect(() => { + if (isTouchscreenDevice) return; autoFocus && ref.current.focus(); }, [value]); diff --git a/src/pages/friends/Friend.module.scss b/src/pages/friends/Friend.module.scss index af867b28..fe103bf7 100644 --- a/src/pages/friends/Friend.module.scss +++ b/src/pages/friends/Friend.module.scss @@ -39,33 +39,6 @@ } } - details { - summary { - outline: none; - list-style: none; - transition: .2s opacity; - - &::marker, &::-webkit-details-marker { - display: none; - } - - svg { - flex-shrink: 0; - transition: .2s ease transform; - } - } - - &:not([open]) { - summary { - opacity: .7; - } - - summary svg { - transform: rotateZ(-90deg); - } - } - } - &[data-empty="true"] { img { height: 120px; diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index 7ccf4761..607f6d8f 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -14,6 +14,7 @@ import { ChevronDown, ChevronRight, ListPlus } from "@styled-icons/boxicons-regu import { UserDetail, MessageAdd, UserPlus } from "@styled-icons/boxicons-solid"; import { TextReact } from "../../lib/i18n"; import { Children } from "../../types/Preact"; +import Details from "../../components/ui/Details"; export default function Friends() { const { openScreen } = useIntermediate(); @@ -112,7 +113,7 @@ export default function Friends() { if (list.length === 0) return; return ( -
+
@@ -122,7 +123,7 @@ export default function Friends() { { list.map(x => ) } -
+
) }) } From 49e49f3952d2232d9f449abd496759479acedcc6 Mon Sep 17 00:00:00 2001 From: nizune <9-nizune@users.noreply.gitlab.insrt.uk> Date: Sun, 4 Jul 2021 13:41:52 +0200 Subject: [PATCH 11/21] Fix: Small changes to profile context menu --- src/components/navigation/right/MemberSidebar.tsx | 1 + src/pages/friends/Friend.module.scss | 1 - src/pages/friends/Friends.tsx | 2 +- src/pages/settings/server/Roles.tsx | 2 +- src/styles/_context-menu.scss | 8 +++++++- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/navigation/right/MemberSidebar.tsx b/src/components/navigation/right/MemberSidebar.tsx index 96b3728f..e8cc3601 100644 --- a/src/components/navigation/right/MemberSidebar.tsx +++ b/src/components/navigation/right/MemberSidebar.tsx @@ -2,6 +2,7 @@ import { Text } from "preact-i18n"; import { useContext, useEffect, useState } from "preact/hooks"; import { User } from "revolt.js"; +import Details from "../../../components/ui/Details"; import Category from "../../ui/Category"; import { useParams } from "react-router"; import { UserButton } from "../items/ButtonItem"; diff --git a/src/pages/friends/Friend.module.scss b/src/pages/friends/Friend.module.scss index fe103bf7..d6338774 100644 --- a/src/pages/friends/Friend.module.scss +++ b/src/pages/friends/Friend.module.scss @@ -118,7 +118,6 @@ .divider { width: 1px; height: 24px; - margin: 0 8px; background: var(--primary-background); } diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index 607f6d8f..284641e7 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -57,7 +57,7 @@ export default function Friends() {
{/* openScreen({ id: 'special_input', type: 'create_group' })}> - +
*/} diff --git a/src/pages/settings/server/Roles.tsx b/src/pages/settings/server/Roles.tsx index db3887c3..0fea1988 100644 --- a/src/pages/settings/server/Roles.tsx +++ b/src/pages/settings/server/Roles.tsx @@ -49,7 +49,7 @@ export function Roles({ server }: Props) {

- + openScreen({ id: 'special_input', type: 'create_role', server: server._id, callback: id => setRole(id) })} />
{ [ 'default', ...Object.keys(roles) ] diff --git a/src/styles/_context-menu.scss b/src/styles/_context-menu.scss index 8f33978b..d5f15ee1 100644 --- a/src/styles/_context-menu.scss +++ b/src/styles/_context-menu.scss @@ -51,7 +51,13 @@ } .status { - font-size: .6rem; + max-width: 132px; + font-size: .625rem; + color: var(--secondary-foreground); + + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } } From 098e28113b49b25237d786bf79a793e43e812f68 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 4 Jul 2021 13:02:32 +0100 Subject: [PATCH 12/21] Fix: Handle defaults before transforming languages. Remove Hardcore Mode. --- src/context/Locale.tsx | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/context/Locale.tsx b/src/context/Locale.tsx index ea75394a..4afc9f50 100644 --- a/src/context/Locale.tsx +++ b/src/context/Locale.tsx @@ -43,7 +43,6 @@ export enum Language { PIRATE = "pr", BOTTOM = "bottom", PIGLATIN = "piglatin", - HARDCORE = "hardcore", } export interface LanguageEntry { @@ -107,13 +106,6 @@ export const Languages: { [key in Language]: LanguageEntry } = { dayjs: "en-gb", alt: true }, - hardcore: { - display: "Hardcore Mode", - emoji: "🔥", - i18n: "hardcore", - dayjs: "en-gb", - alt: true - }, }; interface Props { @@ -125,9 +117,11 @@ function Locale({ children, locale }: Props) { const [defns, setDefinition] = useState(definition); const lang = Languages[locale]; - function transformLanguage(obj: { [key: string]: any }) { + function transformLanguage(source: { [key: string]: any }) { + const obj = defaultsDeep(source, definition); + const dayjs = obj.dayjs; - const defaults = dayjs?.defaults; + const defaults = dayjs.defaults; const twelvehour = defaults?.twelvehour === 'yes' || true; const separator: '/' | '-' | '.' = defaults?.date_separator ?? '/'; @@ -149,10 +143,10 @@ function Locale({ children, locale }: Props) { useEffect(() => { if (locale === "en") { - transformLanguage(definition); - setDefinition(definition); + const defn = transformLanguage(definition); + setDefinition(defn); dayjs.locale("en"); - dayjs.updateLocale('en', { calendar: definition.dayjs }); + dayjs.updateLocale('en', { calendar: defn.dayjs }); return; } @@ -164,8 +158,7 @@ function Locale({ children, locale }: Props) { import(`../../external/lang/${lang.i18n}.json`).then( async (lang_file) => { - const defn = lang_file.default; - transformLanguage(defn); + const defn = transformLanguage(lang_file.default); const target = lang.dayjs ?? lang.i18n; const dayjs_locale = await import(`../../node_modules/dayjs/esm/locale/${target}.js`); @@ -174,7 +167,7 @@ function Locale({ children, locale }: Props) { } dayjs.locale(dayjs_locale.default); - setDefinition(defaultsDeep(defn, definition)); + setDefinition(defn); } ); }, [locale, lang]); From 1768264272e8c68953bc3a84b61f6e43d378da08 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 4 Jul 2021 15:53:06 +0100 Subject: [PATCH 13/21] Add collapsible section component. Can now collapse server categories. Client remembers collapse state, incl. advanced appearance settings. --- src/components/common/CollapsibleSection.tsx | 52 +++++++++++++++++++ .../navigation/left/HomeSidebar.tsx | 15 ++---- .../navigation/left/ServerSidebar.tsx | 21 +++++--- src/components/ui/Category.tsx | 2 +- src/components/ui/Details.tsx | 19 +++++-- src/components/ui/Overline.tsx | 6 ++- src/context/Locale.tsx | 6 --- src/pages/friends/Friend.module.scss | 24 --------- src/pages/friends/Friends.tsx | 31 +++++------ src/pages/settings/panes/Appearance.tsx | 9 ++-- src/redux/index.ts | 8 ++- src/redux/reducers/index.ts | 5 +- src/redux/reducers/section_toggle.ts | 37 +++++++++++++ 13 files changed, 157 insertions(+), 78 deletions(-) create mode 100644 src/components/common/CollapsibleSection.tsx create mode 100644 src/redux/reducers/section_toggle.ts diff --git a/src/components/common/CollapsibleSection.tsx b/src/components/common/CollapsibleSection.tsx new file mode 100644 index 00000000..1f31e21b --- /dev/null +++ b/src/components/common/CollapsibleSection.tsx @@ -0,0 +1,52 @@ +import Details from "../ui/Details"; +import { State, store } from "../../redux"; +import { Action } from "../../redux/reducers"; +import { Children } from "../../types/Preact"; +import { ChevronDown } from "@styled-icons/boxicons-regular"; + +interface Props { + id: string; + defaultValue: boolean; + + sticky?: boolean; + large?: boolean; + + summary: Children; + children: Children; +} + +export default function CollapsibleSection({ id, defaultValue, summary, children, ...detailsProps }: Props) { + const state: State = store.getState(); + + function setState(state: boolean) { + if (state === defaultValue) { + store.dispatch({ + type: 'SECTION_TOGGLE_UNSET', + id + } as Action); + } else { + store.dispatch({ + type: 'SECTION_TOGGLE_SET', + id, + state + } as Action); + } + } + + return ( +
setState(e.currentTarget.open)} + {...detailsProps}> + + + { summary } + {/**/} + {/*
*/} + {/*
*/} + {/*
*/} +
+ { children } +
+ ) +} diff --git a/src/components/navigation/left/HomeSidebar.tsx b/src/components/navigation/left/HomeSidebar.tsx index edde0aaa..16e586bb 100644 --- a/src/components/navigation/left/HomeSidebar.tsx +++ b/src/components/navigation/left/HomeSidebar.tsx @@ -1,4 +1,4 @@ -import { Localizer, Text } from "preact-i18n"; +import { Text } from "preact-i18n"; import { useContext, useEffect } from "preact/hooks"; import { Home, UserDetail, Wrench, Notepad } from "@styled-icons/boxicons-solid"; @@ -105,16 +105,9 @@ function HomeSidebar(props: Props) { )} - - - ) as any - } - action={() => openScreen({ id: "special_input", type: "create_group" })} - /> - + } + action={() => openScreen({ id: "special_input", type: "create_group" })} /> {channelsArr.length === 0 && } {channelsArr.map(x => { let user; diff --git a/src/components/navigation/left/ServerSidebar.tsx b/src/components/navigation/left/ServerSidebar.tsx index 49e57959..3dd7aff9 100644 --- a/src/components/navigation/left/ServerSidebar.tsx +++ b/src/components/navigation/left/ServerSidebar.tsx @@ -14,6 +14,7 @@ import ServerHeader from "../../common/ServerHeader"; import { useEffect } from "preact/hooks"; import Category from "../../ui/Category"; import ConditionalLink from "../../../lib/ConditionalLink"; +import CollapsibleSection from "../../common/CollapsibleSection"; interface Props { unreads: Unreads; @@ -69,6 +70,7 @@ function ServerSidebar(props: Props & WithDispatcher) { let uncategorised = new Set(server.channels); let elements = []; + function addChannel(id: string) { const entry = channels.find(x => x._id === id); if (!entry) return; @@ -76,9 +78,8 @@ function ServerSidebar(props: Props & WithDispatcher) { const active = channel?._id === entry._id; return ( - + ); - + let channels = []; for (let id of category.channels) { uncategorised.delete(id); - elements.push(addChannel(id)); + channels.push(addChannel(id)); } + + elements.push( + }> + { channels } + + ); } } - for (let id of uncategorised) { + for (let id of Array.from(uncategorised).reverse()) { elements.unshift(addChannel(id)); } diff --git a/src/components/ui/Category.tsx b/src/components/ui/Category.tsx index ccdd4e91..3f76d284 100644 --- a/src/components/ui/Category.tsx +++ b/src/components/ui/Category.tsx @@ -31,7 +31,7 @@ const CategoryBase = styled.div>` ` } `; -type Props = Omit, 'children' | 'as'> & { +type Props = Omit, 'children' | 'as' | 'action'> & { text: Children; action?: () => void; variant?: 'default' | 'uniform'; diff --git a/src/components/ui/Details.tsx b/src/components/ui/Details.tsx index 8bf47059..0a032022 100644 --- a/src/components/ui/Details.tsx +++ b/src/components/ui/Details.tsx @@ -1,16 +1,29 @@ -import styled from "styled-components"; +import styled, { css } from "styled-components"; -export default styled.details` +export default styled.details<{ sticky?: boolean, large?: boolean }>` summary { + ${ props => props.sticky && css` + top: -1px; + z-index: 10; + position: sticky; + ` } + + ${ props => props.large && css` + padding: 5px 0; + ` } + outline: none; + display: flex; + cursor: pointer; list-style: none; + align-items: center; transition: .2s opacity; &::marker, &::-webkit-details-marker { display: none; } - svg { + > svg { flex-shrink: 0; transition: .2s ease transform; } diff --git a/src/components/ui/Overline.tsx b/src/components/ui/Overline.tsx index 5a9f9d04..17159077 100644 --- a/src/components/ui/Overline.tsx +++ b/src/components/ui/Overline.tsx @@ -5,6 +5,7 @@ import { Text } from 'preact-i18n'; type Props = Omit, 'children' | 'as'> & { error?: string; block?: boolean; + spaced?: boolean; children?: Children; type?: "default" | "subtle" | "error"; } @@ -12,7 +13,10 @@ type Props = Omit, 'children' | 'as'> & { const OverlineBase = styled.div>` display: inline; margin: 0.4em 0; - margin-top: 0.8em; + + ${ props => props.spaced && css` + margin-top: 0.8em; + ` } font-size: 14px; font-weight: 600; diff --git a/src/context/Locale.tsx b/src/context/Locale.tsx index 4afc9f50..873d57a6 100644 --- a/src/context/Locale.tsx +++ b/src/context/Locale.tsx @@ -150,12 +150,6 @@ function Locale({ children, locale }: Props) { return; } - if (lang.i18n === "hardcore") { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - setDefinition({} as any); - return; - } - import(`../../external/lang/${lang.i18n}.json`).then( async (lang_file) => { const defn = transformLanguage(lang_file.default); diff --git a/src/pages/friends/Friend.module.scss b/src/pages/friends/Friend.module.scss index d6338774..ee9c6f90 100644 --- a/src/pages/friends/Friend.module.scss +++ b/src/pages/friends/Friend.module.scss @@ -14,30 +14,6 @@ padding: 0 10px 10px 10px; user-select: none; overflow-y: scroll; - - summary { - position: sticky; - z-index: 10; - top: -1px; - } - - .overline { - display: flex; - align-items: center; - background: var(--primary-background); - padding: 5px 0; - cursor: pointer; - - .title { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - - svg { - margin-inline-end: 4px; - } - } &[data-empty="true"] { img { diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index 284641e7..01d36085 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -15,6 +15,7 @@ import { UserDetail, MessageAdd, UserPlus } from "@styled-icons/boxicons-solid"; import { TextReact } from "../../lib/i18n"; import { Children } from "../../types/Preact"; import Details from "../../components/ui/Details"; +import CollapsibleSection from "../../components/common/CollapsibleSection"; export default function Friends() { const { openScreen } = useIntermediate(); @@ -30,17 +31,17 @@ export default function Friends() { ) ], [ 'app.special.friends.sent', users.filter(x => x.relationship === Users.Relationship.Outgoing - ) ], + ), 'outgoing' ], [ 'app.status.online', friends.filter(x => x.online && x.status?.presence !== Users.Presence.Invisible - ) ], + ), 'online' ], [ 'app.status.offline', friends.filter(x => !x.online || x.status?.presence === Users.Presence.Invisible - ) ], - [ 'app.special.friends.blocked', friends.filter(x => + ), 'offline' ], + [ 'app.special.friends.blocked', users.filter(x => x.relationship === Users.Relationship.Blocked - ) ] - ] as [ string, User[] ][]; + ), 'blocked' ] + ] as [ string, User[], string ][]; const incoming = lists[0][1]; const userlist: Children[] = incoming.map(x => { x.username }); @@ -108,22 +109,18 @@ export default function Friends() {
} { - lists.map(([i18n, list], index) => { + lists.map(([i18n, list, section_id], index) => { if (index === 0) return; if (list.length === 0) return; return ( -
- - - -
- — { list.length } -
-
-
+ — { list.length }}> { list.map(x => ) } -
+ ) }) } diff --git a/src/pages/settings/panes/Appearance.tsx b/src/pages/settings/panes/Appearance.tsx index b0ed1dae..6ddd2dc5 100644 --- a/src/pages/settings/panes/Appearance.tsx +++ b/src/pages/settings/panes/Appearance.tsx @@ -22,6 +22,7 @@ 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; @@ -171,11 +172,7 @@ export function Component(props: Props & WithDispatcher) {
-
- - -
-
+ }>

@@ -272,7 +269,7 @@ export function Component(props: Props & WithDispatcher) { code value={css} onChange={ev => setCSS(ev.currentTarget.value)} /> -
+
); } diff --git a/src/redux/index.ts b/src/redux/index.ts index dc90bec0..4bee0dcd 100644 --- a/src/redux/index.ts +++ b/src/redux/index.ts @@ -14,6 +14,7 @@ import { QueuedMessage } from "./reducers/queue"; import { ExperimentOptions } from "./reducers/experiments"; import { LastOpened } from "./reducers/last_opened"; import { Notifications } from "./reducers/notifications"; +import { SectionToggle } from "./reducers/section_toggle"; export type State = { config: Core.RevoltNodeConfiguration, @@ -28,6 +29,7 @@ export type State = { experiments: ExperimentOptions; lastOpened: LastOpened; notifications: Notifications; + sectionToggle: SectionToggle; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -56,7 +58,8 @@ store.subscribe(() => { sync, experiments, lastOpened, - notifications + notifications, + sectionToggle } = store.getState() as State; localForage.setItem("state", { @@ -70,6 +73,7 @@ store.subscribe(() => { sync, experiments, lastOpened, - notifications + notifications, + sectionToggle }); }); diff --git a/src/redux/reducers/index.ts b/src/redux/reducers/index.ts index fe47ccbd..baf217dc 100644 --- a/src/redux/reducers/index.ts +++ b/src/redux/reducers/index.ts @@ -13,6 +13,7 @@ import { sync, SyncAction } from "./sync"; import { experiments, ExperimentsAction } from "./experiments"; import { lastOpened, LastOpenedAction } from "./last_opened"; import { notifications, NotificationsAction } from "./notifications"; +import { sectionToggle, SectionToggleAction } from "./section_toggle"; export default combineReducers({ config, @@ -26,7 +27,8 @@ export default combineReducers({ sync, experiments, lastOpened, - notifications + notifications, + sectionToggle }); export type Action = @@ -42,6 +44,7 @@ export type Action = | ExperimentsAction | LastOpenedAction | NotificationsAction + | SectionToggleAction | { type: "__INIT"; state: State }; export type WithDispatcher = { dispatcher: (action: Action) => void }; diff --git a/src/redux/reducers/section_toggle.ts b/src/redux/reducers/section_toggle.ts new file mode 100644 index 00000000..26b23dca --- /dev/null +++ b/src/redux/reducers/section_toggle.ts @@ -0,0 +1,37 @@ +export interface SectionToggle { + [key: string]: boolean +} + +export type SectionToggleAction = + | { type: undefined } + | { + type: "SECTION_TOGGLE_SET"; + id: string; + state: boolean; + } + | { + type: "SECTION_TOGGLE_UNSET"; + id: string; + } + | { + type: "RESET"; + }; + +export function sectionToggle(state = {} as SectionToggle, action: SectionToggleAction): SectionToggle { + switch (action.type) { + case "SECTION_TOGGLE_SET": { + return { + ...state, + [action.id]: action.state + } + } + case "SECTION_TOGGLE_UNSET": { + const { [action.id]: _, ...newState } = state; + return newState; + } + case "RESET": + return {}; + default: + return state; + } +} From 652736c300b90138dd45c46a4d978a3a04e2cc04 Mon Sep 17 00:00:00 2001 From: nizune <9-nizune@users.noreply.gitlab.insrt.uk> Date: Sun, 4 Jul 2021 17:49:44 +0200 Subject: [PATCH 14/21] Fix: Fixed detail element in friends list --- src/components/common/CollapsibleSection.tsx | 10 +++--- src/components/ui/Details.tsx | 37 +++++++++++++++++--- src/pages/friends/Friends.tsx | 2 +- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/components/common/CollapsibleSection.tsx b/src/components/common/CollapsibleSection.tsx index 1f31e21b..3b6409fb 100644 --- a/src/components/common/CollapsibleSection.tsx +++ b/src/components/common/CollapsibleSection.tsx @@ -39,12 +39,10 @@ export default function CollapsibleSection({ id, defaultValue, summary, children onToggle={e => setState(e.currentTarget.open)} {...detailsProps}> - - { summary } - {/**/} - {/*
*/} - {/*
*/} - {/*
*/} +
+ + { summary } +
{ children } diff --git a/src/components/ui/Details.tsx b/src/components/ui/Details.tsx index 0a032022..f06a67f7 100644 --- a/src/components/ui/Details.tsx +++ b/src/components/ui/Details.tsx @@ -9,23 +9,50 @@ export default styled.details<{ sticky?: boolean, large?: boolean }>` ` } ${ props => props.large && css` - padding: 5px 0; + /*padding: 5px 0;*/ + background: var(--primary-background); + color: var(--secondary-foreground); + + .padding { /*TOFIX: make this applicable only for the friends list menu, DO NOT REMOVE.*/ + display: flex; + align-items: center; + padding: 5px 0; + margin: 0.8em 0px 0.4em; + cursor: pointer; + } ` } outline: none; - display: flex; cursor: pointer; list-style: none; align-items: center; transition: .2s opacity; + + font-size: 12px; + font-weight: 600; + text-transform: uppercase; &::marker, &::-webkit-details-marker { display: none; } - > svg { - flex-shrink: 0; - transition: .2s ease transform; + .title { + flex-grow: 1; + margin-top: 1px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + + .padding { + display: flex; + align-items: center; + + > svg { + flex-shrink: 0; + margin-inline-end: 4px; + transition: .2s ease transform; + } } } diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx index 01d36085..d90b5d58 100644 --- a/src/pages/friends/Friends.tsx +++ b/src/pages/friends/Friends.tsx @@ -118,7 +118,7 @@ export default function Friends() { id={`friends_${section_id}`} defaultValue={true} sticky large - summary={ — { list.length }}> + summary={
— { list.length }
}> { list.map(x => ) } ) From 1c80d5675f31a8da73f072ba5acf32d87fef35ec Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 4 Jul 2021 17:56:18 +0100 Subject: [PATCH 15/21] 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 && (