diff --git a/shared/chat/conversation/input-area/normal2/platform-input.desktop.tsx b/shared/chat/conversation/input-area/normal2/platform-input.desktop.tsx index 03ff601a671b..88026a913e7e 100644 --- a/shared/chat/conversation/input-area/normal2/platform-input.desktop.tsx +++ b/shared/chat/conversation/input-area/normal2/platform-input.desktop.tsx @@ -515,7 +515,6 @@ const styles = Kb.Styles.styleSheetCreate( input: Kb.Styles.platformStyles({ isElectron: { backgroundColor: Kb.Styles.globalColors.transparent, - height: 22, // Line height change is so that emojis (unicode characters inside // textarea) are not clipped at the top. This change is accompanied by // a change in padding to offset the increased line height diff --git a/shared/chat/conversation/messages/wrapper/exploding-height-retainer/index.desktop.tsx b/shared/chat/conversation/messages/wrapper/exploding-height-retainer/index.desktop.tsx index 2c0931cb80f8..6cfcf84d3f74 100644 --- a/shared/chat/conversation/messages/wrapper/exploding-height-retainer/index.desktop.tsx +++ b/shared/chat/conversation/messages/wrapper/exploding-height-retainer/index.desktop.tsx @@ -1,8 +1,6 @@ import * as React from 'react' import * as Kb from '@/common-adapters' -import {urlsToImgSet} from '@/common-adapters/icon.desktop' import type {Props} from '.' -import {getAssetPath} from '@/constants/platform.desktop' import {useColorScheme} from 'react-native' export const animationDuration = 2000 @@ -59,7 +57,6 @@ const ExplodingHeightRetainer = (p: Props) => { const Ashes = (props: {doneExploding: boolean; exploded: boolean; explodedBy?: string; height: number}) => { const {doneExploding, explodedBy, exploded, height} = props - const isDarkMode = useColorScheme() === 'dark' let explodedTag: React.ReactNode = null if (doneExploding) { explodedTag = explodedBy ? ( @@ -87,26 +84,8 @@ const Ashes = (props: {doneExploding: boolean; exploded: boolean; explodedBy?: s return (
{exploded && explodedTag} diff --git a/shared/common-adapters/avatar/avatar.css b/shared/common-adapters/avatar/avatar.css index 1154f56411c5..4557afa2c9e3 100644 --- a/shared/common-adapters/avatar/avatar.css +++ b/shared/common-adapters/avatar/avatar.css @@ -127,29 +127,17 @@ /* Background layer - no border-radius needed, parent clips via overflow */ .avatar-background { - background-color: var(--color-greyLight); - bottom: 0; - left: 0; + background-color: light-dark(var(--color-greyLight), #0f0f0f); position: absolute; - right: 0; - top: 0; -} - -@media (prefers-color-scheme: dark) { - .avatar-background { - background-color: #0f0f0f; - } + inset: 0; } /* Image layer - no border-radius needed, parent clips via overflow */ .avatar-user-image { flex-shrink: 0; background-size: cover; - bottom: 0; - left: 0; position: absolute; - right: 0; - top: 0; + inset: 0; } /* For img tag avatars - better caching and performance */ @@ -172,12 +160,9 @@ img.avatar-user-image { .avatar-border-team { border-radius: 8px; background: rgba(0, 0, 0, 0); - bottom: 0; flex-shrink: 0; - left: 0; position: absolute; - right: 0; - top: 0; + inset: 0; } @media (prefers-color-scheme: dark) { diff --git a/shared/common-adapters/button.css b/shared/common-adapters/button.css index 2c628e4f7644..8c243da185fc 100644 --- a/shared/common-adapters/button.css +++ b/shared/common-adapters/button.css @@ -21,10 +21,7 @@ .button__underlay { position: absolute; - bottom: 0; - left: 0; - right: 0; - top: 0; + inset: 0; border-radius: 4px; transition: background-color 0.2s ease-out; } @@ -44,13 +41,7 @@ background-color: rgba(112, 78, 186, 0.05); } .button__underlay_black:hover { - background-color: rgba(0, 0, 0, 0.05); -} - -@media (prefers-color-scheme: dark) { - .button__underlay_black:hover { - background-color: rgba(255, 255, 255, 0.05); - } + background-color: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05)); } .button__underlay_yellow:hover { diff --git a/shared/common-adapters/choice-list.css b/shared/common-adapters/choice-list.css index f4caf09970b0..40aa8203137c 100644 --- a/shared/common-adapters/choice-list.css +++ b/shared/common-adapters/choice-list.css @@ -1,19 +1,13 @@ .cl-entry { background-color: transparent; &:hover { - background-color: var(--color-blueLighter2); + background-color: light-dark(var(--color-blueLighter2), #140d03); .cl-icon-container { background: transparent; } } } -@media (prefers-color-scheme: dark) { - .cl-entry:hover { - background-color: #140d03; - } -} - .cl-icon { transform-origin: center center; diff --git a/shared/common-adapters/icon.desktop.tsx b/shared/common-adapters/icon.desktop.tsx index efd796e624f7..fb644d2d4f54 100644 --- a/shared/common-adapters/icon.desktop.tsx +++ b/shared/common-adapters/icon.desktop.tsx @@ -1,17 +1,17 @@ import * as Shared from './icon.shared' import * as Styles from '@/styles' -import {colors, darkColors} from '@/styles/colors' import * as React from 'react' import logger from '@/logger' import {iconMeta} from './icon.constants-gen' -import invert from 'lodash/invert' import {getAssetPath} from '@/constants/platform.desktop' import type {Props, IconType} from './icon' import type {MeasureRef} from './measure-ref' -import {useColorScheme} from 'react-native' -const invertedLight = invert(colors) -const invertedDark = invert(darkColors) +// Extract color name from CSS variable string: "var(--color-black_50)" → "black_50" +const cssVarToColorName = (cssVar: string): string | undefined => { + const match = /^var\(--color-(.+)\)$/.exec(cssVar) + return match?.[1] +} const Icon = React.memo( React.forwardRef(function Icon(props, ref) { @@ -19,8 +19,6 @@ const Icon = React.memo( const {className, hint, colorOverride, padding, boxStyle, allowLazy = true} = props const iconType = type const hasDarkVariant = !!iconMeta[iconType].nameDark - const scheme = useColorScheme() - const isDarkMode = scheme === 'dark' && hasDarkVariant if (!Shared.isValidIconType(iconType)) { logger.warn('Unknown icontype passed', iconType) @@ -86,7 +84,7 @@ const Icon = React.memo( ...(props.color ? {color: color} : {}), } as React.CSSProperties - iconElement = ( + const img = ( ( title={hint} style={imgStyle} onClick={onClick || undefined} - srcSet={iconTypeToSrcSet(iconType, isDarkMode)} + srcSet={iconTypeToSrcSet(iconType, false)} /> ) + iconElement = hasDarkVariant ? ( + + + {img} + + ) : ( + img + ) } if (hasContainer) { @@ -112,10 +118,9 @@ const Icon = React.memo( hoverColor: 'inherit', } } else { - const invertedColors = isDarkMode ? invertedDark : invertedLight - const hoverColorName = onClick ? invertedColors[hoverColor] : null + const hoverColorName = onClick ? cssVarToColorName(hoverColor) : null hoverStyleName = hoverColorName ? `hover_color_${hoverColorName}` : '' - const colorName = invertedColors[color] + const colorName = cssVarToColorName(color) if (colorName) { colorStyleName = `color_${colorName}` } diff --git a/shared/common-adapters/input2.desktop.tsx b/shared/common-adapters/input2.desktop.tsx index 25a68504b9c4..97255ba9e5dd 100644 --- a/shared/common-adapters/input2.desktop.tsx +++ b/shared/common-adapters/input2.desktop.tsx @@ -21,41 +21,13 @@ export const Input2 = React.memo( const inputSingleRef = React.useRef(null) const inputMultiRef = React.useRef(null) - const autoResizeLastRef = React.useRef('') - const autoResize = React.useCallback(() => { - if (!multiline) { - // no resizing height on single-line inputs - return - } - - // Allow textarea to layout automatically - // if (this.props.growAndScroll) { - // return - // } - - const n = inputMultiRef.current - if (!n) { - return - } - - // ignore if value hasn't changed - if (n.value === autoResizeLastRef.current) { - return - } - autoResizeLastRef.current = n.value - - n.style.height = '1px' - n.style.height = `${n.scrollHeight}px` - }, [multiline]) - const onChange = React.useCallback( (e: {target: HTMLInputElement | HTMLTextAreaElement}) => { const s = e.target.value setValue(s) _onChangeText?.(s) - autoResize() }, - [_onChangeText, autoResize] + [_onChangeText] ) const onSelect = React.useCallback((e: {currentTarget: HTMLInputElement | HTMLTextAreaElement}) => { selectionRef.current = { @@ -103,7 +75,6 @@ export const Input2 = React.memo( } } }, 10) - autoResize() if (reflectChange) { setTimeout(() => { if (!i) return @@ -114,13 +85,13 @@ export const Input2 = React.memo( }, value, } - }, [value, multiline, autoResize, onChange]) + }, [value, multiline, onChange]) const rows = multiline ? rowsMin || Math.min(2, rowsMax || 2) : 0 const style = React.useMemo(() => { const textStyle = getTextStyle(textType, isDarkMode) if (multiline) { - const heightStyles: {minHeight: number; maxHeight?: number; overflowY?: 'hidden'} = { + const heightStyles: {minHeight: number; maxHeight?: number} = { minHeight: rows * (textStyle.lineHeight === undefined ? 20 : maybeParseInt(textStyle.lineHeight, 10) || 20) + (padding ? Styles.globalMargins[padding] * 2 : 0), @@ -130,8 +101,6 @@ export const Input2 = React.memo( heightStyles.maxHeight = rowsMax * (textStyle.lineHeight === undefined ? 20 : maybeParseInt(textStyle.lineHeight, 10) || 20) - } else { - heightStyles.overflowY = 'hidden' } const paddingStyles = padding ? Styles.padding(Styles.globalMargins[padding]) : {} @@ -219,13 +188,15 @@ const styles = Styles.styleSheetCreate(() => ({ }, growAndScroll: Styles.platformStyles({ isElectron: { + fieldSizing: 'fixed', maxHeight: '100%', - overflowY: 'scroll', + overflowY: 'auto', + scrollbarGutter: 'stable', }, }), multiline: Styles.platformStyles({ isElectron: { - height: 'initial', + fieldSizing: 'content', paddingBottom: 0, paddingTop: 0, resize: 'none', diff --git a/shared/common-adapters/list2.desktop.tsx b/shared/common-adapters/list2.desktop.tsx index adeb8003a470..385faf885abd 100644 --- a/shared/common-adapters/list2.desktop.tsx +++ b/shared/common-adapters/list2.desktop.tsx @@ -32,7 +32,8 @@ function List2(props: Props) { style={ { height: '100%', - overflowY: 'scroll', + overflowY: 'auto', + scrollbarGutter: 'stable', width: '100%', ...Styles.castStyleDesktop(style), } as const @@ -68,7 +69,8 @@ function List2(props: Props) { style={ { height: '100%', - overflowY: 'scroll', + overflowY: 'auto', + scrollbarGutter: 'stable', width: '100%', ...Styles.castStyleDesktop(style), } as const @@ -89,7 +91,8 @@ function List2(props: Props) { style={ { height: '100%', - overflowY: 'scroll', + overflowY: 'auto', + scrollbarGutter: 'stable', width: '100%', ...Styles.castStyleDesktop(style), } as const diff --git a/shared/common-adapters/plain-input.desktop.tsx b/shared/common-adapters/plain-input.desktop.tsx index acbffba61cbc..94ab9c6b66ae 100644 --- a/shared/common-adapters/plain-input.desktop.tsx +++ b/shared/common-adapters/plain-input.desktop.tsx @@ -28,8 +28,6 @@ type NativeTextRef = { focus: () => void blur: () => void value: string - style: {height: string} - scrollHeight: number selectionStart: number | null selectionEnd: number | null } @@ -44,7 +42,6 @@ const PlainInput = React.memo( const inputRef = React.useRef(null) const isComposingIMERef = React.useRef(false) const mountedRef = React.useRef(true) - const autoResizeLastRef = React.useRef('') const isDarkMode = useColorScheme() === 'dark' const focus = React.useCallback(() => { @@ -82,32 +79,6 @@ const PlainInput = React.memo( [_onKeyUp] ) - const autoResize = React.useCallback(() => { - if (!multiline) { - // no resizing height on single-line inputs - return - } - - // Allow textarea to layout automatically - if (growAndScroll) { - return - } - - const n = inputRef.current - if (!n) { - return - } - - // ignore if value hasn't changed - if (n.value === autoResizeLastRef.current) { - return - } - autoResizeLastRef.current = n.value - - n.style.height = '1px' - n.style.height = `${n.scrollHeight}px` - }, [multiline, growAndScroll]) - // This is controlled if a value prop is passed const isControlled = typeof p.value === 'string' @@ -151,9 +122,8 @@ const PlainInput = React.memo( } onChangeText?.(value) - autoResize() }, - [maxBytes, onChangeText, autoResize] + [maxBytes, onChangeText] ) const globalKeyDownHandler = React.useCallback( @@ -227,7 +197,7 @@ const PlainInput = React.memo( const getMultilineProps = () => { const rows = rowsMin || Math.min(2, rowsMax || 2) const textStyle = getTextStyle(textType ?? 'Body', isDarkMode) - const heightStyles: {minHeight: number; maxHeight?: number; overflowY?: 'hidden'} = { + const heightStyles: {minHeight: number; maxHeight?: number} = { minHeight: rows * (textStyle.lineHeight === undefined ? 20 : maybeParseInt(textStyle.lineHeight, 10) || 20) + (padding ? Styles.globalMargins[padding] * 2 : 0), @@ -235,8 +205,6 @@ const PlainInput = React.memo( if (rowsMax) { heightStyles.maxHeight = rowsMax * (textStyle.lineHeight === undefined ? 20 : maybeParseInt(textStyle.lineHeight, 10) || 20) - } else { - heightStyles.overflowY = 'hidden' } const paddingStyles = padding ? Styles.padding(Styles.globalMargins[padding]) : {} @@ -301,11 +269,9 @@ const PlainInput = React.memo( if (reflectChange) { onChange({target: inputRef.current ?? {value: ''}}) } - - autoResize() } }, - [autoResize, isControlled, onChange] + [isControlled, onChange] ) React.useImperativeHandle(ref, () => { @@ -363,13 +329,15 @@ const styles = Styles.styleSheetCreate(() => ({ }, growAndScroll: Styles.platformStyles({ isElectron: { + fieldSizing: 'fixed', maxHeight: '100%', - overflowY: 'scroll', + overflowY: 'auto', + scrollbarGutter: 'stable', }, }), multiline: Styles.platformStyles({ isElectron: { - height: 'initial', + fieldSizing: 'content', paddingBottom: 0, paddingTop: 0, resize: 'none', diff --git a/shared/common-adapters/text.css b/shared/common-adapters/text.css index 0cbbf81c10dd..be009814a316 100644 --- a/shared/common-adapters/text.css +++ b/shared/common-adapters/text.css @@ -248,13 +248,7 @@ } .text_Terminal { - color: #a8ccff; -} - -@media (prefers-color-scheme: dark) { - .text_Terminal { - color: #4c8eff; - } + color: light-dark(#a8ccff, #4c8eff); } .text_TerminalComment { @@ -268,7 +262,7 @@ .text_TerminalInline { line-height: 16px; - color: #2645a3; + color: light-dark(#2645a3, #f00); background-color: var(--color-blueLighter2); border-radius: 2px; height: 17px; @@ -276,12 +270,6 @@ word-wrap: break-word; } -@media (prefers-color-scheme: dark) { - .text_TerminalInline { - color: #f00; - } -} - .text_center { display: inline-block; text-align: center; diff --git a/shared/desktop/renderer/style.css b/shared/desktop/renderer/style.css index 52b806ac3357..94f8893d8760 100644 --- a/shared/desktop/renderer/style.css +++ b/shared/desktop/renderer/style.css @@ -211,6 +211,7 @@ table { /* End Keybase */ :root { + color-scheme: light dark; --size-xxtiny: 2px; --size-xtiny: 4px; --size-tiny: 8px; @@ -243,6 +244,7 @@ html { body { height: 100%; width: 100%; + scrollbar-gutter: stable; } :root { @@ -250,17 +252,9 @@ body { --scrollbar-minlength: 0.5rem; --scrollbar-ff-width: thin; --scrollbar-track-color: transparent; - --scrollbar-color: rgba(0, 0, 0, 0.2); - --scrollbar-color-hover: rgba(0, 0, 0, 0.3); - --scrollbar-color-active: rgb(0, 0, 0); -} - -@media (prefers-color-scheme: dark) { - :root { - --scrollbar-color: rgba(255, 255, 255, 0.2); - --scrollbar-color-hover: rgba(255, 255, 255, 0.3); - --scrollbar-color-active: rgb(255, 255, 255, 0.5); - } + --scrollbar-color: light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2)); + --scrollbar-color-hover: light-dark(rgba(0, 0, 0, 0.3), rgba(255, 255, 255, 0.3)); + --scrollbar-color-active: light-dark(rgb(0, 0, 0), rgb(255, 255, 255, 0.5)); } /* Used to customize scrollbars and enable testing the auto hide behavior on os x */ @@ -274,8 +268,6 @@ body { .scrollbar-test { overscroll-behavior: contain; overflow-y: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; scrollbar-width: var(--scrollbar-ff-width); } @@ -308,10 +300,7 @@ body { #root { position: absolute; display: flex; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; overflow: hidden; } @@ -329,13 +318,7 @@ body { .emoji-picker-emoji-box { border-radius: 2px; &:hover { - background-color: rgba(0, 0, 0, 0.05); - } -} - -@media (prefers-color-scheme: dark) { - .emoji-picker-emoji-box:hover { - background-color: rgba(255, 255, 255, 0.15); + background-color: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.15)); } } @@ -483,35 +466,18 @@ body { } body { - background-color: #ffffff; + background-color: light-dark(#ffffff, #191919); &.isWidget { background-color: transparent; } } -@media (prefers-color-scheme: dark) { - body { - background-color: #191919; - &.isWidget { - background-color: transparent; - } - } -} - .addInviteAndLinkBox { transition: box-shadow 0.35s; } .headerTitle:hover { .addInviteAndLinkBox { - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - } -} - -@media (prefers-color-scheme: dark) { - .headerTitle:hover { - .addInviteAndLinkBox { - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.8); - } + box-shadow: light-dark(0 2px 5px rgba(0, 0, 0, 0.2), 0 2px 5px rgba(0, 0, 0, 0.8)); } } diff --git a/shared/fs/filepreview/text-view.desktop.tsx b/shared/fs/filepreview/text-view.desktop.tsx index 63e4ec770d38..bb27fd5ca528 100644 --- a/shared/fs/filepreview/text-view.desktop.tsx +++ b/shared/fs/filepreview/text-view.desktop.tsx @@ -40,7 +40,7 @@ const styles = Kb.Styles.styleSheetCreate( backgroundColor: Kb.Styles.globalColors.blueLighter3, padding: Kb.Styles.globalMargins.small, }, - isElectron: {overflow: 'scroll'} as const, + isElectron: {overflow: 'auto', scrollbarGutter: 'stable'} as const, }), innerContainer: { ...Kb.Styles.globalStyles.flexGrow, @@ -56,7 +56,7 @@ const styles = Kb.Styles.styleSheetCreate( text: Kb.Styles.platformStyles({ isElectron: { color: Kb.Styles.globalColors.black_on_white, - overflow: 'scroll', + overflow: 'auto', whiteSpace: 'pre', }, }), diff --git a/shared/fs/footer/upload.desktop.tsx b/shared/fs/footer/upload.desktop.tsx index fa464af2c342..c6191ab41533 100644 --- a/shared/fs/footer/upload.desktop.tsx +++ b/shared/fs/footer/upload.desktop.tsx @@ -3,20 +3,7 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import type {UploadProps} from './upload' import capitalize from 'lodash/capitalize' -import {getAssetPath} from '@/constants/platform.desktop' -import * as Path from '@/util/path' import './upload.css' -import {useColorScheme} from 'react-native' - -const backgroundURL = (url: string, isDarkMode: boolean) => { - const ext = Path.extname(url) - const goodPath = Path.basename(url, ext) ?? '' - const guiModePath = `${isDarkMode ? 'dark-' : ''}${goodPath}` - const images = [1, 2, 3].map( - mult => `url('${getAssetPath('images', guiModePath)}${mult === 1 ? '' : `@${mult}x`}${ext}') ${mult}x` - ) - return `-webkit-image-set(${images.join(', ')})` -} type DrawState = 'showing' | 'hiding' | 'hidden' const Upload = React.memo(function Upload(props: UploadProps) { @@ -43,7 +30,6 @@ const Upload = React.memo(function Upload(props: UploadProps) { // this is due to the fact that the parent container has a marginTop of -13 on darwin const offset = smallMode && C.isDarwin ? 13 : 0 - const isDarkMode = useColorScheme() === 'dark' return ( <> {!!debugToggleShow && ( @@ -57,15 +43,10 @@ const Upload = React.memo(function Upload(props: UploadProps) { diff --git a/shared/router-v2/router.css b/shared/router-v2/router.css index f6c6a6b3f7b4..6664eddbd307 100644 --- a/shared/router-v2/router.css +++ b/shared/router-v2/router.css @@ -1,9 +1,6 @@ .modal-backdrop { position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; + inset: 0; pointer-events: none; transition: background-color 0.3s ease; } diff --git a/shared/styles/css.d.ts b/shared/styles/css.d.ts index 8bdfdf5cfe65..398830bd51c2 100644 --- a/shared/styles/css.d.ts +++ b/shared/styles/css.d.ts @@ -6,10 +6,12 @@ export type DimensionValue = number | 'auto' | `${number}%` export type Color = undefined | string type _StylesDesktopOverride = { backgroundImage?: string + fieldSizing?: 'content' | 'fixed' lineHeight?: `${number}px` | number | 'inherit' | 'unset' objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down' overflowX?: 'auto' | 'clip' | 'hidden' | 'scroll' | 'visible' overflowY?: 'auto' | 'clip' | 'hidden' | 'scroll' | 'visible' + scrollbarGutter?: 'auto' | 'stable' | 'stable both-edges' wordBreak?: 'normal' | 'break-all' | 'keep-all' | 'inherit' | 'initial' | 'unset' | 'break-word' WebkitAppRegion?: 'drag' | 'no-drag' WebkitBackgroundClip?: 'text' @@ -65,6 +67,7 @@ type StyleKeys = | 'fontVariant' | 'fontWeight' | 'height' + | 'inset' | 'justifyContent' | 'left' | 'letterSpacing' diff --git a/shared/styles/index.d.ts b/shared/styles/index.d.ts index 8449c0f166fe..14189938c2f6 100644 --- a/shared/styles/index.d.ts +++ b/shared/styles/index.d.ts @@ -14,11 +14,8 @@ type _fakeFontDefSeeCommentsOnThisStyle = { export declare const globalStyles: { fillAbsolute: { - bottom: 0 - left: 0 + inset: 0 position: 'absolute' - right: 0 - top: 0 } flexBoxCenter: { alignItems: 'center' diff --git a/shared/styles/index.desktop.tsx b/shared/styles/index.desktop.tsx index f0b35b8114cb..89ee60ff8823 100644 --- a/shared/styles/index.desktop.tsx +++ b/shared/styles/index.desktop.tsx @@ -2,6 +2,7 @@ import * as Shared from './shared' import styleSheetCreateProxy from './style-sheet-proxy' import type * as CSS from './css' import {themed, colors, darkColors} from './colors' +import {getAssetPath} from '@/constants/platform.desktop' const fontCommon = { WebkitFontSmoothing: 'antialiased', @@ -119,18 +120,12 @@ export const initDesktopStyles = () => { const colorVars = ` :root { ${colorNames .reduce((s, name) => { - s.push(`--color-${name}: ${colors[name]};`) + const light = colors[name] as string + const dark = darkColors[name] as string + s.push(`--color-${name}: ${light === dark ? light : `light-dark(${light}, ${dark})`};`) return s }, new Array()) .join(' ')} } - @media (prefers-color-scheme: dark) { - :root { ${colorNames - .reduce((s, name) => { - s.push(`--color-${name}: ${darkColors[name]};`) - return s - }, new Array()) - .join(' ')} } - } ` const helpers = colorNames.reduce((s, name) => { return ( @@ -150,6 +145,29 @@ export const initDesktopStyles = () => { const helperStyle = document.createElement('style') helperStyle.appendChild(document.createTextNode(helpers)) head.appendChild(helperStyle) + + // Generate background-image CSS classes with dark mode variants + const makeImgSet = (dir: string, name: string) => { + const url = getAssetPath('images', dir, name) + return `-webkit-image-set(url('${url}') 1x)` + } + const makeMultiResImgSet = (baseName: string) => { + const ext = baseName.slice(baseName.lastIndexOf('.')) + const base = baseName.slice(0, baseName.lastIndexOf('.')) + const images = [1, 2, 3].map( + mult => `url('${getAssetPath('images', base)}${mult === 1 ? '' : `@${mult}x`}${ext}') ${mult}x` + ) + return `-webkit-image-set(${images.join(', ')})` + } + const imageCss = + `.ashes-bg { background-image: ${makeImgSet('icons', 'pattern-ashes-desktop-400-68.png')}; }\n` + + `@media (prefers-color-scheme: dark) { .ashes-bg { background-image: ${makeImgSet('icons', 'dark-pattern-ashes-desktop-400-68.png')}; } }\n` + + `.upload-bg { background-image: ${makeMultiResImgSet('upload-pattern-80.png')}; }\n` + + `@media (prefers-color-scheme: dark) { .upload-bg { background-image: ${makeMultiResImgSet('dark-upload-pattern-80.png')}; } }\n` + const imageStyle = document.createElement('style') + imageStyle.appendChild(document.createTextNode(imageCss)) + head.appendChild(imageStyle) + fixScrollbars() } diff --git a/shared/styles/shared.tsx b/shared/styles/shared.tsx index 31258346654c..ac9239e32290 100644 --- a/shared/styles/shared.tsx +++ b/shared/styles/shared.tsx @@ -56,7 +56,7 @@ export const backgroundModeToTextColor = (backgroundMode: Background) => { const flexCommon = isMobile ? {} : ({display: 'flex'} as const) export const util = { - fillAbsolute: {bottom: 0, left: 0, position: 'absolute', right: 0, top: 0}, + fillAbsolute: {inset: 0, position: 'absolute'}, flexBoxCenter: {...flexCommon, alignItems: 'center', justifyContent: 'center'}, flexBoxColumn: {...flexCommon, flexDirection: 'column'}, flexBoxColumnReverse: {...flexCommon, flexDirection: 'column-reverse'}, diff --git a/shared/unlock-folders/device-list.desktop.tsx b/shared/unlock-folders/device-list.desktop.tsx index 5aec553bb53e..7388a3f10f38 100644 --- a/shared/unlock-folders/device-list.desktop.tsx +++ b/shared/unlock-folders/device-list.desktop.tsx @@ -64,9 +64,10 @@ const styles = Kb.Styles.styleSheetCreate( alignSelf: 'center', backgroundColor: Kb.Styles.globalColors.greyLight, height: 162, - overflowY: 'scroll', + overflowY: 'auto', paddingBottom: Kb.Styles.globalMargins.small, paddingTop: Kb.Styles.globalMargins.small, + scrollbarGutter: 'stable', width: 440, }, }),