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,
},
}),