From 43cf33fc0a8cbe0c4ab38bf4800a3d9a1c65d58d Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 7 Jul 2024 21:06:04 -0400 Subject: [PATCH] fix: Light icons are not responsive to dark theme --- app/components/DocumentCard.tsx | 3 +- app/components/Icon.tsx | 80 +++++++++++-------- .../IconPicker/components/GridTemplate.tsx | 4 +- .../IconPicker/components/IconPanel.tsx | 4 +- app/components/IconPicker/index.tsx | 4 +- .../Sharing/Document/OtherAccess.tsx | 4 +- shared/types.ts | 2 +- shared/utils/icon.ts | 2 +- 8 files changed, 58 insertions(+), 45 deletions(-) diff --git a/app/components/DocumentCard.tsx b/app/components/DocumentCard.tsx index 894e160e4..3354dd2eb 100644 --- a/app/components/DocumentCard.tsx +++ b/app/components/DocumentCard.tsx @@ -178,8 +178,7 @@ const DocumentSquircle = ({ }) => { const theme = useTheme(); const iconType = determineIconType(icon)!; - const squircleColor = - iconType === IconType.Outline ? color : theme.slateLight; + const squircleColor = iconType === IconType.SVG ? color : theme.slateLight; return ( diff --git a/app/components/Icon.tsx b/app/components/Icon.tsx index 4e67bb8d7..ef47f0c38 100644 --- a/app/components/Icon.tsx +++ b/app/components/Icon.tsx @@ -1,3 +1,4 @@ +import { observer } from "mobx-react"; import { getLuminance } from "polished"; import * as React from "react"; import { randomElement } from "@shared/random"; @@ -9,12 +10,22 @@ import EmojiIcon from "~/components/Icons/EmojiIcon"; import useStores from "~/hooks/useStores"; import Logger from "~/utils/Logger"; -type IconProps = { +export type Props = { + /** The icon to render */ value: string; + /** The color of the icon */ color?: string; + /** The size of the icon */ size?: number; + /** The initial to display if the icon is a letter icon */ initial?: string; + /** Optional additional class name */ className?: string; + /** + * Ensure the color does not change in response to theme and contrast. Should only be + * used in color picker UI. + */ + forceColor?: boolean; }; const Icon = ({ @@ -22,8 +33,9 @@ const Icon = ({ color, size = 24, initial, + forceColor, className, -}: IconProps) => { +}: Props) => { const iconType = determineIconType(icon); if (!iconType) { @@ -34,14 +46,15 @@ const Icon = ({ } try { - if (iconType === IconType.Outline) { + if (iconType === IconType.SVG) { return ( - ); } @@ -56,38 +69,39 @@ const Icon = ({ return null; }; -type OutlineIconProps = { - value: string; - color?: string; - size?: number; - initial?: string; - className?: string; -}; +const SVGIcon = observer( + ({ + value: icon, + color: inputColor, + initial, + size, + className, + forceColor, + }: Props) => { + const { ui } = useStores(); -const OutlineIcon = ({ - value: icon, - color: inputColor, - initial, - size, - className, -}: OutlineIconProps) => { - const { ui } = useStores(); + let color = inputColor ?? randomElement(colorPalette); - let color = inputColor ?? randomElement(colorPalette); + // If the chosen icon color is very dark then we invert it in dark mode + if (!forceColor) { + if (ui.resolvedTheme === "dark" && color !== "currentColor") { + color = getLuminance(color) > 0.09 ? color : "currentColor"; + } - // If the chosen icon color is very dark then we invert it in dark mode - // otherwise it will be impossible to see against the dark background. - if (!inputColor && ui.resolvedTheme === "dark" && color !== "currentColor") { - color = getLuminance(color) > 0.09 ? color : "currentColor"; + // If the chosen icon color is very light then we invert it in light mode + if (ui.resolvedTheme === "light" && color !== "currentColor") { + color = getLuminance(color) < 0.9 ? color : "currentColor"; + } + } + + const Component = IconLibrary.getComponent(icon); + + return ( + + {initial} + + ); } - - const Component = IconLibrary.getComponent(icon); - - return ( - - {initial} - - ); -}; +); export default Icon; diff --git a/app/components/IconPicker/components/GridTemplate.tsx b/app/components/IconPicker/components/GridTemplate.tsx index 3ab7c12cc..d3b1d24e4 100644 --- a/app/components/IconPicker/components/GridTemplate.tsx +++ b/app/components/IconPicker/components/GridTemplate.tsx @@ -16,7 +16,7 @@ import { IconButton } from "./IconButton"; const BUTTON_SIZE = 32; type OutlineNode = { - type: IconType.Outline; + type: IconType.SVG; name: string; color: string; initial: string; @@ -66,7 +66,7 @@ const GridTemplate = ( ); const items = node.icons.map((item) => { - if (item.type === IconType.Outline) { + if (item.type === IconType.SVG) { return ( ({ - type: IconType.Outline, + type: IconType.SVG, name, color, initial, @@ -144,7 +144,7 @@ const IconPanel = ({ { category: DisplayCategory.Frequent, icons: freqIcons.map((name, index) => ({ - type: IconType.Outline, + type: IconType.SVG, name, color, initial, diff --git a/app/components/IconPicker/index.tsx b/app/components/IconPicker/index.tsx index da3cd85d1..7f4b7be32 100644 --- a/app/components/IconPicker/index.tsx +++ b/app/components/IconPicker/index.tsx @@ -98,7 +98,7 @@ const IconPicker = ({ (ic: string) => { popover.hide(); const icType = determineIconType(ic); - const finalColor = icType === IconType.Outline ? chosenColor : null; + const finalColor = icType === IconType.SVG ? chosenColor : null; onChange(ic, finalColor); }, [popover, onChange, chosenColor] @@ -110,7 +110,7 @@ const IconPicker = ({ const icType = determineIconType(icon); // Outline icon set; propagate color change - if (icType === IconType.Outline) { + if (icType === IconType.SVG) { onChange(icon, c); } }, diff --git a/app/components/Sharing/Document/OtherAccess.tsx b/app/components/Sharing/Document/OtherAccess.tsx index 62e299345..4170e9dce 100644 --- a/app/components/Sharing/Document/OtherAccess.tsx +++ b/app/components/Sharing/Document/OtherAccess.tsx @@ -133,8 +133,8 @@ const CollectionSquircle = ({ collection }: { collection: Collection }) => { const theme = useTheme(); const iconType = determineIconType(collection.icon)!; const squircleColor = - iconType === IconType.Outline ? collection.color! : theme.slateLight; - const iconSize = iconType === IconType.Outline ? 16 : 22; + iconType === IconType.SVG ? collection.color! : theme.slateLight; + const iconSize = iconType === IconType.SVG ? 16 : 22; return ( diff --git a/shared/types.ts b/shared/types.ts index 031bc79b9..919ebf083 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -414,7 +414,7 @@ export type ProsemirrorDoc = { }; export enum IconType { - Outline = "outline", + SVG = "svg", Emoji = "emoji", } diff --git a/shared/utils/icon.ts b/shared/utils/icon.ts index 7f0f0ea63..286cb28b3 100644 --- a/shared/utils/icon.ts +++ b/shared/utils/icon.ts @@ -9,5 +9,5 @@ export const determineIconType = ( if (!icon) { return; } - return outlineIconNames.has(icon) ? IconType.Outline : IconType.Emoji; + return outlineIconNames.has(icon) ? IconType.SVG : IconType.Emoji; };