From 98540493e01b47a751ffe9cbbc696e75fec3537b Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Mon, 27 Jan 2025 08:23:00 -0800 Subject: [PATCH] Desktop: Accessibility: Improve scrollbar contrast (#11708) --- .../app-desktop/gui/ConfigScreen/Sidebar.tsx | 2 +- .../gui/ConfigScreen/styles/index.scss | 1 - packages/app-desktop/gui/Sidebar/Sidebar.tsx | 4 +- packages/app-desktop/main.scss | 16 +++- .../app-mobile/components/global-style.ts | 3 +- packages/lib/theme.ts | 83 +++++++++++-------- packages/renderer/noteStyle.ts | 5 +- 7 files changed, 70 insertions(+), 44 deletions(-) diff --git a/packages/app-desktop/gui/ConfigScreen/Sidebar.tsx b/packages/app-desktop/gui/ConfigScreen/Sidebar.tsx index 13789a54c4..d465cd219e 100644 --- a/packages/app-desktop/gui/ConfigScreen/Sidebar.tsx +++ b/packages/app-desktop/gui/ConfigScreen/Sidebar.tsx @@ -164,7 +164,7 @@ export default function Sidebar(props: Props) { } return ( - + {buttons} ); diff --git a/packages/app-desktop/gui/ConfigScreen/styles/index.scss b/packages/app-desktop/gui/ConfigScreen/styles/index.scss index b202da6e95..f3ed9e4296 100644 --- a/packages/app-desktop/gui/ConfigScreen/styles/index.scss +++ b/packages/app-desktop/gui/ConfigScreen/styles/index.scss @@ -1,4 +1,3 @@ - @use "./setting-description.scss"; @use "./setting-label.scss"; @use "./setting-header.scss"; diff --git a/packages/app-desktop/gui/Sidebar/Sidebar.tsx b/packages/app-desktop/gui/Sidebar/Sidebar.tsx index f89fdbdbd0..41427814c5 100644 --- a/packages/app-desktop/gui/Sidebar/Sidebar.tsx +++ b/packages/app-desktop/gui/Sidebar/Sidebar.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { StyledRoot, StyledSyncReportText, StyledSyncReport, StyledSynchronizeButton } from './styles'; +import { StyledSyncReportText, StyledSyncReport, StyledSynchronizeButton, StyledRoot } from './styles'; import { ButtonLevel } from '../Button/Button'; import CommandService from '@joplin/lib/services/CommandService'; import Synchronizer from '@joplin/lib/Synchronizer'; @@ -74,7 +74,7 @@ const SidebarComponent = (props: Props) => { ); return ( - +
{syncReportComp} diff --git a/packages/app-desktop/main.scss b/packages/app-desktop/main.scss index cb04c8d960..73ec9ee737 100644 --- a/packages/app-desktop/main.scss +++ b/packages/app-desktop/main.scss @@ -44,7 +44,7 @@ a { } ::-webkit-scrollbar-thumb { - background: rgba(100, 100, 100, 0.3); + background: var(--scrollbar-thumb-color); border-radius: calc(var(--scrollbar-size, 7px) * 0.7); } @@ -53,7 +53,19 @@ a { } ::-webkit-scrollbar-thumb:hover { - background: rgba(100, 100, 100, 0.7); + background: var(--scrollbar-thumb-color-hover); +} + +:root { + --scrollbar-thumb-color: var(--joplin-scrollbar-thumb-color); + --scrollbar-thumb-color-hover: var(--joplin-scrollbar-thumb-color-hover); +} + +// Uses a scrollbar with secondary colors. Should be used for content with +// background matching joplin-background-color2. +._scrollbar2 { + --scrollbar-thumb-color: var(--joplin-scrollbar-thumb-color2); + --scrollbar-thumb-color-hover: var(--joplin-scrollbar-thumb-color-hover2); } .fade_out { diff --git a/packages/app-mobile/components/global-style.ts b/packages/app-mobile/components/global-style.ts index d9e52af692..b1e7d50f74 100644 --- a/packages/app-mobile/components/global-style.ts +++ b/packages/app-mobile/components/global-style.ts @@ -1,6 +1,6 @@ import Setting from '@joplin/lib/models/Setting'; import { Platform, TextStyle, ViewStyle } from 'react-native'; -import { themeById } from '@joplin/lib/theme'; +import { withDerivedColors, themeById } from '@joplin/lib/theme'; import { Theme as BaseTheme } from '@joplin/lib/themes/type'; const Color = require('color'); @@ -154,6 +154,7 @@ function themeStyle(theme: number) { const output: ThemeStyle = { ...baseStyle, ...baseTheme, + ...withDerivedColors(baseTheme), ...extraStyles(baseTheme), }; themeCache_[cacheKey] = output; diff --git a/packages/lib/theme.ts b/packages/lib/theme.ts index c34b29885d..925dfebda4 100644 --- a/packages/lib/theme.ts +++ b/packages/lib/theme.ts @@ -97,7 +97,49 @@ const globalStyle = (() => { }; })(); -export function extraStyles(theme: Theme) { +export const withDerivedColors = (theme: Theme) => { + const backgroundColor5 = theme.backgroundColor5 ?? theme.color4; + const backgroundColor4 = theme.backgroundColor4; + + // Colors need to be converted to string to work in some cases (in particular + // on mobile) + const rgbString = (color: typeof Color): string => color.rgb().string(); + const hexString = (color: typeof Color): string => color.hex(); + + return { + ...theme, + borderColor4: rgbString(Color(theme.color).alpha(0.3)), + iconColor: rgbString(Color(theme.color).alpha(0.8)), + focusOutlineColor: theme.colorWarn, + + backgroundColor5, + backgroundColorHover5: hexString(Color(backgroundColor5).darken(0.2)), + backgroundColorActive5: hexString(Color(backgroundColor5).darken(0.4)), + + colorFaded2: rgbString(Color(theme.color2).alpha(0.52)), + colorHover2: rgbString(Color(theme.color2).alpha(0.7)), + colorActive2: rgbString(Color(theme.color2).alpha(0.9)), + + backgroundColorHoverDim3: rgbString(Color(theme.backgroundColorHover3).alpha(0.3)), + backgroundColorActive3: rgbString(Color(theme.backgroundColorHover3).alpha(0.5)), + backgroundColorHover2: rgbString(Color(theme.selectedColor2).alpha(0.4)), + backgroundColorHover4: rgbString(Color(theme.backgroundColorHover3).alpha(0.3)), + backgroundColorActive4: rgbString(Color(theme.backgroundColorHover3).alpha(0.8)), + + scrollbarThumbColor: rgbString(Color(theme.color).alpha(0.54)), + scrollbarThumbColorHover: rgbString(Color(theme.color).alpha(0.63)), + scrollbarThumbColor2: rgbString(Color(theme.color2).alpha(0.46)), + scrollbarThumbColorHover2: rgbString(Color(theme.color2).alpha(0.63)), + + selectedDividerColor: hexString(Color(theme.dividerColor).darken(0.2)), + color5: theme.color5 ?? backgroundColor4, + colorHover3: theme.color3, + }; +}; + +type ThemeAndDerivedColors = ReturnType; + +export function extraStyles(theme: ThemeAndDerivedColors) { const zoomRatio = 1; const baseFontSize = Math.round(12 * zoomRatio); @@ -107,15 +149,6 @@ export function extraStyles(theme: Theme) { noteViewerFontSize: Math.round(baseFontSize * 1.25), }; - const bgColor4 = theme.backgroundColor4; - const borderColor4: string = Color(theme.color).alpha(0.3); - const iconColor = Color(theme.color).alpha(0.8); - const focusOutlineColor = theme.colorWarn; - - const backgroundColor5 = theme.backgroundColor5 ?? theme.color4; - const backgroundColorHover5 = Color(backgroundColor5).darken(0.2).hex(); - const backgroundColorActive5 = Color(backgroundColor5).darken(0.4).hex(); - const inputStyle = { ...globalStyle.inputStyle, color: theme.color, @@ -133,7 +166,7 @@ export function extraStyles(theme: Theme) { ...globalStyle.buttonStyle, color: theme.color4, backgroundColor: theme.backgroundColor4, - borderColor: borderColor4, + borderColor: theme.borderColor4, userSelect: literal('none'), // cursor: 'pointer', @@ -213,25 +246,6 @@ export function extraStyles(theme: Theme) { return { zoomRatio, ...fontSizes, - selectedDividerColor: Color(theme.dividerColor).darken(0.2).hex(), - iconColor, - colorFaded2: Color(theme.color2).alpha(0.52).rgb(), - colorHover2: Color(theme.color2).alpha(0.7).rgb(), - colorActive2: Color(theme.color2).alpha(0.9).rgb(), - - backgroundColorHoverDim3: Color(theme.backgroundColorHover3).alpha(0.3).rgb(), - backgroundColorActive3: Color(theme.backgroundColorHover3).alpha(0.5).rgb(), - backgroundColorHover2: Color(theme.selectedColor2).alpha(0.4).rgb(), - backgroundColorHover4: Color(theme.backgroundColorHover3).alpha(0.3).rgb(), - backgroundColorActive4: Color(theme.backgroundColorHover3).alpha(0.8).rgb(), - colorHover3: theme.color3, - borderColor4, - backgroundColor4: bgColor4, - color5: theme.color5 ?? bgColor4, - backgroundColor5, - backgroundColorHover5, - backgroundColorActive5, - focusOutlineColor, icon: { ...globalStyle.icon, @@ -306,7 +320,7 @@ export function extraStyles(theme: Theme) { flexDirection: literal('column'), }, buttonIconStyle: { - color: iconColor, + color: theme.iconColor, marginRight: 6, }, notificationBox: { @@ -329,7 +343,7 @@ export function extraStyles(theme: Theme) { type ExtraStyles = ReturnType; type GlobalStyle = typeof globalStyle; -export type ThemeStyle = Theme & ExtraStyles & GlobalStyle & { cacheKey: number }; +export type ThemeStyle = ThemeAndDerivedColors & ExtraStyles & GlobalStyle & { cacheKey: number }; const themeCache_: Record = {}; @@ -339,14 +353,15 @@ export function themeStyle(themeId: number): ThemeStyle { const cacheKey = themeId; if (themeCache_[cacheKey]) return themeCache_[cacheKey]; + const theme = withDerivedColors(themes[themeId]); const output: ThemeStyle = { cacheKey, ...globalStyle, - ...themes[themeId], + ...theme, // All theme are based on the light style, and just override the // relevant properties - ...extraStyles(themes[themeId]), + ...extraStyles(theme), }; themeCache_[cacheKey] = output; diff --git a/packages/renderer/noteStyle.ts b/packages/renderer/noteStyle.ts index b104c46d7d..37b8c4a593 100644 --- a/packages/renderer/noteStyle.ts +++ b/packages/renderer/noteStyle.ts @@ -137,14 +137,13 @@ export default function(theme: any, options: Options = null) { border: none; } ::-webkit-scrollbar-thumb { - background: rgba(100, 100, 100, 0.3); - border-radius: 5px; + background: ${theme.scrollbarThumbColor}; } ::-webkit-scrollbar-track:hover { background: rgba(0, 0, 0, 0.1); } ::-webkit-scrollbar-thumb:hover { - background: rgba(100, 100, 100, 0.7); + background: ${theme.scrollbarThumbColorHover}; } ${maxWidthCss}