diff --git a/.changeset/migrate-icons-to-phosphor.md b/.changeset/migrate-icons-to-phosphor.md
new file mode 100644
index 000000000..05881f3be
--- /dev/null
+++ b/.changeset/migrate-icons-to-phosphor.md
@@ -0,0 +1,5 @@
+---
+default: patch
+---
+
+Migrate the app icon API to Phosphor-backed icons.
diff --git a/src/app/components/icons/phosphor.tsx b/src/app/components/icons/phosphor.tsx
index 40d8ac196..bc13193ca 100644
--- a/src/app/components/icons/phosphor.tsx
+++ b/src/app/components/icons/phosphor.tsx
@@ -13,6 +13,7 @@ import {
BellIcon,
BellRingingIcon,
BellSlashIcon,
+ BookmarkIcon,
CaretDownIcon,
CaretLeftIcon,
CaretRightIcon,
@@ -243,6 +244,7 @@ export {
BellIcon as Bell,
BellRingingIcon as BellRinging,
BellSlashIcon as BellSlash,
+ BookmarkIcon as Bookmark,
CaretDownIcon as CaretDown,
CaretLeftIcon as CaretLeft,
CaretRightIcon as CaretRight,
diff --git a/src/app/features/message-search/MessageSearch.tsx b/src/app/features/message-search/MessageSearch.tsx
index fbb80bd7d..1b36209ca 100644
--- a/src/app/features/message-search/MessageSearch.tsx
+++ b/src/app/features/message-search/MessageSearch.tsx
@@ -1,6 +1,6 @@
import type { RefObject } from 'react';
import { useCallback, useEffect, useMemo, useRef } from 'react';
-import { Text, Box, config, Icon, Icons, Spinner, IconButton, Line, toRem } from 'folds';
+import { Text, Box, config, Spinner, IconButton, Line, toRem } from 'folds';
import { CaretUp, ChatCircle, dropzoneIcon, sizedIcon, Info } from '$components/icons/phosphor';
import { useAtomValue } from 'jotai';
import { useVirtualizer } from '@tanstack/react-virtual';
@@ -320,7 +320,7 @@ export function MessageSearch({
alignItems="Center"
gap="200"
>
-
+ {sizedIcon(Info, '200')}
{`${inMemoryRoomCount} ${inMemoryRoomCount === 1 ? 'room' : 'rooms'} searched from local cache only.`}
diff --git a/src/app/features/message-search/SearchFilters.tsx b/src/app/features/message-search/SearchFilters.tsx
index be53e25e1..0c29706ee 100644
--- a/src/app/features/message-search/SearchFilters.tsx
+++ b/src/app/features/message-search/SearchFilters.tsx
@@ -1,12 +1,10 @@
import type { ChangeEventHandler, MouseEventHandler } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import type { IconSrc, RectCords } from 'folds';
+import type { RectCords } from 'folds';
import {
Avatar,
Box,
Chip,
- Icon,
- Icons,
Text,
Line,
config,
@@ -23,7 +21,23 @@ import {
import type { RoomMember } from '$types/matrix-sdk';
import FocusTrap from 'focus-trap-react';
import { getRoomIconComponent } from '$components/icons/roomIcons';
-import { Check, Lock, sizedIcon, PlusCircle, SortAscending, X } from '$components/icons/phosphor';
+import type { PhosphorIcon } from '$components/icons/phosphor';
+import {
+ Check,
+ Clock,
+ File,
+ Hash,
+ Image,
+ Link,
+ Lock,
+ Play,
+ sizedIcon,
+ PlusCircle,
+ SortAscending,
+ SpeakerHigh,
+ User,
+ X,
+} from '$components/icons/phosphor';
import { SearchOrderBy } from '$types/matrix-sdk';
import { useVirtualizer } from '@tanstack/react-virtual';
import { useMatrixClient } from '$hooks/useMatrixClient';
@@ -103,7 +117,7 @@ function GroupButton({ grouped = true, onChange }: GroupButtonProps) {
onClick={handleOpenMenu}
variant="SurfaceVariant"
radii="Pill"
- before={}
+ before={sizedIcon(grouped ? Hash : Clock, '100')}
>
{grouped ? 'Grouped' : 'Timeline'}
@@ -404,12 +418,12 @@ function SelectRoomButton({ roomList, selectedRooms, onChange }: SelectRoomButto
);
}
-const HAS_FILTER_OPTIONS: { type: SearchHasType; label: string; icon: IconSrc }[] = [
- { type: 'image', label: 'Image', icon: Icons.Photo },
- { type: 'file', label: 'File', icon: Icons.File },
- { type: 'audio', label: 'Audio', icon: Icons.VolumeHigh },
- { type: 'video', label: 'Video', icon: Icons.Play },
- { type: 'link', label: 'Link', icon: Icons.Link },
+const HAS_FILTER_OPTIONS: { type: SearchHasType; label: string; icon: PhosphorIcon }[] = [
+ { type: 'image', label: 'Image', icon: Image },
+ { type: 'file', label: 'File', icon: File },
+ { type: 'audio', label: 'Audio', icon: SpeakerHigh },
+ { type: 'video', label: 'Video', icon: Play },
+ { type: 'link', label: 'Link', icon: Link },
];
type HasFilterChipsProps = {
@@ -435,7 +449,7 @@ function HasFilterChips({ hasTypes, onChange }: HasFilterChipsProps) {
key={type}
variant={active ? 'Success' : 'Surface'}
aria-pressed={active}
- before={active ? : }
+ before={active ? sizedIcon(Check, '100') : sizedIcon(icon, '100')}
outlined
onClick={() => toggle(type)}
>
@@ -609,7 +623,7 @@ function SelectSenderButton({ roomList, selectedSenders, onChange }: SelectSende
: undefined
}
alt={getMemberDisplayName(member)}
- renderFallback={() => }
+ renderFallback={() => sizedIcon(User, '50', { filled: true })}
/>
}
@@ -638,7 +652,7 @@ function SelectSenderButton({ roomList, selectedSenders, onChange }: SelectSende
onClick={handleOpenMenu}
variant="SurfaceVariant"
radii="Pill"
- before={}
+ before={sizedIcon(PlusCircle, '100')}
>
Add Sender
@@ -764,8 +778,8 @@ export function SearchFilters({
onSendersChange(next.length > 0 ? next : undefined);
}}
radii="Pill"
- before={}
- after={}
+ before={sizedIcon(User, '50')}
+ after={sizedIcon(X, '50')}
>
{mx.getUser(sender)?.displayName ?? sender}
diff --git a/src/app/features/message-search/SearchResultTimelineItem.tsx b/src/app/features/message-search/SearchResultTimelineItem.tsx
index f35564daf..bd06c5109 100644
--- a/src/app/features/message-search/SearchResultTimelineItem.tsx
+++ b/src/app/features/message-search/SearchResultTimelineItem.tsx
@@ -4,7 +4,7 @@ import type { IEventWithRoomId, Room } from '$types/matrix-sdk';
import { JoinRule, RelationType, EventType } from '$types/matrix-sdk';
import type { IImageContent } from '$types/matrix/common';
import type { HTMLReactParserOptions } from 'html-react-parser';
-import { Avatar, Box, Chip, Icon, Icons, Text, config } from 'folds';
+import { Avatar, Box, Chip, Text, config } from 'folds';
import type { Opts as LinkifyOpts } from 'linkifyjs';
import { useMatrixClient } from '$hooks/useMatrixClient';
import {
@@ -59,6 +59,7 @@ import { useSettingsLinkBaseUrl } from '$features/settings/useSettingsLinkBaseUr
import { useSetting } from '$state/hooks/settings';
import { settingsAtom } from '$state/settings';
import type { ResultItem } from './useMessageSearch';
+import { Icon, Icons } from '$app/icons';
type SearchResultTimelineItemProps = {
room: Room;
diff --git a/src/app/features/room/PollCreator.tsx b/src/app/features/room/PollCreator.tsx
index 348b647be..fab4b8942 100644
--- a/src/app/features/room/PollCreator.tsx
+++ b/src/app/features/room/PollCreator.tsx
@@ -5,9 +5,7 @@ import {
Button,
Dialog,
Header,
- Icon,
IconButton,
- Icons,
Input,
Overlay,
OverlayBackdrop,
@@ -25,6 +23,7 @@ import {
} from 'matrix-js-sdk/lib/@types/polls';
import type { Room } from '$types/matrix-sdk';
import { useMatrixClient } from '$hooks/useMatrixClient';
+import { Icon, Icons } from '$app/icons';
const MIN_ANSWERS = 2;
const MAX_ANSWERS = 20;
diff --git a/src/app/features/room/RoomInputTiptap.tsx b/src/app/features/room/RoomInputTiptap.tsx
index efe5c1beb..932c39433 100644
--- a/src/app/features/room/RoomInputTiptap.tsx
+++ b/src/app/features/room/RoomInputTiptap.tsx
@@ -29,7 +29,7 @@ import { useCallback, useRef, useState } from 'react';
import type { Editor as TiptapEditorInstance } from '@tiptap/core';
import type { Room } from '$types/matrix-sdk';
import { MsgType } from '$types/matrix-sdk';
-import { Box, Icon, IconButton, Icons, Text, config, color } from 'folds';
+import { Box, IconButton, Text, config, color } from 'folds';
import { useMatrixClient } from '$hooks/useMatrixClient';
import { useSetting } from '$state/hooks/settings';
@@ -51,6 +51,7 @@ import { TiptapMentionAutocomplete } from './tiptap-autocomplete/TiptapMentionAu
import { TiptapRoomMentionAutocomplete } from './tiptap-autocomplete/TiptapRoomMentionAutocomplete';
import { TiptapEmoticonAutocomplete } from './tiptap-autocomplete/TiptapEmoticonAutocomplete';
import { mobileOrTablet } from '$utils/user-agent';
+import { Icon, Icons } from '$app/icons';
// ─── Autocomplete detection ──────────────────────────────────────────────────
diff --git a/src/app/features/room/message/MobileMessageMenu.tsx b/src/app/features/room/message/MobileMessageMenu.tsx
index b06494051..ce0805a4d 100644
--- a/src/app/features/room/message/MobileMessageMenu.tsx
+++ b/src/app/features/room/message/MobileMessageMenu.tsx
@@ -1,5 +1,5 @@
import { createPortal } from 'react-dom';
-import { Icon, Icons, MenuItem, Text } from 'folds';
+import { MenuItem, Text } from 'folds';
import * as messageCss from './styles.css';
import type { MouseEventHandler, ReactNode, TouchEvent as ReactTouchEvent } from 'react';
import { useEffect, useCallback, useRef, useState } from 'react';
@@ -29,6 +29,7 @@ import { useIsBookmarked, useBookmarkActions } from '$features/bookmarks/useBook
import { useSetting } from '$state/hooks/settings';
import { settingsAtom } from '$state/settings';
import * as css from './MobileMessageMenu.css';
+import { Icon, Icons } from '$app/icons';
export type MobileMessageMenuProps = {
room: Room;
diff --git a/src/app/features/room/tiptap-autocomplete/TiptapMentionAutocomplete.tsx b/src/app/features/room/tiptap-autocomplete/TiptapMentionAutocomplete.tsx
index ae66d341f..31a9131e5 100644
--- a/src/app/features/room/tiptap-autocomplete/TiptapMentionAutocomplete.tsx
+++ b/src/app/features/room/tiptap-autocomplete/TiptapMentionAutocomplete.tsx
@@ -1,6 +1,6 @@
import type { KeyboardEvent as ReactKbEvent } from 'react';
import { useEffect } from 'react';
-import { Avatar, Icon, Icons, MenuItem, Text } from 'folds';
+import { Avatar, MenuItem, Text } from 'folds';
import type { Room, RoomMember } from '$types/matrix-sdk';
import { useRoomMembers } from '$hooks/useRoomMembers';
import { useMatrixClient } from '$hooks/useMatrixClient';
@@ -16,6 +16,7 @@ import { useAtomValue } from 'jotai';
import { nicknamesAtom } from '$state/nicknames';
import { KnownMembership } from '$types/matrix-sdk';
import { TiptapAutocompleteMenu } from './TiptapAutocompleteMenu';
+import { Icon, Icons } from '$app/icons';
const SEARCH_OPTIONS: UseAsyncSearchOptions = { limit: 1000, matchOptions: { contain: true } };
const mxIdToName = (id: string) => getMxIdLocalPart(id) ?? id;
diff --git a/src/app/features/settings/about/About.tsx b/src/app/features/settings/about/About.tsx
index f3123f80c..fd231e064 100644
--- a/src/app/features/settings/about/About.tsx
+++ b/src/app/features/settings/about/About.tsx
@@ -1,5 +1,5 @@
import { useState } from 'react';
-import { Box, Text, Scroll, Button, config, Icon, Icons, toRem, Spinner } from 'folds';
+import { Box, Text, Scroll, Button, config, toRem, Spinner } from 'folds';
import { Code, Heart, menuIcon } from '$components/icons/phosphor';
import { PageContent } from '$components/page';
import { SequenceCard } from '$components/sequence-card';
@@ -240,7 +240,7 @@ export function About({ requestBack, requestClose }: Readonly) {
fill="Soft"
size="300"
radii="300"
- before={}
+ before={menuIcon(Code, { weight: 'fill' })}
>
Upstream
diff --git a/src/app/features/settings/cosmetics/Themes.tsx b/src/app/features/settings/cosmetics/Themes.tsx
index ce3e0a258..0309c3139 100644
--- a/src/app/features/settings/cosmetics/Themes.tsx
+++ b/src/app/features/settings/cosmetics/Themes.tsx
@@ -5,8 +5,6 @@ import {
Button,
Chip,
config,
- Icon,
- Icons,
Input,
Menu,
MenuItem,
@@ -40,6 +38,7 @@ import { useShowRoomIcon } from '$hooks/useShowRoomIcon';
import type { PanelSizetItem } from '$hooks/usePanelSizes';
import { usePanelSizeItems } from '$hooks/usePanelSizes';
import { SelectShowPerRoomRoomIcon } from '$features/common-settings/appearance/Appearance';
+import { Icon, Icons } from '$app/icons';
const clampIncomingInlineImageHeight = (n: number) => Math.max(1, Math.min(4096, n));
diff --git a/src/app/features/settings/notifications/SystemNotification.tsx b/src/app/features/settings/notifications/SystemNotification.tsx
index 4e5c1a3d4..30df49011 100644
--- a/src/app/features/settings/notifications/SystemNotification.tsx
+++ b/src/app/features/settings/notifications/SystemNotification.tsx
@@ -7,9 +7,7 @@ import {
Button,
color,
config,
- Icon,
IconButton,
- Icons,
Input,
Menu,
MenuItem,
@@ -68,6 +66,7 @@ import {
setUnifiedPushDistributorSelection,
switchUnifiedPushDistributorSelection,
} from './UnifiedPushTransport';
+import { Icon, Icons } from '$app/icons';
type BackgroundPushKind = NotificationTransportProvider;
type BackgroundPushPlatform = NotificationTransportPlatform;
diff --git a/src/app/icons/index.tsx b/src/app/icons/index.tsx
new file mode 100644
index 000000000..7f0bb6421
--- /dev/null
+++ b/src/app/icons/index.tsx
@@ -0,0 +1,442 @@
+import { forwardRef } from 'react';
+import type { CSSProperties, SVGProps } from 'react';
+import classNames from 'classnames';
+import {
+ ArrowBendUpLeft,
+ ArrowBendUpRight,
+ ArrowClockwise,
+ ArrowDown,
+ ArrowLeft,
+ ArrowRight,
+ ArrowSquareOut,
+ ArrowUp,
+ At,
+ Bell,
+ BellRinging,
+ BellSimpleRinging,
+ BellSlash,
+ Bookmark,
+ Buildings,
+ CaretDown,
+ CaretLeft,
+ CaretRight,
+ CaretUp,
+ ChatCenteredText,
+ ChatCircle,
+ ChatCircleDots,
+ ChatCircleText,
+ Check,
+ Checks,
+ Clock,
+ ClockCounterClockwise,
+ Code,
+ CodeBlock,
+ Coffee,
+ Compass,
+ DotsThree,
+ DotsThreeVertical,
+ DownloadSimple,
+ Envelope,
+ EnvelopeSimple,
+ Eye,
+ EyeSlash,
+ File,
+ Flag,
+ Funnel,
+ Gear,
+ Globe,
+ HardDrives,
+ Hash,
+ Headphones,
+ Heart,
+ House,
+ Image,
+ Info,
+ Leaf,
+ Lightbulb,
+ Link,
+ ListBullets,
+ ListNumbers,
+ Lock,
+ MagnifyingGlass,
+ MarkdownLogo,
+ Microphone,
+ MicrophoneSlash,
+ Minus,
+ Monitor,
+ PaperPlaneRight,
+ Paperclip,
+ Pause,
+ Peace,
+ PencilSimple,
+ Phone,
+ PhoneDisconnect,
+ Planet,
+ Play,
+ Plus,
+ PlusCircle,
+ Power,
+ Prohibit,
+ ProhibitInset,
+ PushPin,
+ Quotes,
+ Screencast,
+ Shield,
+ ShieldCheck,
+ ShieldWarning,
+ SlidersHorizontal,
+ Smiley,
+ SmileySticker,
+ SoccerBall,
+ SortAscending,
+ SpeakerHigh,
+ SpeakerSlash,
+ SquaresFour,
+ Star,
+ Sticker,
+ Sun,
+ Terminal,
+ TextAa,
+ TextB,
+ TextHOne,
+ TextHThree,
+ TextHTwo,
+ TextItalic,
+ TextStrikethrough,
+ TextT,
+ TextUnderline,
+ Trash,
+ Tray,
+ User,
+ UserPlus,
+ Video,
+ VideoCamera,
+ VideoCameraSlash,
+ Warning,
+ X,
+ XCircle,
+} from '@phosphor-icons/react';
+import type { Icon as PhosphorIcon, IconWeight } from '@phosphor-icons/react';
+import { config } from 'folds';
+
+export type IconName =
+ | 'Home'
+ | 'User'
+ | 'UserPlus'
+ | 'Mail'
+ | 'MailPlus'
+ | 'Star'
+ | 'PlusCircle'
+ | 'Explore'
+ | 'Smile'
+ | 'SmilePlus'
+ | 'Leaf'
+ | 'Sticker'
+ | 'Delete'
+ | 'Phone'
+ | 'PhoneDown'
+ | 'Headphone'
+ | 'HeadphoneMute'
+ | 'Send'
+ | 'Bell'
+ | 'BellRing'
+ | 'BellPing'
+ | 'BellMute'
+ | 'Message'
+ | 'MessageUnread'
+ | 'Setting'
+ | 'Search'
+ | 'Heart'
+ | 'Play'
+ | 'Pause'
+ | 'Sun'
+ | 'Photo'
+ | 'Lock'
+ | 'Vlc'
+ | 'Flag'
+ | 'Ball'
+ | 'Bulb'
+ | 'Terminal'
+ | 'Pencil'
+ | 'Info'
+ | 'Shield'
+ | 'ShieldLock'
+ | 'ShieldUser'
+ | 'Cup'
+ | 'Pin'
+ | 'VolumeHigh'
+ | 'VolumeHighLock'
+ | 'VolumeHighGlobe'
+ | 'VolumeMute'
+ | 'File'
+ | 'Category'
+ | 'Peace'
+ | 'Eye'
+ | 'EyeBlind'
+ | 'Warning'
+ | 'Funnel'
+ | 'Bookmark'
+ | 'Inbox'
+ | 'Thread'
+ | 'ThreadPlus'
+ | 'ThreadUnread'
+ | 'ThreadReply'
+ | 'Monitor'
+ | 'ScreenShare'
+ | 'Server'
+ | 'Prohibited'
+ | 'NoEntry'
+ | 'Mic'
+ | 'MicMute'
+ | 'VideoCamera'
+ | 'VideoCameraMute'
+ | 'BlockQuote'
+ | 'Hash'
+ | 'HashLock'
+ | 'HashGlobe'
+ | 'HashSearch'
+ | 'HashPlus'
+ | 'Space'
+ | 'SpaceLock'
+ | 'SpaceGlobe'
+ | 'SpaceSearch'
+ | 'SpacePlus'
+ | 'ChevronRight'
+ | 'ChevronLeft'
+ | 'ChevronTop'
+ | 'ChevronBottom'
+ | 'Plus'
+ | 'Minus'
+ | 'Cross'
+ | 'VerticalDots'
+ | 'HorizontalDots'
+ | 'Check'
+ | 'CheckTwice'
+ | 'Download'
+ | 'External'
+ | 'Clock'
+ | 'RecentClock'
+ | 'Power'
+ | 'ReplyArrow'
+ | 'ArrowGoRight'
+ | 'ArrowGoRightPlus'
+ | 'ArrowGoRightCross'
+ | 'ArrowGoLeft'
+ | 'Markdown'
+ | 'Attachment'
+ | 'Alphabet'
+ | 'AlphabetUnderline'
+ | 'Text'
+ | 'Heading1'
+ | 'Heading2'
+ | 'Heading3'
+ | 'Bold'
+ | 'Italic'
+ | 'Underline'
+ | 'Strike'
+ | 'Link'
+ | 'Code'
+ | 'BlockCode'
+ | 'OrderList'
+ | 'UnorderList'
+ | 'Mention'
+ | 'Filter'
+ | 'Sort'
+ | 'ArrowUpDown'
+ | 'ArrowRight'
+ | 'ArrowLeft'
+ | 'ArrowTop'
+ | 'ArrowBottom'
+ | 'ArrowDropRight'
+ | 'ArrowDropLeft'
+ | 'ArrowDropTop'
+ | 'ArrowDropBottom'
+ | 'Reload'
+ | 'Globe';
+
+export type IconSrc = PhosphorIcon;
+
+export const Icons = {
+ Home: House,
+ User,
+ UserPlus,
+ Mail: Envelope,
+ MailPlus: EnvelopeSimple,
+ Star,
+ PlusCircle,
+ Explore: Compass,
+ Smile: Smiley,
+ SmilePlus: SmileySticker,
+ Leaf,
+ Sticker,
+ Delete: Trash,
+ Phone,
+ PhoneDown: PhoneDisconnect,
+ Headphone: Headphones,
+ HeadphoneMute: SpeakerSlash,
+ Send: PaperPlaneRight,
+ Bell,
+ BellRing: BellRinging,
+ BellPing: BellSimpleRinging,
+ BellMute: BellSlash,
+ Message: ChatCircle,
+ MessageUnread: ChatCircleDots,
+ Setting: Gear,
+ Search: MagnifyingGlass,
+ Heart,
+ Play,
+ Pause,
+ Sun,
+ Photo: Image,
+ Lock,
+ Vlc: Video,
+ Flag,
+ Ball: SoccerBall,
+ Bulb: Lightbulb,
+ Terminal,
+ Pencil: PencilSimple,
+ Info,
+ Shield,
+ ShieldLock: ShieldCheck,
+ ShieldUser: ShieldWarning,
+ Cup: Coffee,
+ Pin: PushPin,
+ VolumeHigh: SpeakerHigh,
+ VolumeHighLock: SpeakerHigh,
+ VolumeHighGlobe: SpeakerHigh,
+ VolumeMute: SpeakerSlash,
+ File,
+ Category: SquaresFour,
+ Peace,
+ Eye,
+ EyeBlind: EyeSlash,
+ Warning,
+ Funnel,
+ Bookmark,
+ Inbox: Tray,
+ Thread: ChatCenteredText,
+ ThreadPlus: ChatCircleText,
+ ThreadUnread: ChatCircleDots,
+ ThreadReply: ChatCenteredText,
+ Monitor,
+ ScreenShare: Screencast,
+ Server: HardDrives,
+ Prohibited: Prohibit,
+ NoEntry: ProhibitInset,
+ Mic: Microphone,
+ MicMute: MicrophoneSlash,
+ VideoCamera,
+ VideoCameraMute: VideoCameraSlash,
+ BlockQuote: Quotes,
+ Hash,
+ HashLock: Lock,
+ HashGlobe: Globe,
+ HashSearch: Hash,
+ HashPlus: Hash,
+ Space: Planet,
+ SpaceLock: Planet,
+ SpaceGlobe: Globe,
+ SpaceSearch: Planet,
+ SpacePlus: Buildings,
+ ChevronRight: CaretRight,
+ ChevronLeft: CaretLeft,
+ ChevronTop: CaretUp,
+ ChevronBottom: CaretDown,
+ Plus,
+ Minus,
+ Cross: X,
+ VerticalDots: DotsThreeVertical,
+ HorizontalDots: DotsThree,
+ Check,
+ CheckTwice: Checks,
+ Download: DownloadSimple,
+ External: ArrowSquareOut,
+ Clock,
+ RecentClock: ClockCounterClockwise,
+ Power,
+ ReplyArrow: ArrowBendUpLeft,
+ ArrowGoRight: ArrowBendUpRight,
+ ArrowGoRightPlus: PlusCircle,
+ ArrowGoRightCross: XCircle,
+ ArrowGoLeft: ArrowBendUpLeft,
+ Markdown: MarkdownLogo,
+ Attachment: Paperclip,
+ Alphabet: TextAa,
+ AlphabetUnderline: TextAa,
+ Text: TextT,
+ Heading1: TextHOne,
+ Heading2: TextHTwo,
+ Heading3: TextHThree,
+ Bold: TextB,
+ Italic: TextItalic,
+ Underline: TextUnderline,
+ Strike: TextStrikethrough,
+ Link,
+ Code,
+ BlockCode: CodeBlock,
+ OrderList: ListNumbers,
+ UnorderList: ListBullets,
+ Mention: At,
+ Filter: SlidersHorizontal,
+ Sort: SortAscending,
+ ArrowUpDown: SlidersHorizontal,
+ ArrowRight,
+ ArrowLeft,
+ ArrowTop: ArrowUp,
+ ArrowBottom: ArrowDown,
+ ArrowDropRight: CaretRight,
+ ArrowDropLeft: CaretLeft,
+ ArrowDropTop: CaretUp,
+ ArrowDropBottom: CaretDown,
+ Reload: ArrowClockwise,
+ Globe,
+} satisfies Record;
+
+type IconSize = '50' | '100' | '200' | '300' | '400' | '500' | '600' | 'Inherit';
+
+const iconSize: Record = {
+ '50': config.size.X50,
+ '100': config.size.X100,
+ '200': config.size.X200,
+ '300': config.size.X300,
+ '400': config.size.X400,
+ '500': config.size.X500,
+ '600': config.size.X600,
+ Inherit: config.size.XInherit,
+};
+
+export type IconProps = Omit, 'src'> & {
+ size?: IconSize;
+ filled?: boolean;
+ src: IconSrc;
+};
+
+export const Icon = forwardRef(
+ ({ className, size = '400', filled = false, src: IconComponent, style, ...props }, ref) => {
+ const phosphorSize = iconSize[size];
+ const iconStyle: CSSProperties = {
+ flexShrink: 0,
+ width: phosphorSize,
+ height: phosphorSize,
+ minWidth: phosphorSize,
+ fontSize: phosphorSize,
+ lineHeight: phosphorSize,
+ ...style,
+ };
+ const weight: IconWeight = filled ? 'fill' : 'regular';
+
+ return (
+
+ );
+ }
+);
+
+Icon.displayName = 'Icon';
diff --git a/src/app/pages/client/bookmarks/BookmarksList.tsx b/src/app/pages/client/bookmarks/BookmarksList.tsx
index d4293d5a6..37ca427ab 100644
--- a/src/app/pages/client/bookmarks/BookmarksList.tsx
+++ b/src/app/pages/client/bookmarks/BookmarksList.tsx
@@ -6,9 +6,7 @@ import {
Button,
Dialog,
Header,
- Icon,
IconButton,
- Icons,
Input,
Line,
Overlay,
@@ -55,6 +53,7 @@ import {
useBookmarkReminders,
useBookmarkReminderActions,
} from '$features/bookmarks/useBookmarks';
+import { Icon, Icons } from '$app/icons';
const REMINDER_PRESETS = [
{ label: '30 min', ms: 30 * 60 * 1000 },
diff --git a/src/app/pages/client/direct/Search.tsx b/src/app/pages/client/direct/Search.tsx
index bc6eb4620..2be02cc17 100644
--- a/src/app/pages/client/direct/Search.tsx
+++ b/src/app/pages/client/direct/Search.tsx
@@ -1,10 +1,11 @@
import { useRef } from 'react';
-import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds';
+import { Box, Text, Scroll, IconButton } from 'folds';
import { Page, PageContent, PageContentCenter, PageHeader } from '$components/page';
import { MessageSearch } from '$features/message-search';
import { ScreenSize, useScreenSizeContext } from '$hooks/useScreenSize';
import { BackRouteHandler } from '$components/BackRouteHandler';
import { useDirectRooms } from './useDirectRooms';
+import { Icon, Icons } from '$app/icons';
export function DirectSearch() {
const scrollRef = useRef(null);
diff --git a/src/app/pages/client/inbox/Inbox.tsx b/src/app/pages/client/inbox/Inbox.tsx
index 8433d3c7b..162159f67 100644
--- a/src/app/pages/client/inbox/Inbox.tsx
+++ b/src/app/pages/client/inbox/Inbox.tsx
@@ -1,5 +1,11 @@
-import { Avatar, Box, Icon, Icons, Text, toRem } from 'folds';
-import { ChatCircleDots, EnvelopeSimple, Tray, sizedIcon } from '$components/icons/phosphor';
+import { Avatar, Box, Text, toRem } from 'folds';
+import {
+ Bookmark,
+ ChatCircleDots,
+ EnvelopeSimple,
+ Tray,
+ sizedIcon,
+} from '$components/icons/phosphor';
import { NavCategory, NavItem, NavItemContent, NavLink } from '$components/nav';
import {
getInboxBookmarksPath,
@@ -71,7 +77,7 @@ function BookmarksNavItem({ hideText }: { hideText?: boolean }) {
radii="400"
style={hideText ? { width: '100%', padding: '0' } : { height: '100%' }}
>
-
+ {sizedIcon(Bookmark, '100', { filled: bookmarksSelected })}
{!hideText && (
diff --git a/src/app/pages/client/sidebar/BookmarksTab.tsx b/src/app/pages/client/sidebar/BookmarksTab.tsx
index 20124af49..dd29d3410 100644
--- a/src/app/pages/client/sidebar/BookmarksTab.tsx
+++ b/src/app/pages/client/sidebar/BookmarksTab.tsx
@@ -1,5 +1,5 @@
import { useNavigate } from 'react-router-dom';
-import { Icon, Icons } from 'folds';
+
import {
SidebarAvatar,
SidebarItem,
@@ -11,6 +11,7 @@ import { useInboxBookmarksSelected } from '$hooks/router/useInbox';
import { useSetting } from '$state/hooks/settings';
import { settingsAtom } from '$state/settings';
import { useFiredReminderCount } from '$features/bookmarks/useBookmarks';
+import { Icon, Icons } from '$app/icons';
export function BookmarksTab() {
const navigate = useNavigate();