aural-ui 4.0.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1228
- package/dist/components/avatar/Avatar.stories.tsx +219 -235
- package/dist/components/badge/Badge.stories.tsx +379 -116
- package/dist/components/banner/Banner.stories.tsx +445 -391
- package/dist/components/breadcrumb/Breadcrumb.stories.tsx +453 -199
- package/dist/components/button/Button.stories.tsx +585 -230
- package/dist/components/card/Card.stories.tsx +619 -301
- package/dist/components/char-count/CharCount.stories.tsx +350 -248
- package/dist/components/checkbox/Checkbox.stories.tsx +309 -167
- package/dist/components/chip/Chip.stories.tsx +362 -168
- package/dist/components/circular-loader/CircularLoader.stories.tsx +221 -636
- package/dist/components/clamp-lines/ClampLines.stories.tsx +246 -117
- package/dist/components/collapsible/Collapsible.stories.tsx +391 -252
- package/dist/components/command/Command.stories.tsx +530 -867
- package/dist/components/dialog/Dialog.stories.tsx +501 -950
- package/dist/components/divider/Divider.stories.tsx +264 -527
- package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
- package/dist/components/drawer/Drawer.stories.tsx +659 -1023
- package/dist/components/dropdown/Dropdown.stories.tsx +643 -1028
- package/dist/components/form/Form.stories.tsx +560 -274
- package/dist/components/helper-text/HelperText.stories.tsx +199 -200
- package/dist/components/hover-card/HoverCard.stories.tsx +318 -1254
- package/dist/components/icon-button/IconButton.stories.tsx +837 -194
- package/dist/components/if-else/if-else.stories.tsx +370 -83
- package/dist/components/input/Input.stories.tsx +436 -368
- package/dist/components/label/Label.stories.tsx +156 -154
- package/dist/components/list/List.stories.tsx +484 -835
- package/dist/components/marquee/Marquee.stories.tsx +356 -712
- package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -422
- package/dist/components/overlay/Overlay.stories.tsx +452 -824
- package/dist/components/pagination/Pagination.stories.tsx +721 -210
- package/dist/components/popover/Popover.stories.tsx +481 -896
- package/dist/components/radio/Radio.stories.tsx +432 -124
- package/dist/components/resizable/Resizable.stories.tsx +495 -799
- package/dist/components/scroll-area/ScrollArea.stories.tsx +383 -1059
- package/dist/components/search/Search.stories.tsx +312 -595
- package/dist/components/select/Select.stories.tsx +684 -789
- package/dist/components/sheet/Sheet.stories.tsx +671 -950
- package/dist/components/skelton/Skelton.stories.tsx +230 -764
- package/dist/components/slider/Slider.stories.tsx +383 -760
- package/dist/components/stepper/Stepper.stories.tsx +371 -514
- package/dist/components/switch/Switch.stories.tsx +461 -208
- package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
- package/dist/components/table/Table.stories.tsx +770 -916
- package/dist/components/tabs/Tabs.stories.tsx +458 -1455
- package/dist/components/tag/Tag.stories.tsx +714 -542
- package/dist/components/textarea/TextArea.stories.tsx +621 -562
- package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -154
- package/dist/components/toast/Toast.stories.tsx +452 -1339
- package/dist/components/toggle/Toggle.stories.tsx +488 -931
- package/dist/components/tooltip/Tooltip.stories.tsx +344 -1388
- package/dist/components/typography/Typography.stories.tsx +406 -89
- package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
- package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
- package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
- package/dist/icons/Icons.stories.tsx +0 -12
- package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +223 -1060
- package/dist/icons/alert-icon/AlertIcon.stories.tsx +106 -968
- package/dist/icons/all-icons.tsx +37 -16
- package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +137 -1010
- package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +145 -935
- package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +132 -1046
- package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +134 -986
- package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +135 -1028
- package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +133 -971
- package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +145 -1123
- package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +143 -1252
- package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +123 -632
- package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +141 -1223
- package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +164 -1018
- package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +121 -1236
- package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +121 -1213
- package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +116 -893
- package/dist/icons/camera-icon/CameraIcon.stories.tsx +109 -1254
- package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +114 -975
- package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +157 -994
- package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +160 -992
- package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +140 -970
- package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +126 -993
- package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +144 -987
- package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +141 -1007
- package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +147 -1187
- package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +110 -476
- package/dist/icons/coin-icon/CoinIcon.stories.tsx +120 -1364
- package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +113 -1360
- package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +111 -942
- package/dist/icons/command-icon/CommandIcon.stories.tsx +124 -1087
- package/dist/icons/copy-icon/CopyIcon.stories.tsx +119 -996
- package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +144 -1046
- package/dist/icons/cross-icon/CrossIcon.stories.tsx +136 -999
- package/dist/icons/download-icon/DownloadIcon.stories.tsx +123 -857
- package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +121 -1080
- package/dist/icons/email-icon/EmailIcon.stories.tsx +112 -979
- package/dist/icons/expand-icon/ExpandIcon.stories.tsx +109 -1146
- package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +141 -1068
- package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +140 -1081
- package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +124 -1050
- package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +123 -1091
- package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +122 -633
- package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +116 -1087
- package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +166 -1020
- package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +112 -1182
- package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +112 -1155
- package/dist/icons/globe-icon/GlobeIcon.stories.tsx +127 -325
- package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +142 -985
- package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +116 -1217
- package/dist/icons/head-icon/HeadIcon.stories.tsx +108 -953
- package/dist/icons/heart-icon/HeartIcon.stories.tsx +117 -1060
- package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +116 -716
- package/dist/icons/image-icon/ImageIcon.stories.tsx +102 -1164
- package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +108 -1233
- package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +133 -1289
- package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +155 -1012
- package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +158 -1438
- package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +121 -1011
- package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +116 -981
- package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +116 -979
- package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +105 -1252
- package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +151 -1554
- package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +107 -1227
- package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +116 -707
- package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +119 -1226
- package/dist/icons/message-icon/MessageIcon.stories.tsx +111 -557
- package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +112 -1198
- package/dist/icons/moon-icon/MoonIcon.stories.tsx +117 -557
- package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +106 -1235
- package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +112 -1185
- package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +116 -1012
- package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +108 -1137
- package/dist/icons/notes-icon/NotesIcon.stories.tsx +116 -1138
- package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +106 -1146
- package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +119 -719
- package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +110 -999
- package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +109 -912
- package/dist/icons/pause-icon/PauseIcon.stories.tsx +110 -1041
- package/dist/icons/pencil-icon/PencilIcon.stories.tsx +112 -1109
- package/dist/icons/phone-icon/PhoneIcon.stories.tsx +112 -1023
- package/dist/icons/plus-icon/PlusIcon.stories.tsx +103 -1132
- package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +104 -870
- package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +99 -476
- package/dist/icons/search-icon/SearchIcon.stories.tsx +108 -1161
- package/dist/icons/setting-icon/SettingIcon.stories.tsx +104 -1009
- package/dist/icons/share-icon/ShareIcon.stories.tsx +117 -1064
- package/dist/icons/shield-icon/ShieldIcon.stories.tsx +114 -974
- package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +134 -1160
- package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +169 -1017
- package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +161 -1016
- package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +102 -1001
- package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +155 -593
- package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +155 -608
- package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +142 -712
- package/dist/icons/star-icon/StarIcon.stories.tsx +120 -946
- package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +109 -1013
- package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +113 -891
- package/dist/icons/sun-icon/SunIcon.stories.tsx +117 -864
- package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +113 -989
- package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +120 -1027
- package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +153 -1476
- package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +143 -1187
- package/dist/icons/tick-icon/TickIcon.stories.tsx +142 -1322
- package/dist/icons/trash-icon/TrashIcon.stories.tsx +105 -970
- package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +154 -1457
- package/dist/icons/upload-icon/UploadIcon.stories.tsx +112 -930
- package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +115 -1019
- package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +122 -1092
- package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +120 -1401
- package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +107 -1212
- package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +109 -1122
- package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +112 -1124
- package/dist/icons/warning-icon/WarningIcon.stories.tsx +119 -1083
- package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +158 -983
- package/dist/index.cjs +90 -90
- package/dist/index.js +90 -90
- package/package.json +8 -3
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import React from "react"
|
|
2
|
-
import { Badge } from "@components/badge"
|
|
3
2
|
import { Button } from "@components/button"
|
|
4
3
|
import {
|
|
5
|
-
|
|
6
|
-
BubbleCheckIcon,
|
|
7
|
-
BubbleSparkleIcon,
|
|
4
|
+
AudioBarIcon,
|
|
8
5
|
ChevronLeftIcon,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
ChevronRightIcon,
|
|
7
|
+
CircleTickIcon,
|
|
8
|
+
DownloadIcon,
|
|
12
9
|
EditBigIcon,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
FileChartIcon,
|
|
10
|
+
FileTextIcon,
|
|
11
|
+
HeartIcon,
|
|
16
12
|
ImageIcon,
|
|
17
|
-
ImportFolderIcon,
|
|
18
|
-
LightBulbSimpleIcon,
|
|
19
|
-
MagicBookIcon,
|
|
20
13
|
MaintenanceIcon,
|
|
14
|
+
MusicalNoteIcon,
|
|
21
15
|
SearchIcon,
|
|
22
|
-
|
|
16
|
+
ShareIcon,
|
|
17
|
+
SkipForwardIcon,
|
|
18
|
+
SparklesSoftIcon,
|
|
19
|
+
StarIcon,
|
|
23
20
|
TrashIcon,
|
|
24
21
|
UploadIcon,
|
|
22
|
+
VerticalMenuIcon,
|
|
25
23
|
} from "@icons/index"
|
|
26
24
|
import type { Meta, StoryObj } from "@storybook/react-vite"
|
|
27
25
|
|
|
26
|
+
import { AuralComponentDocsPage } from "src/ui/story-spec/components/component-story-docs-page"
|
|
27
|
+
|
|
28
28
|
import {
|
|
29
29
|
Command,
|
|
30
30
|
CommandDialog,
|
|
@@ -43,81 +43,29 @@ const meta: Meta<typeof Command> = {
|
|
|
43
43
|
component: Command,
|
|
44
44
|
parameters: {
|
|
45
45
|
layout: "fullscreen",
|
|
46
|
-
backgrounds: {
|
|
47
|
-
default: "dark",
|
|
48
|
-
values: [
|
|
49
|
-
{ name: "dark", value: "#0a0a0a" },
|
|
50
|
-
{ name: "light", value: "#ffffff" },
|
|
51
|
-
],
|
|
52
|
-
},
|
|
53
46
|
docs: {
|
|
54
47
|
description: {
|
|
55
|
-
component:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
A fast, unstyled command menu component built on top of CMDK with integration to our design system's List components. Perfect for creating command palettes, search interfaces, and quick action menus.
|
|
59
|
-
|
|
60
|
-
## Features
|
|
61
|
-
|
|
62
|
-
- **Fast Fuzzy Search**: Built-in fuzzy search with instant results
|
|
63
|
-
- **Keyboard Navigation**: Full keyboard support with arrow keys and Enter
|
|
64
|
-
- **Grouping**: Organize commands into logical groups with labels
|
|
65
|
-
- **Shortcuts**: Display keyboard shortcuts for commands
|
|
66
|
-
- **Icon Support**: Rich icon support for visual command identification
|
|
67
|
-
- **Customizable**: Extensive theming and styling options
|
|
68
|
-
- **Accessible**: ARIA compliant with screen reader support
|
|
69
|
-
- **Dialog Mode**: Can be used as a modal command palette
|
|
70
|
-
- **Empty States**: Customizable empty state when no results found
|
|
71
|
-
|
|
72
|
-
## Usage Examples
|
|
73
|
-
|
|
74
|
-
### Basic Command Menu
|
|
75
|
-
\`\`\`tsx
|
|
76
|
-
<Command>
|
|
77
|
-
<CommandInput placeholder="Type a command..." />
|
|
78
|
-
<CommandList>
|
|
79
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
80
|
-
<CommandGroup>
|
|
81
|
-
<CommandLabel>Suggestions</CommandLabel>
|
|
82
|
-
<CommandItem>
|
|
83
|
-
<FileChartIcon />
|
|
84
|
-
New File
|
|
85
|
-
<CommandShortcut>⌘N</CommandShortcut>
|
|
86
|
-
</CommandItem>
|
|
87
|
-
</CommandGroup>
|
|
88
|
-
</CommandList>
|
|
89
|
-
</Command>
|
|
90
|
-
\`\`\`
|
|
91
|
-
|
|
92
|
-
### Command Dialog
|
|
93
|
-
\`\`\`tsx
|
|
94
|
-
<CommandDialog open={open} onOpenChange={setOpen}>
|
|
95
|
-
<CommandInput placeholder="Search commands..." />
|
|
96
|
-
<CommandList>
|
|
97
|
-
<CommandEmpty>No commands found.</CommandEmpty>
|
|
98
|
-
<CommandGroup>
|
|
99
|
-
<CommandLabel>Actions</CommandLabel>
|
|
100
|
-
<CommandItem>Save File</CommandItem>
|
|
101
|
-
<CommandItem>Export</CommandItem>
|
|
102
|
-
</CommandGroup>
|
|
103
|
-
</CommandList>
|
|
104
|
-
</CommandDialog>
|
|
105
|
-
\`\`\`
|
|
106
|
-
|
|
107
|
-
### With Custom Styling
|
|
108
|
-
\`\`\`tsx
|
|
109
|
-
<Command
|
|
110
|
-
listProps={{ variant: "elevated", size: "lg" }}
|
|
111
|
-
classes={{ list: "custom-command-list" }}
|
|
112
|
-
>
|
|
113
|
-
<CommandInput />
|
|
114
|
-
<CommandList>
|
|
115
|
-
<CommandItem variant="destructive">Delete</CommandItem>
|
|
116
|
-
</CommandList>
|
|
117
|
-
</Command>
|
|
118
|
-
\`\`\`
|
|
119
|
-
`,
|
|
48
|
+
component:
|
|
49
|
+
"A fast command palette component built on CMDK, integrated with the design system's List components. Supports inline and modal (CommandDialog) modes, grouped items, live fuzzy search, keyboard navigation, icon support, keyboard shortcuts, and a destructive variant for dangerous actions. Use it for global search, quick actions, and context-sensitive command menus in any audio-focused or general-purpose application.",
|
|
120
50
|
},
|
|
51
|
+
page: () => (
|
|
52
|
+
<AuralComponentDocsPage
|
|
53
|
+
features={[
|
|
54
|
+
{
|
|
55
|
+
title: "Inline & Modal Modes",
|
|
56
|
+
description: "Palette or dialog overlay",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: "Fuzzy Search",
|
|
60
|
+
description: "Live filtering built in",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
title: "Keyboard Navigation",
|
|
64
|
+
description: "Arrow keys and shortcuts",
|
|
65
|
+
},
|
|
66
|
+
]}
|
|
67
|
+
/>
|
|
68
|
+
),
|
|
121
69
|
},
|
|
122
70
|
},
|
|
123
71
|
tags: ["autodocs"],
|
|
@@ -126,172 +74,145 @@ A fast, unstyled command menu component built on top of CMDK with integration to
|
|
|
126
74
|
export default meta
|
|
127
75
|
type Story = StoryObj<typeof Command>
|
|
128
76
|
|
|
129
|
-
//
|
|
130
|
-
export const BasicCommand: Story = {
|
|
131
|
-
render: () => (
|
|
132
|
-
<div className="mx-auto max-w-lg p-8">
|
|
133
|
-
<h3 className="text-fm-primary mb-4 text-lg font-medium">
|
|
134
|
-
Basic Command Menu
|
|
135
|
-
</h3>
|
|
136
|
-
<Command className="border-fm-divider-secondary rounded-lg border">
|
|
137
|
-
<CommandInput placeholder="Type a command or search..." />
|
|
138
|
-
<CommandList>
|
|
139
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
140
|
-
<CommandGroup>
|
|
141
|
-
<CommandLabel>Suggestions</CommandLabel>
|
|
142
|
-
<CommandItem>
|
|
143
|
-
<SearchIcon />
|
|
144
|
-
Search Files
|
|
145
|
-
</CommandItem>
|
|
146
|
-
<CommandItem>
|
|
147
|
-
<ImageIcon />
|
|
148
|
-
View Images
|
|
149
|
-
</CommandItem>
|
|
150
|
-
<CommandItem>
|
|
151
|
-
<FileChartIcon />
|
|
152
|
-
Open Reports
|
|
153
|
-
</CommandItem>
|
|
154
|
-
</CommandGroup>
|
|
155
|
-
<CommandSeparator />
|
|
156
|
-
<CommandGroup>
|
|
157
|
-
<CommandLabel>Settings</CommandLabel>
|
|
158
|
-
<CommandItem shortcut="⌘P">
|
|
159
|
-
<EyeOpenIcon />
|
|
160
|
-
View Profile
|
|
161
|
-
</CommandItem>
|
|
162
|
-
<CommandItem shortcut="⌘,">
|
|
163
|
-
<MaintenanceIcon />
|
|
164
|
-
Settings
|
|
165
|
-
</CommandItem>
|
|
166
|
-
</CommandGroup>
|
|
167
|
-
</CommandList>
|
|
168
|
-
</Command>
|
|
169
|
-
</div>
|
|
170
|
-
),
|
|
171
|
-
parameters: {
|
|
172
|
-
docs: {
|
|
173
|
-
description: {
|
|
174
|
-
story:
|
|
175
|
-
"A basic command menu with search input, grouped items, icons, and keyboard shortcuts.",
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
}
|
|
77
|
+
// ─── Configurations ──────────────────────────────────────────────────────────
|
|
180
78
|
|
|
181
|
-
|
|
182
|
-
export const CommandDialogExample: Story = {
|
|
79
|
+
export const Configurations: Story = {
|
|
183
80
|
render: () => {
|
|
184
|
-
const [
|
|
81
|
+
const [dialogOpen, setDialogOpen] = React.useState(false)
|
|
185
82
|
|
|
186
83
|
React.useEffect(() => {
|
|
187
84
|
const down = (e: KeyboardEvent) => {
|
|
188
85
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
189
86
|
e.preventDefault()
|
|
190
|
-
|
|
87
|
+
setDialogOpen((v) => !v)
|
|
191
88
|
}
|
|
192
89
|
}
|
|
193
|
-
|
|
194
90
|
document.addEventListener("keydown", down)
|
|
195
91
|
return () => document.removeEventListener("keydown", down)
|
|
196
92
|
}, [])
|
|
197
93
|
|
|
198
94
|
return (
|
|
199
95
|
<div className="space-y-8 p-8">
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
<
|
|
207
|
-
<
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
96
|
+
{/* Inline palette */}
|
|
97
|
+
<div className="space-y-3">
|
|
98
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
99
|
+
Inline Command Palette
|
|
100
|
+
</h4>
|
|
101
|
+
<div className="mx-auto max-w-md">
|
|
102
|
+
<Command className="border-fm-divider-secondary rounded-lg border">
|
|
103
|
+
<CommandInput placeholder="Search tracks, artists, playlists…" />
|
|
104
|
+
<CommandList>
|
|
105
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
106
|
+
<CommandGroup>
|
|
107
|
+
<CommandLabel>Library</CommandLabel>
|
|
108
|
+
<CommandItem>
|
|
109
|
+
<MusicalNoteIcon />
|
|
110
|
+
Browse Tracks
|
|
111
|
+
<CommandShortcut>⌘T</CommandShortcut>
|
|
112
|
+
</CommandItem>
|
|
113
|
+
<CommandItem>
|
|
114
|
+
<StarIcon />
|
|
115
|
+
Favourites
|
|
116
|
+
<CommandShortcut>⌘F</CommandShortcut>
|
|
117
|
+
</CommandItem>
|
|
118
|
+
<CommandItem>
|
|
119
|
+
<DownloadIcon />
|
|
120
|
+
Downloaded
|
|
121
|
+
<CommandShortcut>⌘D</CommandShortcut>
|
|
122
|
+
</CommandItem>
|
|
123
|
+
</CommandGroup>
|
|
124
|
+
<CommandSeparator />
|
|
125
|
+
<CommandGroup>
|
|
126
|
+
<CommandLabel>Actions</CommandLabel>
|
|
127
|
+
<CommandItem>
|
|
128
|
+
<UploadIcon />
|
|
129
|
+
Upload Track
|
|
130
|
+
<CommandShortcut>⌘U</CommandShortcut>
|
|
131
|
+
</CommandItem>
|
|
132
|
+
<CommandItem variant="destructive">
|
|
133
|
+
<TrashIcon />
|
|
134
|
+
Delete Selected
|
|
135
|
+
<CommandShortcut>⌘⌫</CommandShortcut>
|
|
136
|
+
</CommandItem>
|
|
137
|
+
</CommandGroup>
|
|
138
|
+
</CommandList>
|
|
139
|
+
</Command>
|
|
140
|
+
</div>
|
|
211
141
|
</div>
|
|
212
142
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
143
|
+
{/* Dialog / modal palette */}
|
|
144
|
+
<div className="space-y-3">
|
|
145
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
146
|
+
Modal Command Dialog (⌘K)
|
|
147
|
+
</h4>
|
|
148
|
+
<div className="flex justify-center">
|
|
149
|
+
<Button
|
|
150
|
+
variant="outline"
|
|
151
|
+
onClick={() => setDialogOpen(true)}
|
|
152
|
+
innerClassName="flex items-center gap-2"
|
|
153
|
+
>
|
|
154
|
+
<SearchIcon className="size-4" />
|
|
155
|
+
Search commands…
|
|
156
|
+
<span className="font-fm-brand text-fm-secondary ml-2 text-xs tracking-widest opacity-60">
|
|
157
|
+
⌘K
|
|
158
|
+
</span>
|
|
159
|
+
</Button>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<CommandDialog
|
|
163
|
+
open={dialogOpen}
|
|
164
|
+
onOpenChange={setDialogOpen}
|
|
165
|
+
title="Command Palette"
|
|
166
|
+
description="Search tracks, artists, and app actions"
|
|
219
167
|
>
|
|
220
|
-
<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
168
|
+
<CommandInput placeholder="Search tracks, artists, actions…" />
|
|
169
|
+
<CommandList>
|
|
170
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
171
|
+
<CommandGroup>
|
|
172
|
+
<CommandLabel>Quick Actions</CommandLabel>
|
|
173
|
+
<CommandItem onSelect={() => setDialogOpen(false)}>
|
|
174
|
+
<MusicalNoteIcon />
|
|
175
|
+
Play Next
|
|
176
|
+
<CommandShortcut>⌘→</CommandShortcut>
|
|
177
|
+
</CommandItem>
|
|
178
|
+
<CommandItem onSelect={() => setDialogOpen(false)}>
|
|
179
|
+
<HeartIcon />
|
|
180
|
+
Like Current Track
|
|
181
|
+
<CommandShortcut>⌘L</CommandShortcut>
|
|
182
|
+
</CommandItem>
|
|
183
|
+
<CommandItem onSelect={() => setDialogOpen(false)}>
|
|
184
|
+
<ShareIcon />
|
|
185
|
+
Share Track
|
|
186
|
+
<CommandShortcut>⌘⇧S</CommandShortcut>
|
|
187
|
+
</CommandItem>
|
|
188
|
+
</CommandGroup>
|
|
189
|
+
<CommandSeparator />
|
|
190
|
+
<CommandGroup>
|
|
191
|
+
<CommandLabel>Navigation</CommandLabel>
|
|
192
|
+
<CommandItem onSelect={() => setDialogOpen(false)}>
|
|
193
|
+
<ChevronRightIcon />
|
|
194
|
+
Library
|
|
195
|
+
</CommandItem>
|
|
196
|
+
<CommandItem onSelect={() => setDialogOpen(false)}>
|
|
197
|
+
<ChevronLeftIcon />
|
|
198
|
+
Go Back
|
|
199
|
+
</CommandItem>
|
|
200
|
+
</CommandGroup>
|
|
201
|
+
<CommandSeparator />
|
|
202
|
+
<CommandGroup>
|
|
203
|
+
<CommandLabel>Danger Zone</CommandLabel>
|
|
204
|
+
<CommandItem
|
|
205
|
+
variant="destructive"
|
|
206
|
+
onSelect={() => setDialogOpen(false)}
|
|
207
|
+
>
|
|
208
|
+
<TrashIcon />
|
|
209
|
+
Remove from Library
|
|
210
|
+
<CommandShortcut>⌘⌫</CommandShortcut>
|
|
211
|
+
</CommandItem>
|
|
212
|
+
</CommandGroup>
|
|
213
|
+
</CommandList>
|
|
214
|
+
</CommandDialog>
|
|
228
215
|
</div>
|
|
229
|
-
|
|
230
|
-
<CommandDialog
|
|
231
|
-
open={open}
|
|
232
|
-
onOpenChange={setOpen}
|
|
233
|
-
title="Command Palette"
|
|
234
|
-
description="Search for commands and actions"
|
|
235
|
-
>
|
|
236
|
-
<CommandInput placeholder="Type a command or search..." />
|
|
237
|
-
<CommandList>
|
|
238
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
239
|
-
<CommandGroup>
|
|
240
|
-
<CommandLabel>Quick Actions</CommandLabel>
|
|
241
|
-
<CommandItem onSelect={() => setOpen(false)}>
|
|
242
|
-
<FileChartIcon />
|
|
243
|
-
New File
|
|
244
|
-
<CommandShortcut>⌘N</CommandShortcut>
|
|
245
|
-
</CommandItem>
|
|
246
|
-
<CommandItem onSelect={() => setOpen(false)}>
|
|
247
|
-
<ImportFolderIcon />
|
|
248
|
-
Import Folder
|
|
249
|
-
<CommandShortcut>⌘⇧N</CommandShortcut>
|
|
250
|
-
</CommandItem>
|
|
251
|
-
<CommandItem onSelect={() => setOpen(false)}>
|
|
252
|
-
<UploadIcon />
|
|
253
|
-
Upload
|
|
254
|
-
<CommandShortcut>⌘U</CommandShortcut>
|
|
255
|
-
</CommandItem>
|
|
256
|
-
<CommandItem onSelect={() => setOpen(false)}>
|
|
257
|
-
<ImageIcon />
|
|
258
|
-
Add Image
|
|
259
|
-
<CommandShortcut>⌘I</CommandShortcut>
|
|
260
|
-
</CommandItem>
|
|
261
|
-
</CommandGroup>
|
|
262
|
-
<CommandSeparator />
|
|
263
|
-
<CommandGroup>
|
|
264
|
-
<CommandLabel>Navigation</CommandLabel>
|
|
265
|
-
<CommandItem onSelect={() => setOpen(false)}>
|
|
266
|
-
<ArrowRightIcon />
|
|
267
|
-
Go Forward
|
|
268
|
-
<CommandShortcut>⌘→</CommandShortcut>
|
|
269
|
-
</CommandItem>
|
|
270
|
-
<CommandItem onSelect={() => setOpen(false)}>
|
|
271
|
-
<ChevronLeftIcon />
|
|
272
|
-
Go Back
|
|
273
|
-
<CommandShortcut>⌘←</CommandShortcut>
|
|
274
|
-
</CommandItem>
|
|
275
|
-
<CommandItem onSelect={() => setOpen(false)}>
|
|
276
|
-
<ChevronUpIcon />
|
|
277
|
-
Go Up
|
|
278
|
-
<CommandShortcut>⌘↑</CommandShortcut>
|
|
279
|
-
</CommandItem>
|
|
280
|
-
</CommandGroup>
|
|
281
|
-
<CommandSeparator />
|
|
282
|
-
<CommandGroup>
|
|
283
|
-
<CommandLabel>Dangerous Actions</CommandLabel>
|
|
284
|
-
<CommandItem
|
|
285
|
-
variant="destructive"
|
|
286
|
-
onSelect={() => setOpen(false)}
|
|
287
|
-
>
|
|
288
|
-
<TrashIcon />
|
|
289
|
-
Delete
|
|
290
|
-
<CommandShortcut>⌘⌫</CommandShortcut>
|
|
291
|
-
</CommandItem>
|
|
292
|
-
</CommandGroup>
|
|
293
|
-
</CommandList>
|
|
294
|
-
</CommandDialog>
|
|
295
216
|
</div>
|
|
296
217
|
)
|
|
297
218
|
},
|
|
@@ -299,258 +220,239 @@ export const CommandDialogExample: Story = {
|
|
|
299
220
|
docs: {
|
|
300
221
|
description: {
|
|
301
222
|
story:
|
|
302
|
-
"
|
|
223
|
+
"Two configuration modes side by side: an inline Command palette always visible on the page, and a CommandDialog that opens as a modal overlay triggered by a button or ⌘K. Both share the same internal anatomy — input, list, groups, separator, shortcuts, and the destructive variant.",
|
|
303
224
|
},
|
|
304
225
|
},
|
|
305
226
|
},
|
|
306
227
|
}
|
|
307
228
|
|
|
308
|
-
//
|
|
309
|
-
export const FileManagementCommands: Story = {
|
|
310
|
-
render: () => (
|
|
311
|
-
<div className="mx-auto max-w-lg space-y-8 p-8">
|
|
312
|
-
<h3 className="text-fm-primary text-lg font-medium">File Management</h3>
|
|
313
|
-
<Command className="border-fm-divider-secondary rounded-lg border">
|
|
314
|
-
<CommandInput placeholder="Search files and actions..." />
|
|
315
|
-
<CommandList>
|
|
316
|
-
<CommandEmpty>
|
|
317
|
-
<div className="py-6 text-center">
|
|
318
|
-
<SearchIcon className="text-fm-tertiary mx-auto h-8 w-8" />
|
|
319
|
-
<p className="text-fm-secondary mt-2 text-sm">
|
|
320
|
-
No files or actions found.
|
|
321
|
-
</p>
|
|
322
|
-
</div>
|
|
323
|
-
</CommandEmpty>
|
|
324
|
-
|
|
325
|
-
<CommandGroup>
|
|
326
|
-
<CommandLabel>Create</CommandLabel>
|
|
327
|
-
<CommandItem>
|
|
328
|
-
<FileChartIcon />
|
|
329
|
-
New Document
|
|
330
|
-
<CommandShortcut>⌘N</CommandShortcut>
|
|
331
|
-
</CommandItem>
|
|
332
|
-
<CommandItem>
|
|
333
|
-
<ImportFolderIcon />
|
|
334
|
-
New Folder
|
|
335
|
-
<CommandShortcut>⌘⇧N</CommandShortcut>
|
|
336
|
-
</CommandItem>
|
|
337
|
-
<CommandItem>
|
|
338
|
-
<EditBigIcon />
|
|
339
|
-
New Template
|
|
340
|
-
<CommandShortcut>⌘T</CommandShortcut>
|
|
341
|
-
</CommandItem>
|
|
342
|
-
</CommandGroup>
|
|
343
|
-
|
|
344
|
-
<CommandSeparator />
|
|
345
|
-
|
|
346
|
-
<CommandGroup>
|
|
347
|
-
<CommandLabel>Actions</CommandLabel>
|
|
348
|
-
<CommandItem>
|
|
349
|
-
<BubbleCheckIcon />
|
|
350
|
-
Approve
|
|
351
|
-
<CommandShortcut>⌘A</CommandShortcut>
|
|
352
|
-
</CommandItem>
|
|
353
|
-
<CommandItem>
|
|
354
|
-
<EditBigIcon />
|
|
355
|
-
Edit
|
|
356
|
-
<CommandShortcut>⌘E</CommandShortcut>
|
|
357
|
-
</CommandItem>
|
|
358
|
-
<CommandItem>
|
|
359
|
-
<BubbleSparkleIcon />
|
|
360
|
-
Share
|
|
361
|
-
<CommandShortcut>⌘⇧S</CommandShortcut>
|
|
362
|
-
</CommandItem>
|
|
363
|
-
<CommandItem>
|
|
364
|
-
<TickIcon />
|
|
365
|
-
Mark Complete
|
|
366
|
-
<CommandShortcut>⌘⇧F</CommandShortcut>
|
|
367
|
-
</CommandItem>
|
|
368
|
-
</CommandGroup>
|
|
369
|
-
|
|
370
|
-
<CommandSeparator />
|
|
371
|
-
|
|
372
|
-
<CommandGroup>
|
|
373
|
-
<CommandLabel>Import/Export</CommandLabel>
|
|
374
|
-
<CommandItem>
|
|
375
|
-
<UploadIcon />
|
|
376
|
-
Import Files
|
|
377
|
-
<CommandShortcut>⌘I</CommandShortcut>
|
|
378
|
-
</CommandItem>
|
|
379
|
-
<CommandItem>
|
|
380
|
-
<ArrowRightIcon />
|
|
381
|
-
Export Selection
|
|
382
|
-
<CommandShortcut>⌘E</CommandShortcut>
|
|
383
|
-
</CommandItem>
|
|
384
|
-
<CommandItem>
|
|
385
|
-
<MaintenanceIcon />
|
|
386
|
-
Sync
|
|
387
|
-
<CommandShortcut>⌘R</CommandShortcut>
|
|
388
|
-
</CommandItem>
|
|
389
|
-
</CommandGroup>
|
|
390
|
-
|
|
391
|
-
<CommandSeparator />
|
|
392
|
-
|
|
393
|
-
<CommandGroup>
|
|
394
|
-
<CommandLabel>Danger Zone</CommandLabel>
|
|
395
|
-
<CommandItem variant="destructive">
|
|
396
|
-
<TrashIcon />
|
|
397
|
-
Move to Trash
|
|
398
|
-
<CommandShortcut>⌘⌫</CommandShortcut>
|
|
399
|
-
</CommandItem>
|
|
400
|
-
</CommandGroup>
|
|
401
|
-
</CommandList>
|
|
402
|
-
</Command>
|
|
403
|
-
</div>
|
|
404
|
-
),
|
|
405
|
-
parameters: {
|
|
406
|
-
docs: {
|
|
407
|
-
description: {
|
|
408
|
-
story:
|
|
409
|
-
"File management command palette with create, action, import/export, and destructive commands organized in groups.",
|
|
410
|
-
},
|
|
411
|
-
},
|
|
412
|
-
},
|
|
413
|
-
}
|
|
229
|
+
// ─── Interactive ──────────────────────────────────────────────────────────────
|
|
414
230
|
|
|
415
|
-
|
|
416
|
-
export const SearchAndFilterCommands: Story = {
|
|
231
|
+
export const Interactive: Story = {
|
|
417
232
|
render: () => {
|
|
418
|
-
const [
|
|
233
|
+
const [search, setSearch] = React.useState("")
|
|
234
|
+
const [lastSelected, setLastSelected] = React.useState<string | null>(null)
|
|
419
235
|
|
|
420
|
-
const
|
|
421
|
-
{
|
|
422
|
-
id: "recent",
|
|
423
|
-
label: "Recent Files",
|
|
424
|
-
icon: <FileChartIcon />,
|
|
425
|
-
group: "Quick Access",
|
|
426
|
-
},
|
|
427
|
-
{
|
|
428
|
-
id: "images",
|
|
429
|
-
label: "Images",
|
|
430
|
-
icon: <ImageIcon />,
|
|
431
|
-
group: "Quick Access",
|
|
432
|
-
},
|
|
433
|
-
{
|
|
434
|
-
id: "uploads",
|
|
435
|
-
label: "Uploads",
|
|
436
|
-
icon: <UploadIcon />,
|
|
437
|
-
group: "Quick Access",
|
|
438
|
-
},
|
|
439
|
-
{
|
|
440
|
-
id: "magic",
|
|
441
|
-
label: "Magic Book",
|
|
442
|
-
icon: <MagicBookIcon />,
|
|
443
|
-
group: "Quick Access",
|
|
444
|
-
},
|
|
445
|
-
{
|
|
446
|
-
id: "charts",
|
|
447
|
-
label: "Charts",
|
|
448
|
-
icon: <FileChartIcon />,
|
|
449
|
-
group: "Apps",
|
|
450
|
-
},
|
|
236
|
+
const tracks = [
|
|
451
237
|
{
|
|
452
|
-
id: "
|
|
453
|
-
label: "
|
|
454
|
-
|
|
455
|
-
group: "
|
|
238
|
+
id: "t1",
|
|
239
|
+
label: "Midnight Echoes",
|
|
240
|
+
artist: "Luna Vex",
|
|
241
|
+
group: "Tracks",
|
|
456
242
|
},
|
|
457
243
|
{
|
|
458
|
-
id: "
|
|
459
|
-
label: "
|
|
460
|
-
|
|
461
|
-
group: "
|
|
462
|
-
},
|
|
463
|
-
{
|
|
464
|
-
id: "profile",
|
|
465
|
-
label: "Profile",
|
|
466
|
-
icon: <EyeOpenIcon />,
|
|
467
|
-
group: "Account",
|
|
244
|
+
id: "t2",
|
|
245
|
+
label: "Solar Drift",
|
|
246
|
+
artist: "The Velvet Faders",
|
|
247
|
+
group: "Tracks",
|
|
468
248
|
},
|
|
249
|
+
{ id: "t3", label: "Neon Requiem", artist: "Axiom", group: "Tracks" },
|
|
250
|
+
]
|
|
251
|
+
const artists = [
|
|
252
|
+
{ id: "a1", label: "Luna Vex", genre: "Electronic", group: "Artists" },
|
|
469
253
|
{
|
|
470
|
-
id: "
|
|
471
|
-
label: "
|
|
472
|
-
|
|
473
|
-
group: "
|
|
254
|
+
id: "a2",
|
|
255
|
+
label: "The Velvet Faders",
|
|
256
|
+
genre: "Indie",
|
|
257
|
+
group: "Artists",
|
|
474
258
|
},
|
|
475
259
|
]
|
|
260
|
+
const playlists = [
|
|
261
|
+
{ id: "p1", label: "Late Night Drive", count: 18, group: "Playlists" },
|
|
262
|
+
{ id: "p2", label: "Focus Mode", count: 34, group: "Playlists" },
|
|
263
|
+
{ id: "p3", label: "Morning Energy", count: 22, group: "Playlists" },
|
|
264
|
+
]
|
|
476
265
|
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
266
|
+
const filterItems = <T extends { label: string }>(items: T[]) =>
|
|
267
|
+
search
|
|
268
|
+
? items.filter((i) =>
|
|
269
|
+
i.label.toLowerCase().includes(search.toLowerCase())
|
|
270
|
+
)
|
|
271
|
+
: items
|
|
482
272
|
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
return acc
|
|
490
|
-
},
|
|
491
|
-
{} as Record<string, typeof allItems>
|
|
492
|
-
)
|
|
273
|
+
const filteredTracks = filterItems(tracks)
|
|
274
|
+
const filteredArtists = filterItems(artists)
|
|
275
|
+
const filteredPlaylists = filterItems(playlists)
|
|
276
|
+
|
|
277
|
+
const totalResults =
|
|
278
|
+
filteredTracks.length + filteredArtists.length + filteredPlaylists.length
|
|
493
279
|
|
|
494
280
|
return (
|
|
495
|
-
<div className="
|
|
496
|
-
<div className="space-y-
|
|
497
|
-
<
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
</div>
|
|
281
|
+
<div className="w-full p-8">
|
|
282
|
+
<div className="mx-auto max-w-3xl space-y-6">
|
|
283
|
+
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
|
284
|
+
{/* Controls panel */}
|
|
285
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-5 rounded-xl border p-5">
|
|
286
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
287
|
+
Search State
|
|
288
|
+
</p>
|
|
504
289
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
value={searchTerm}
|
|
509
|
-
onValueChange={setSearchTerm}
|
|
510
|
-
/>
|
|
511
|
-
<CommandList>
|
|
512
|
-
<CommandEmpty>
|
|
513
|
-
<div className="py-6 text-center">
|
|
514
|
-
<SearchIcon className="text-fm-tertiary mx-auto h-8 w-8" />
|
|
515
|
-
<p className="text-fm-secondary mt-2 text-sm">
|
|
516
|
-
No results for "{searchTerm}"
|
|
290
|
+
<div className="space-y-2">
|
|
291
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
292
|
+
Query
|
|
517
293
|
</p>
|
|
518
|
-
<p className="text-fm-
|
|
519
|
-
|
|
294
|
+
<p className="text-fm-primary font-fm-text text-fm-md leading-fm-md truncate font-medium">
|
|
295
|
+
{search || "—"}
|
|
520
296
|
</p>
|
|
521
297
|
</div>
|
|
522
|
-
</CommandEmpty>
|
|
523
298
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
299
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
300
|
+
|
|
301
|
+
<div className="space-y-2">
|
|
302
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
303
|
+
Results
|
|
304
|
+
</p>
|
|
305
|
+
<div className="space-y-1">
|
|
306
|
+
<div className="flex justify-between">
|
|
307
|
+
<span className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
308
|
+
Tracks
|
|
309
|
+
</span>
|
|
310
|
+
<span className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm font-medium">
|
|
311
|
+
{filteredTracks.length}
|
|
312
|
+
</span>
|
|
313
|
+
</div>
|
|
314
|
+
<div className="flex justify-between">
|
|
315
|
+
<span className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
316
|
+
Artists
|
|
317
|
+
</span>
|
|
318
|
+
<span className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm font-medium">
|
|
319
|
+
{filteredArtists.length}
|
|
320
|
+
</span>
|
|
321
|
+
</div>
|
|
322
|
+
<div className="flex justify-between">
|
|
323
|
+
<span className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
324
|
+
Playlists
|
|
325
|
+
</span>
|
|
326
|
+
<span className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm font-medium">
|
|
327
|
+
{filteredPlaylists.length}
|
|
328
|
+
</span>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
</div>
|
|
332
|
+
|
|
333
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
334
|
+
|
|
335
|
+
<div className="space-y-2">
|
|
336
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
337
|
+
Last Selected
|
|
338
|
+
</p>
|
|
339
|
+
<p className="text-fm-primary font-fm-text text-fm-md leading-fm-md truncate font-medium">
|
|
340
|
+
{lastSelected ?? "—"}
|
|
341
|
+
</p>
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
{search && (
|
|
345
|
+
<>
|
|
346
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
347
|
+
<Button
|
|
348
|
+
variant="outline"
|
|
349
|
+
size="sm"
|
|
350
|
+
onClick={() => setSearch("")}
|
|
351
|
+
className="w-full"
|
|
352
|
+
>
|
|
353
|
+
Clear search
|
|
354
|
+
</Button>
|
|
355
|
+
</>
|
|
356
|
+
)}
|
|
357
|
+
</div>
|
|
358
|
+
|
|
359
|
+
{/* Preview stage */}
|
|
360
|
+
<div className="flex flex-col gap-3 lg:col-span-2">
|
|
361
|
+
<Command className="border-fm-divider-secondary rounded-lg border">
|
|
362
|
+
<CommandInput
|
|
363
|
+
placeholder="Search tracks, artists, playlists…"
|
|
364
|
+
value={search}
|
|
365
|
+
onValueChange={setSearch}
|
|
366
|
+
/>
|
|
367
|
+
<CommandList>
|
|
368
|
+
<CommandEmpty>
|
|
369
|
+
<div className="py-6 text-center">
|
|
370
|
+
<SearchIcon className="text-fm-tertiary mx-auto size-8" />
|
|
371
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm mt-2">
|
|
372
|
+
No results for "{search}"
|
|
373
|
+
</p>
|
|
374
|
+
</div>
|
|
375
|
+
</CommandEmpty>
|
|
376
|
+
|
|
377
|
+
{filteredTracks.length > 0 && (
|
|
378
|
+
<CommandGroup>
|
|
379
|
+
<CommandLabel>Tracks</CommandLabel>
|
|
380
|
+
{filteredTracks.map((t) => (
|
|
381
|
+
<CommandItem
|
|
382
|
+
key={t.id}
|
|
383
|
+
onSelect={() => setLastSelected(t.label)}
|
|
384
|
+
>
|
|
385
|
+
<MusicalNoteIcon />
|
|
386
|
+
<span className="flex flex-col">
|
|
387
|
+
<span>{t.label}</span>
|
|
388
|
+
<span className="text-fm-tertiary text-xs">
|
|
389
|
+
{t.artist}
|
|
390
|
+
</span>
|
|
391
|
+
</span>
|
|
392
|
+
<CommandShortcut>↵</CommandShortcut>
|
|
393
|
+
</CommandItem>
|
|
394
|
+
))}
|
|
395
|
+
</CommandGroup>
|
|
396
|
+
)}
|
|
397
|
+
|
|
398
|
+
{filteredTracks.length > 0 && filteredArtists.length > 0 && (
|
|
399
|
+
<CommandSeparator />
|
|
400
|
+
)}
|
|
401
|
+
|
|
402
|
+
{filteredArtists.length > 0 && (
|
|
403
|
+
<CommandGroup>
|
|
404
|
+
<CommandLabel>Artists</CommandLabel>
|
|
405
|
+
{filteredArtists.map((a) => (
|
|
406
|
+
<CommandItem
|
|
407
|
+
key={a.id}
|
|
408
|
+
onSelect={() => setLastSelected(a.label)}
|
|
409
|
+
>
|
|
410
|
+
<StarIcon />
|
|
411
|
+
<span className="flex flex-col">
|
|
412
|
+
<span>{a.label}</span>
|
|
413
|
+
<span className="text-fm-tertiary text-xs">
|
|
414
|
+
{a.genre}
|
|
415
|
+
</span>
|
|
416
|
+
</span>
|
|
417
|
+
</CommandItem>
|
|
418
|
+
))}
|
|
419
|
+
</CommandGroup>
|
|
420
|
+
)}
|
|
421
|
+
|
|
422
|
+
{filteredArtists.length > 0 &&
|
|
423
|
+
filteredPlaylists.length > 0 && <CommandSeparator />}
|
|
424
|
+
|
|
425
|
+
{filteredPlaylists.length > 0 && (
|
|
426
|
+
<CommandGroup>
|
|
427
|
+
<CommandLabel>Playlists</CommandLabel>
|
|
428
|
+
{filteredPlaylists.map((p) => (
|
|
429
|
+
<CommandItem
|
|
430
|
+
key={p.id}
|
|
431
|
+
onSelect={() => setLastSelected(p.label)}
|
|
432
|
+
>
|
|
433
|
+
<AudioBarIcon />
|
|
434
|
+
<span className="flex flex-col">
|
|
435
|
+
<span>{p.label}</span>
|
|
436
|
+
<span className="text-fm-tertiary text-xs">
|
|
437
|
+
{p.count} tracks
|
|
438
|
+
</span>
|
|
439
|
+
</span>
|
|
440
|
+
</CommandItem>
|
|
441
|
+
))}
|
|
442
|
+
</CommandGroup>
|
|
443
|
+
)}
|
|
444
|
+
</CommandList>
|
|
445
|
+
</Command>
|
|
446
|
+
|
|
447
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
448
|
+
<code className="text-fm-secondary text-fm-md leading-fm-md font-(--font-fm-mono)">
|
|
449
|
+
{totalResults} result{totalResults !== 1 ? "s" : ""} —
|
|
450
|
+
navigate with ↑↓ and confirm with ↵
|
|
451
|
+
</code>
|
|
452
|
+
</div>
|
|
551
453
|
</div>
|
|
552
454
|
</div>
|
|
553
|
-
|
|
455
|
+
</div>
|
|
554
456
|
</div>
|
|
555
457
|
)
|
|
556
458
|
},
|
|
@@ -558,442 +460,203 @@ export const SearchAndFilterCommands: Story = {
|
|
|
558
460
|
docs: {
|
|
559
461
|
description: {
|
|
560
462
|
story:
|
|
561
|
-
"
|
|
463
|
+
"Live search filtering across tracks, artists, and playlists in an audio app context. The left panel shows real-time result counts and the last selected item. Use the keyboard arrow keys to navigate and Enter to select — demonstrating CMDK's built-in keyboard navigation.",
|
|
562
464
|
},
|
|
563
465
|
},
|
|
564
466
|
},
|
|
565
467
|
}
|
|
566
468
|
|
|
567
|
-
//
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
469
|
+
// ─── UseCases ─────────────────────────────────────────────────────────────────
|
|
470
|
+
|
|
471
|
+
export const UseCases: Story = {
|
|
472
|
+
render: () => {
|
|
473
|
+
const [globalOpen, setGlobalOpen] = React.useState(false)
|
|
474
|
+
|
|
475
|
+
React.useEffect(() => {
|
|
476
|
+
const down = (e: KeyboardEvent) => {
|
|
477
|
+
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
478
|
+
e.preventDefault()
|
|
479
|
+
setGlobalOpen((v) => !v)
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
document.addEventListener("keydown", down)
|
|
483
|
+
return () => document.removeEventListener("keydown", down)
|
|
484
|
+
}, [])
|
|
485
|
+
|
|
486
|
+
return (
|
|
487
|
+
<div className="mx-auto max-w-3xl space-y-8 p-8">
|
|
488
|
+
{/* 1 — Global app search */}
|
|
489
|
+
<div className="space-y-3">
|
|
490
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
491
|
+
Global App Search (⌘K)
|
|
580
492
|
</h4>
|
|
581
|
-
<
|
|
582
|
-
|
|
583
|
-
|
|
493
|
+
<div className="flex justify-center">
|
|
494
|
+
<Button
|
|
495
|
+
variant="outline"
|
|
496
|
+
onClick={() => setGlobalOpen(true)}
|
|
497
|
+
innerClassName="flex items-center gap-2"
|
|
498
|
+
>
|
|
499
|
+
<SearchIcon className="size-4" />
|
|
500
|
+
Search everything…
|
|
501
|
+
<span className="font-fm-brand text-fm-secondary ml-2 text-xs tracking-widest opacity-60">
|
|
502
|
+
⌘K
|
|
503
|
+
</span>
|
|
504
|
+
</Button>
|
|
505
|
+
</div>
|
|
506
|
+
<CommandDialog
|
|
507
|
+
open={globalOpen}
|
|
508
|
+
onOpenChange={setGlobalOpen}
|
|
509
|
+
title="Global Search"
|
|
510
|
+
description="Search tracks, artists, playlists, and settings"
|
|
584
511
|
>
|
|
585
|
-
<CommandInput placeholder="
|
|
512
|
+
<CommandInput placeholder="Search everything…" />
|
|
586
513
|
<CommandList>
|
|
587
514
|
<CommandEmpty>No results found.</CommandEmpty>
|
|
588
515
|
<CommandGroup>
|
|
589
|
-
<CommandLabel>
|
|
590
|
-
<CommandItem>
|
|
591
|
-
<
|
|
592
|
-
|
|
593
|
-
<Badge color="positive" className="ml-auto">
|
|
594
|
-
Pro
|
|
595
|
-
</Badge>
|
|
516
|
+
<CommandLabel>Tracks</CommandLabel>
|
|
517
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
518
|
+
<MusicalNoteIcon />
|
|
519
|
+
Midnight Echoes — Luna Vex
|
|
596
520
|
</CommandItem>
|
|
597
|
-
<CommandItem>
|
|
598
|
-
<
|
|
599
|
-
|
|
521
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
522
|
+
<MusicalNoteIcon />
|
|
523
|
+
Solar Drift — The Velvet Faders
|
|
600
524
|
</CommandItem>
|
|
601
525
|
</CommandGroup>
|
|
602
|
-
|
|
603
|
-
</Command>
|
|
604
|
-
</div>
|
|
605
|
-
|
|
606
|
-
{/* Compact Command */}
|
|
607
|
-
<div className="space-y-4">
|
|
608
|
-
<h4 className="text-fm-secondary text-sm font-medium">
|
|
609
|
-
Compact Style
|
|
610
|
-
</h4>
|
|
611
|
-
<Command
|
|
612
|
-
className="border-fm-divider-secondary rounded-lg border"
|
|
613
|
-
listProps={{ size: "sm" }}
|
|
614
|
-
>
|
|
615
|
-
<CommandInput
|
|
616
|
-
placeholder="Compact menu..."
|
|
617
|
-
classes={{ input: "text-xs" }}
|
|
618
|
-
/>
|
|
619
|
-
<CommandList>
|
|
620
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
526
|
+
<CommandSeparator />
|
|
621
527
|
<CommandGroup>
|
|
622
|
-
<CommandLabel>
|
|
623
|
-
<CommandItem>
|
|
624
|
-
<
|
|
625
|
-
|
|
626
|
-
<CommandShortcut>⌘N</CommandShortcut>
|
|
627
|
-
</CommandItem>
|
|
628
|
-
<CommandItem>
|
|
629
|
-
<SearchIcon />
|
|
630
|
-
Find
|
|
631
|
-
<CommandShortcut>⌘F</CommandShortcut>
|
|
528
|
+
<CommandLabel>Playlists</CommandLabel>
|
|
529
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
530
|
+
<AudioBarIcon />
|
|
531
|
+
Late Night Drive
|
|
632
532
|
</CommandItem>
|
|
633
|
-
<CommandItem>
|
|
634
|
-
<
|
|
635
|
-
|
|
636
|
-
<CommandShortcut>⌘R</CommandShortcut>
|
|
533
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
534
|
+
<AudioBarIcon />
|
|
535
|
+
Focus Mode
|
|
637
536
|
</CommandItem>
|
|
638
537
|
</CommandGroup>
|
|
639
|
-
|
|
640
|
-
</Command>
|
|
641
|
-
</div>
|
|
642
|
-
|
|
643
|
-
{/* Flat Style */}
|
|
644
|
-
<div className="space-y-4">
|
|
645
|
-
<h4 className="text-fm-secondary text-sm font-medium">Flat Style</h4>
|
|
646
|
-
<Command
|
|
647
|
-
className="border-fm-divider-secondary rounded-lg border"
|
|
648
|
-
listProps={{ variant: "flat", rounded: "lg" }}
|
|
649
|
-
>
|
|
650
|
-
<CommandInput placeholder="Flat design menu..." />
|
|
651
|
-
<CommandList>
|
|
652
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
538
|
+
<CommandSeparator />
|
|
653
539
|
<CommandGroup>
|
|
654
|
-
<CommandLabel>
|
|
655
|
-
<CommandItem>
|
|
540
|
+
<CommandLabel>Settings</CommandLabel>
|
|
541
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
656
542
|
<MaintenanceIcon />
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
<CommandItem>
|
|
660
|
-
<EyeOpenIcon />
|
|
661
|
-
Account
|
|
543
|
+
Audio Quality
|
|
544
|
+
<CommandShortcut>⌘,</CommandShortcut>
|
|
662
545
|
</CommandItem>
|
|
663
546
|
</CommandGroup>
|
|
664
547
|
</CommandList>
|
|
665
|
-
</
|
|
548
|
+
</CommandDialog>
|
|
666
549
|
</div>
|
|
667
550
|
|
|
668
|
-
{/*
|
|
669
|
-
<div className="space-y-
|
|
670
|
-
<h4 className="text-fm-secondary text-
|
|
671
|
-
|
|
551
|
+
{/* 2 — File management commands */}
|
|
552
|
+
<div className="space-y-3">
|
|
553
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
554
|
+
File Management Commands
|
|
672
555
|
</h4>
|
|
673
|
-
<
|
|
674
|
-
className="rounded-lg border
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
</h3>
|
|
722
|
-
|
|
723
|
-
<Command className="border-fm-divider-secondary rounded-lg border">
|
|
724
|
-
<CommandInput placeholder="Search all commands..." />
|
|
725
|
-
<CommandList>
|
|
726
|
-
<CommandEmpty>
|
|
727
|
-
<div className="py-8 text-center">
|
|
728
|
-
<SearchIcon className="text-fm-tertiary mx-auto h-12 w-12" />
|
|
729
|
-
<h4 className="text-fm-primary mt-2 text-sm font-medium">
|
|
730
|
-
No commands found
|
|
731
|
-
</h4>
|
|
732
|
-
<p className="text-fm-secondary mt-1 text-xs">
|
|
733
|
-
Try adjusting your search to find what you're looking for.
|
|
734
|
-
</p>
|
|
735
|
-
</div>
|
|
736
|
-
</CommandEmpty>
|
|
737
|
-
|
|
738
|
-
<CommandGroup>
|
|
739
|
-
<CommandLabel>
|
|
740
|
-
<FileChartIcon className="mr-2" />
|
|
741
|
-
File Operations
|
|
742
|
-
</CommandLabel>
|
|
743
|
-
<CommandItem>
|
|
744
|
-
<FileChartIcon />
|
|
745
|
-
New Document
|
|
746
|
-
<Badge color="info" className="ml-auto">
|
|
747
|
-
Ctrl+N
|
|
748
|
-
</Badge>
|
|
749
|
-
</CommandItem>
|
|
750
|
-
<CommandItem>
|
|
751
|
-
<ImportFolderIcon />
|
|
752
|
-
Open Folder
|
|
753
|
-
<CommandShortcut>⌘O</CommandShortcut>
|
|
754
|
-
</CommandItem>
|
|
755
|
-
<CommandItem>
|
|
756
|
-
<EditBigIcon />
|
|
757
|
-
Recent Files
|
|
758
|
-
<Badge color="neutral" className="ml-auto">
|
|
759
|
-
5
|
|
760
|
-
</Badge>
|
|
761
|
-
</CommandItem>
|
|
762
|
-
</CommandGroup>
|
|
763
|
-
|
|
764
|
-
<CommandSeparator />
|
|
765
|
-
|
|
766
|
-
<CommandGroup>
|
|
767
|
-
<CommandLabel>
|
|
768
|
-
<EyeOpenIcon className="mr-2" />
|
|
769
|
-
User Management
|
|
770
|
-
</CommandLabel>
|
|
771
|
-
<CommandItem>
|
|
772
|
-
<EyeOpenIcon />
|
|
773
|
-
View Profile
|
|
774
|
-
<CommandShortcut>⌘P</CommandShortcut>
|
|
775
|
-
</CommandItem>
|
|
776
|
-
<CommandItem>
|
|
777
|
-
<MaintenanceIcon />
|
|
778
|
-
User Settings
|
|
779
|
-
<CommandShortcut>⌘,</CommandShortcut>
|
|
780
|
-
</CommandItem>
|
|
781
|
-
<CommandItem>
|
|
782
|
-
<BubbleSparkleIcon />
|
|
783
|
-
Share Profile
|
|
784
|
-
<Badge color="warning" className="ml-auto">
|
|
785
|
-
Beta
|
|
786
|
-
</Badge>
|
|
787
|
-
</CommandItem>
|
|
788
|
-
</CommandGroup>
|
|
789
|
-
|
|
790
|
-
<CommandSeparator />
|
|
791
|
-
|
|
792
|
-
<CommandGroup>
|
|
793
|
-
<CommandLabel>
|
|
794
|
-
<UploadIcon className="mr-2" />
|
|
795
|
-
Data Management
|
|
796
|
-
</CommandLabel>
|
|
797
|
-
<CommandItem>
|
|
798
|
-
<ArrowRightIcon />
|
|
799
|
-
Export Data
|
|
800
|
-
<CommandShortcut>⌘E</CommandShortcut>
|
|
801
|
-
</CommandItem>
|
|
802
|
-
<CommandItem>
|
|
803
|
-
<UploadIcon />
|
|
804
|
-
Import Data
|
|
805
|
-
<CommandShortcut>⌘I</CommandShortcut>
|
|
806
|
-
</CommandItem>
|
|
807
|
-
<CommandItem>
|
|
808
|
-
<MaintenanceIcon />
|
|
809
|
-
Sync Data
|
|
810
|
-
<Badge color="positive" className="ml-auto">
|
|
811
|
-
Auto
|
|
812
|
-
</Badge>
|
|
813
|
-
</CommandItem>
|
|
814
|
-
</CommandGroup>
|
|
815
|
-
|
|
816
|
-
<CommandSeparator />
|
|
817
|
-
|
|
818
|
-
<CommandGroup>
|
|
819
|
-
<CommandLabel>
|
|
820
|
-
<FeatureShineIcon className="mr-2" />
|
|
821
|
-
Features
|
|
822
|
-
</CommandLabel>
|
|
823
|
-
<CommandItem>
|
|
824
|
-
<MagicBookIcon />
|
|
825
|
-
Magic Features
|
|
826
|
-
<Badge color="neutral" className="ml-auto">
|
|
827
|
-
12
|
|
828
|
-
</Badge>
|
|
829
|
-
</CommandItem>
|
|
830
|
-
<CommandItem>
|
|
831
|
-
<LightBulbSimpleIcon />
|
|
832
|
-
Ideas
|
|
833
|
-
<Badge color="positive" className="ml-auto">
|
|
834
|
-
New
|
|
835
|
-
</Badge>
|
|
836
|
-
</CommandItem>
|
|
837
|
-
<CommandItem>
|
|
838
|
-
<FeatureShineIcon />
|
|
839
|
-
Special Features
|
|
840
|
-
<CommandShortcut>⌘⇧S</CommandShortcut>
|
|
841
|
-
</CommandItem>
|
|
842
|
-
</CommandGroup>
|
|
843
|
-
|
|
844
|
-
<CommandSeparator />
|
|
845
|
-
|
|
846
|
-
<CommandGroup>
|
|
847
|
-
<CommandLabel>
|
|
848
|
-
<TrashIcon className="mr-2" />
|
|
849
|
-
Dangerous Actions
|
|
850
|
-
</CommandLabel>
|
|
851
|
-
<CommandItem variant="destructive">
|
|
852
|
-
<TrashIcon />
|
|
853
|
-
Delete Account
|
|
854
|
-
<Badge color="negative" className="ml-auto">
|
|
855
|
-
!
|
|
856
|
-
</Badge>
|
|
857
|
-
</CommandItem>
|
|
858
|
-
<CommandItem variant="destructive">
|
|
859
|
-
<CrossCircleIcon />
|
|
860
|
-
Reset All Data
|
|
861
|
-
<CommandShortcut>⌘⇧R</CommandShortcut>
|
|
862
|
-
</CommandItem>
|
|
863
|
-
</CommandGroup>
|
|
864
|
-
</CommandList>
|
|
865
|
-
</Command>
|
|
866
|
-
</div>
|
|
867
|
-
),
|
|
868
|
-
parameters: {
|
|
869
|
-
docs: {
|
|
870
|
-
description: {
|
|
871
|
-
story:
|
|
872
|
-
"Complex command structure with multiple groups, icons in labels, badges for additional context, and both regular and destructive actions.",
|
|
873
|
-
},
|
|
874
|
-
},
|
|
875
|
-
},
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
// 7. Performance Demo
|
|
879
|
-
export const PerformanceDemo: Story = {
|
|
880
|
-
render: () => {
|
|
881
|
-
const [itemCount, setItemCount] = React.useState(100)
|
|
882
|
-
|
|
883
|
-
const generateItems = (count: number) => {
|
|
884
|
-
const categories = ["Files", "Actions", "Settings", "Images", "Tools"]
|
|
885
|
-
const icons = [
|
|
886
|
-
FileChartIcon,
|
|
887
|
-
EditBigIcon,
|
|
888
|
-
MaintenanceIcon,
|
|
889
|
-
ImageIcon,
|
|
890
|
-
CommandIcon,
|
|
891
|
-
]
|
|
892
|
-
const items = []
|
|
893
|
-
|
|
894
|
-
for (let i = 0; i < count; i++) {
|
|
895
|
-
const categoryIndex = i % categories.length
|
|
896
|
-
items.push({
|
|
897
|
-
id: i,
|
|
898
|
-
label: `${categories[categoryIndex]} Item ${i + 1}`,
|
|
899
|
-
icon: icons[categoryIndex],
|
|
900
|
-
category: categories[categoryIndex],
|
|
901
|
-
shortcut: i % 10 === 0 ? `⌘${i / 10}` : undefined,
|
|
902
|
-
})
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
return items
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
const items = React.useMemo(() => generateItems(itemCount), [itemCount])
|
|
909
|
-
const groupedItems = React.useMemo(() => {
|
|
910
|
-
return items.reduce(
|
|
911
|
-
(acc, item) => {
|
|
912
|
-
if (!acc[item.category]) {
|
|
913
|
-
acc[item.category] = []
|
|
914
|
-
}
|
|
915
|
-
acc[item.category].push(item)
|
|
916
|
-
return acc
|
|
917
|
-
},
|
|
918
|
-
{} as Record<string, typeof items>
|
|
919
|
-
)
|
|
920
|
-
}, [items])
|
|
921
|
-
|
|
922
|
-
return (
|
|
923
|
-
<div className="space-y-8 p-8">
|
|
924
|
-
<div className="space-y-4 text-center">
|
|
925
|
-
<h3 className="text-fm-primary text-lg font-medium">
|
|
926
|
-
Performance Demo
|
|
927
|
-
</h3>
|
|
928
|
-
<p className="text-fm-secondary text-sm">
|
|
929
|
-
Test command menu performance with large datasets
|
|
930
|
-
</p>
|
|
931
|
-
|
|
932
|
-
<div className="flex items-center justify-center gap-4">
|
|
933
|
-
<label className="text-fm-secondary text-sm">Items:</label>
|
|
934
|
-
<select
|
|
935
|
-
value={itemCount}
|
|
936
|
-
onChange={(e) => setItemCount(Number(e.target.value))}
|
|
937
|
-
className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-primary rounded border px-3 py-1"
|
|
938
|
-
>
|
|
939
|
-
<option value={50}>50</option>
|
|
940
|
-
<option value={100}>100</option>
|
|
941
|
-
<option value={500}>500</option>
|
|
942
|
-
<option value={1000}>1000</option>
|
|
943
|
-
</select>
|
|
944
|
-
<Badge color="info">{itemCount} items</Badge>
|
|
556
|
+
<div className="mx-auto max-w-md">
|
|
557
|
+
<Command className="border-fm-divider-secondary rounded-lg border">
|
|
558
|
+
<CommandInput placeholder="Search file actions…" />
|
|
559
|
+
<CommandList>
|
|
560
|
+
<CommandEmpty>No file actions found.</CommandEmpty>
|
|
561
|
+
<CommandGroup>
|
|
562
|
+
<CommandLabel>Create</CommandLabel>
|
|
563
|
+
<CommandItem>
|
|
564
|
+
<FileTextIcon />
|
|
565
|
+
New Playlist
|
|
566
|
+
<CommandShortcut>⌘N</CommandShortcut>
|
|
567
|
+
</CommandItem>
|
|
568
|
+
<CommandItem>
|
|
569
|
+
<UploadIcon />
|
|
570
|
+
Upload Track
|
|
571
|
+
<CommandShortcut>⌘U</CommandShortcut>
|
|
572
|
+
</CommandItem>
|
|
573
|
+
</CommandGroup>
|
|
574
|
+
<CommandSeparator />
|
|
575
|
+
<CommandGroup>
|
|
576
|
+
<CommandLabel>Manage</CommandLabel>
|
|
577
|
+
<CommandItem>
|
|
578
|
+
<EditBigIcon />
|
|
579
|
+
Edit Metadata
|
|
580
|
+
<CommandShortcut>⌘E</CommandShortcut>
|
|
581
|
+
</CommandItem>
|
|
582
|
+
<CommandItem>
|
|
583
|
+
<DownloadIcon />
|
|
584
|
+
Download Offline
|
|
585
|
+
<CommandShortcut>⌘D</CommandShortcut>
|
|
586
|
+
</CommandItem>
|
|
587
|
+
<CommandItem>
|
|
588
|
+
<ShareIcon />
|
|
589
|
+
Share
|
|
590
|
+
<CommandShortcut>⌘⇧S</CommandShortcut>
|
|
591
|
+
</CommandItem>
|
|
592
|
+
</CommandGroup>
|
|
593
|
+
<CommandSeparator />
|
|
594
|
+
<CommandGroup>
|
|
595
|
+
<CommandLabel>Danger Zone</CommandLabel>
|
|
596
|
+
<CommandItem variant="destructive">
|
|
597
|
+
<TrashIcon />
|
|
598
|
+
Remove from Library
|
|
599
|
+
<CommandShortcut>⌘⌫</CommandShortcut>
|
|
600
|
+
</CommandItem>
|
|
601
|
+
</CommandGroup>
|
|
602
|
+
</CommandList>
|
|
603
|
+
</Command>
|
|
945
604
|
</div>
|
|
946
605
|
</div>
|
|
947
606
|
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
<CommandEmpty>
|
|
953
|
-
No results found in {itemCount} items.
|
|
954
|
-
</CommandEmpty>
|
|
955
|
-
|
|
956
|
-
{Object.entries(groupedItems).map(([category, categoryItems]) => (
|
|
957
|
-
<React.Fragment key={category}>
|
|
958
|
-
<CommandGroup>
|
|
959
|
-
<CommandLabel>
|
|
960
|
-
{category} ({categoryItems.length})
|
|
961
|
-
</CommandLabel>
|
|
962
|
-
{categoryItems.map((item) => {
|
|
963
|
-
const IconComponent = item.icon
|
|
964
|
-
return (
|
|
965
|
-
<CommandItem key={item.id}>
|
|
966
|
-
<IconComponent />
|
|
967
|
-
{item.label}
|
|
968
|
-
{item.shortcut && (
|
|
969
|
-
<CommandShortcut>{item.shortcut}</CommandShortcut>
|
|
970
|
-
)}
|
|
971
|
-
</CommandItem>
|
|
972
|
-
)
|
|
973
|
-
})}
|
|
974
|
-
</CommandGroup>
|
|
975
|
-
{Object.keys(groupedItems).indexOf(category) <
|
|
976
|
-
Object.keys(groupedItems).length - 1 && (
|
|
977
|
-
<CommandSeparator />
|
|
978
|
-
)}
|
|
979
|
-
</React.Fragment>
|
|
980
|
-
))}
|
|
981
|
-
</CommandList>
|
|
982
|
-
</Command>
|
|
983
|
-
</div>
|
|
984
|
-
|
|
985
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary mx-auto max-w-lg rounded-lg border p-4">
|
|
986
|
-
<h4 className="text-fm-primary text-sm font-medium">
|
|
987
|
-
Performance Info
|
|
607
|
+
{/* 3 — Action shortcuts */}
|
|
608
|
+
<div className="space-y-3">
|
|
609
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
610
|
+
Playback Action Shortcuts
|
|
988
611
|
</h4>
|
|
989
|
-
<div className="
|
|
990
|
-
<
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
612
|
+
<div className="mx-auto max-w-md">
|
|
613
|
+
<Command className="border-fm-divider-secondary rounded-lg border">
|
|
614
|
+
<CommandInput placeholder="Search playback actions…" />
|
|
615
|
+
<CommandList>
|
|
616
|
+
<CommandEmpty>No playback actions found.</CommandEmpty>
|
|
617
|
+
<CommandGroup>
|
|
618
|
+
<CommandLabel>Now Playing</CommandLabel>
|
|
619
|
+
<CommandItem>
|
|
620
|
+
<HeartIcon />
|
|
621
|
+
Like Track
|
|
622
|
+
<CommandShortcut>⌘L</CommandShortcut>
|
|
623
|
+
</CommandItem>
|
|
624
|
+
<CommandItem>
|
|
625
|
+
<SkipForwardIcon />
|
|
626
|
+
Skip to Next
|
|
627
|
+
<CommandShortcut>⌘→</CommandShortcut>
|
|
628
|
+
</CommandItem>
|
|
629
|
+
<CommandItem>
|
|
630
|
+
<AudioBarIcon />
|
|
631
|
+
Add to Queue
|
|
632
|
+
<CommandShortcut>⌘Q</CommandShortcut>
|
|
633
|
+
</CommandItem>
|
|
634
|
+
<CommandItem>
|
|
635
|
+
<SparklesSoftIcon />
|
|
636
|
+
Start Radio
|
|
637
|
+
<CommandShortcut>⌘R</CommandShortcut>
|
|
638
|
+
</CommandItem>
|
|
639
|
+
<CommandItem>
|
|
640
|
+
<CircleTickIcon />
|
|
641
|
+
Mark as Listened
|
|
642
|
+
</CommandItem>
|
|
643
|
+
</CommandGroup>
|
|
644
|
+
<CommandSeparator />
|
|
645
|
+
<CommandGroup>
|
|
646
|
+
<CommandLabel>View</CommandLabel>
|
|
647
|
+
<CommandItem>
|
|
648
|
+
<ImageIcon />
|
|
649
|
+
Show Album Art
|
|
650
|
+
<CommandShortcut>⌘⇧A</CommandShortcut>
|
|
651
|
+
</CommandItem>
|
|
652
|
+
<CommandItem>
|
|
653
|
+
<VerticalMenuIcon />
|
|
654
|
+
Track Info
|
|
655
|
+
<CommandShortcut>⌘I</CommandShortcut>
|
|
656
|
+
</CommandItem>
|
|
657
|
+
</CommandGroup>
|
|
658
|
+
</CommandList>
|
|
659
|
+
</Command>
|
|
997
660
|
</div>
|
|
998
661
|
</div>
|
|
999
662
|
</div>
|
|
@@ -1003,7 +666,7 @@ export const PerformanceDemo: Story = {
|
|
|
1003
666
|
docs: {
|
|
1004
667
|
description: {
|
|
1005
668
|
story:
|
|
1006
|
-
"
|
|
669
|
+
"Three real-world use cases in a single export: (1) a global app search dialog triggered by ⌘K covering tracks, playlists, and settings; (2) a file-management command palette for create/manage/delete operations; (3) a playback action shortcut palette for controlling the currently playing track without leaving the keyboard.",
|
|
1007
670
|
},
|
|
1008
671
|
},
|
|
1009
672
|
},
|