Optimize icon picker for mobile with responsive sizing (#12275)

* Increase emoji picker cell size on mobile

Mobile uses a 40px button with a 32px emoji glyph (vs. 32px / 24px on
desktop), so roughly 8 emojis fit across a typical phone screen for
easier touch targeting.

https://claude.ai/code/session_017Rrv75Rc6eZ7eb2iNpZxpu

* tweaks

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Tom Moor
2026-05-05 23:37:15 -04:00
committed by GitHub
parent 913322c0d5
commit 41031aa7e6
4 changed files with 33 additions and 9 deletions
@@ -6,15 +6,21 @@ import { IconType } from "@shared/types";
import { IconLibrary } from "@shared/utils/IconLibrary";
import { Emoji } from "~/components/Emoji";
import Text from "~/components/Text";
import useMobile from "~/hooks/useMobile";
import { TRANSLATED_CATEGORIES } from "../utils";
import Grid from "./Grid";
import { IconButton } from "./IconButton";
import { CustomEmoji } from "@shared/components/CustomEmoji";
/**
* icon/emoji size is 24px; and we add 4px padding on all sides,
* Desktop: 24px icon/emoji + 4px padding on all sides = 32px button.
* Mobile: 32px icon/emoji + 4px padding on all sides = 40px button, so
* roughly 8 emojis fit across a typical phone screen.
*/
const BUTTON_SIZE = 32;
const BUTTON_SIZE_DESKTOP = 32;
const BUTTON_SIZE_MOBILE = 40;
const ICON_SIZE_DESKTOP = 24;
const ICON_SIZE_MOBILE = 32;
type OutlineNode = {
type: IconType.SVG;
@@ -53,8 +59,11 @@ const GridTemplate = (
{ width, height, data, empty, onIconSelect }: Props,
ref: React.Ref<HTMLDivElement>
) => {
const isMobile = useMobile();
const buttonSize = isMobile ? BUTTON_SIZE_MOBILE : BUTTON_SIZE_DESKTOP;
const iconSize = isMobile ? ICON_SIZE_MOBILE : ICON_SIZE_DESKTOP;
// 24px padding for the Grid Container
const itemsPerRow = Math.floor((width - 24) / BUTTON_SIZE);
const itemsPerRow = Math.max(1, Math.floor((width - 24) / buttonSize));
const gridItems = compact(
data.flatMap((node) => {
@@ -84,7 +93,11 @@ const GridTemplate = (
onClick={() => onIconSelect({ id: item.name, value: item.name })}
style={{ "--delay": `${item.delay}ms` } as React.CSSProperties}
>
<Icon as={IconLibrary.getComponent(item.name)} color={item.color}>
<Icon
as={IconLibrary.getComponent(item.name)}
color={item.color}
size={iconSize}
>
{item.initial}
</Icon>
</IconButton>
@@ -96,7 +109,11 @@ const GridTemplate = (
key={item.id}
onClick={() => onIconSelect({ id: item.id, value: item.value })}
>
<Emoji width={24} height={24}>
<Emoji
width={iconSize}
height={iconSize}
size={isMobile ? iconSize : undefined}
>
{item.type === IconType.Custom ? (
<CustomEmoji value={item.value} title={item.name} />
) : (
@@ -119,7 +136,7 @@ const GridTemplate = (
height={height}
data={gridItems}
columns={itemsPerRow}
itemWidth={BUTTON_SIZE}
itemWidth={buttonSize}
/>
);
};
@@ -1,5 +1,5 @@
import styled from "styled-components";
import { s, hover } from "@shared/styles";
import { breakpoints, s, hover } from "@shared/styles";
import NudeButton from "~/components/NudeButton";
export const IconButton = styled(NudeButton)<{ delay?: number }>`
@@ -10,4 +10,9 @@ export const IconButton = styled(NudeButton)<{ delay?: number }>`
&: ${hover} {
background: ${s("listItemHoverBackground")};
}
@media (max-width: ${breakpoints.tablet - 1}px) {
width: 40px;
height: 40px;
}
`;
+3 -1
View File
@@ -79,7 +79,9 @@ const IconPicker = ({
const [activeTab, setActiveTab] = React.useState<TabName>(defaultTab);
const popoverWidth = isMobile ? windowWidth : POPOVER_WIDTH;
// The Drawer's inner content has 6px padding on each side; subtract it
// so the panel doesn't overflow horizontally and itemsPerRow is correct.
const popoverWidth = isMobile ? windowWidth - 12 : POPOVER_WIDTH;
const handleTabChange = React.useCallback((value: string) => {
setActiveTab(value as TabName);
@@ -297,7 +297,7 @@ const StyledIconPicker = styled(IconPicker)`
const Title = styled(ContentEditable)<TitleProps>`
position: relative;
line-height: ${lineHeight};
margin-top: ${(props: TitleProps) => (props.$containsIcon ? "10vh" : "3vh")};
margin-top: 8vh;
margin-bottom: 0.5em;
font-size: ${fontSize};
font-weight: 600;