aural-ui 3.0.7 → 4.1.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/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1199
- package/dist/components/avatar/Avatar.stories.tsx +235 -237
- 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/button/index.tsx +7 -7
- 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 -620
- 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 +533 -856
- package/dist/components/dialog/Dialog.stories.tsx +505 -949
- package/dist/components/divider/Divider.stories.tsx +265 -502
- package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
- package/dist/components/drawer/Drawer.stories.tsx +659 -993
- package/dist/components/drawer/index.tsx +3 -3
- package/dist/components/dropdown/Dropdown.stories.tsx +643 -1018
- 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 -1221
- 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 +485 -822
- package/dist/components/marquee/Marquee.stories.tsx +356 -694
- package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -410
- package/dist/components/overlay/Overlay.stories.tsx +452 -818
- package/dist/components/overlay/index.tsx +4 -4
- package/dist/components/pagination/Pagination.stories.tsx +721 -210
- package/dist/components/popover/Popover.stories.tsx +484 -873
- package/dist/components/radio/Radio.stories.tsx +432 -124
- package/dist/components/resizable/Resizable.stories.tsx +496 -752
- package/dist/components/scroll-area/ScrollArea.stories.tsx +384 -1006
- package/dist/components/search/Search.stories.tsx +314 -575
- package/dist/components/select/Select.stories.tsx +684 -787
- package/dist/components/sheet/Sheet.stories.tsx +671 -936
- package/dist/components/skelton/Skelton.stories.tsx +230 -764
- package/dist/components/slider/Slider.stories.tsx +384 -737
- 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 -914
- package/dist/components/tabs/Tabs.stories.tsx +459 -1400
- 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 -148
- package/dist/components/toast/Toast.stories.tsx +452 -1333
- package/dist/components/toggle/Toggle.stories.tsx +488 -909
- package/dist/components/tooltip/Tooltip.stories.tsx +344 -1372
- 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 +226 -1013
- package/dist/icons/alert-icon/AlertIcon.stories.tsx +109 -929
- package/dist/icons/all-icons.tsx +124 -87
- package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +140 -971
- package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +148 -888
- package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +135 -1019
- package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +137 -953
- package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +138 -997
- package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +136 -942
- package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +148 -1092
- package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +146 -1211
- package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +126 -615
- package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +144 -1164
- package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +167 -985
- package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +122 -1179
- package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +124 -1168
- package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +119 -850
- package/dist/icons/camera-icon/CameraIcon.stories.tsx +112 -1213
- package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +117 -934
- package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +160 -961
- package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +163 -961
- package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +144 -942
- package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +129 -966
- package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +147 -964
- package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +145 -975
- package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +150 -1142
- package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +114 -461
- package/dist/icons/coin-icon/CoinIcon.stories.tsx +124 -1322
- package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +117 -1318
- package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +114 -903
- package/dist/icons/command-icon/CommandIcon.stories.tsx +127 -1042
- package/dist/icons/copy-icon/CopyIcon.stories.tsx +123 -962
- package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +147 -999
- package/dist/icons/cross-icon/CrossIcon.stories.tsx +139 -960
- package/dist/icons/download-icon/DownloadIcon.stories.tsx +126 -820
- package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +124 -1031
- package/dist/icons/email-icon/EmailIcon.stories.tsx +115 -936
- package/dist/icons/expand-icon/ExpandIcon.stories.tsx +112 -1111
- package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +144 -1025
- package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +143 -1036
- package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +127 -1011
- package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +126 -1056
- package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +125 -614
- package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +119 -1050
- package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +169 -989
- package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +115 -1145
- package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +115 -1122
- package/dist/icons/globe-icon/GlobeIcon.stories.tsx +130 -313
- package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +145 -940
- package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +119 -1174
- package/dist/icons/head-icon/HeadIcon.stories.tsx +111 -916
- package/dist/icons/heart-icon/HeartIcon.stories.tsx +120 -1019
- package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +119 -683
- package/dist/icons/image-icon/ImageIcon.stories.tsx +105 -1121
- package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +111 -1192
- package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +136 -1256
- package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +159 -962
- package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +161 -1385
- package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +124 -972
- package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +119 -948
- package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +119 -942
- package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +108 -1215
- package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +154 -1517
- package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +110 -1188
- package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +119 -678
- package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +123 -1184
- package/dist/icons/message-icon/MessageIcon.stories.tsx +114 -538
- package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +116 -1158
- package/dist/icons/moon-icon/MoonIcon.stories.tsx +120 -536
- package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +109 -1184
- package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +115 -1134
- package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +119 -971
- package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +111 -1100
- package/dist/icons/notes-icon/NotesIcon.stories.tsx +119 -1101
- package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +109 -1111
- package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +122 -684
- package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +113 -954
- package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +112 -877
- package/dist/icons/pause-icon/PauseIcon.stories.tsx +113 -1000
- package/dist/icons/pencil-icon/PencilIcon.stories.tsx +115 -1070
- package/dist/icons/phone-icon/PhoneIcon.stories.tsx +115 -978
- package/dist/icons/plus-icon/PlusIcon.stories.tsx +106 -1093
- package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +107 -829
- package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +102 -469
- package/dist/icons/search-icon/SearchIcon.stories.tsx +111 -1124
- package/dist/icons/setting-icon/SettingIcon.stories.tsx +107 -970
- package/dist/icons/share-icon/ShareIcon.stories.tsx +120 -1025
- package/dist/icons/shield-icon/ShieldIcon.stories.tsx +117 -931
- package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +137 -1104
- package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +172 -982
- package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +164 -983
- package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +105 -958
- package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +158 -580
- package/dist/icons/spinner-gradient-icon/index.tsx +6 -1
- package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +158 -587
- package/dist/icons/spinner-solid-icon/index.tsx +6 -1
- package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +146 -682
- package/dist/icons/spinner-solid-neutral-icon/index.tsx +1 -1
- package/dist/icons/star-icon/StarIcon.stories.tsx +124 -904
- package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +112 -964
- package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +116 -852
- package/dist/icons/sun-icon/SunIcon.stories.tsx +120 -831
- package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +116 -950
- package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +123 -980
- package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +156 -1427
- package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +146 -1142
- package/dist/icons/tick-icon/TickIcon.stories.tsx +145 -1276
- package/dist/icons/trash-icon/TrashIcon.stories.tsx +108 -933
- package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +157 -1402
- package/dist/icons/upload-icon/UploadIcon.stories.tsx +115 -889
- package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +118 -984
- package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +125 -1049
- package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +123 -1356
- package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +110 -1171
- package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +112 -1093
- package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +115 -1087
- package/dist/icons/warning-icon/WarningIcon.stories.tsx +122 -1046
- package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +161 -936
- package/dist/index.cjs +84 -84
- package/dist/index.js +84 -84
- package/dist/styles/aural-all-theme.css +1222 -0
- package/dist/styles/{aural-theme.css → aural-dark-theme.css} +15 -3
- package/dist/styles/aural-light-theme.css +1047 -0
- package/package.json +1 -1
|
@@ -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="mb-4 text-lg font-medium text-white">
|
|
134
|
-
Basic Command Menu
|
|
135
|
-
</h3>
|
|
136
|
-
<Command className="rounded-lg border border-white/10">
|
|
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,254 +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-lg font-medium text-white">File Management</h3>
|
|
313
|
-
<Command className="rounded-lg border border-white/10">
|
|
314
|
-
<CommandInput placeholder="Search files and actions..." />
|
|
315
|
-
<CommandList>
|
|
316
|
-
<CommandEmpty>
|
|
317
|
-
<div className="py-6 text-center">
|
|
318
|
-
<SearchIcon className="mx-auto h-8 w-8 text-white/30" />
|
|
319
|
-
<p className="mt-2 text-sm text-white/60">
|
|
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
|
-
},
|
|
236
|
+
const tracks = [
|
|
445
237
|
{
|
|
446
|
-
id: "
|
|
447
|
-
label: "
|
|
448
|
-
|
|
449
|
-
group: "
|
|
238
|
+
id: "t1",
|
|
239
|
+
label: "Midnight Echoes",
|
|
240
|
+
artist: "Luna Vex",
|
|
241
|
+
group: "Tracks",
|
|
450
242
|
},
|
|
451
243
|
{
|
|
452
|
-
id: "
|
|
453
|
-
label: "
|
|
454
|
-
|
|
455
|
-
group: "
|
|
456
|
-
},
|
|
457
|
-
{
|
|
458
|
-
id: "maintenance",
|
|
459
|
-
label: "Maintenance",
|
|
460
|
-
icon: <MaintenanceIcon />,
|
|
461
|
-
group: "Apps",
|
|
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
|
-
|
|
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>
|
|
502
289
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
value={searchTerm}
|
|
507
|
-
onValueChange={setSearchTerm}
|
|
508
|
-
/>
|
|
509
|
-
<CommandList>
|
|
510
|
-
<CommandEmpty>
|
|
511
|
-
<div className="py-6 text-center">
|
|
512
|
-
<SearchIcon className="mx-auto h-8 w-8 text-white/30" />
|
|
513
|
-
<p className="mt-2 text-sm text-white/60">
|
|
514
|
-
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
|
|
515
293
|
</p>
|
|
516
|
-
<p className="text-
|
|
517
|
-
|
|
294
|
+
<p className="text-fm-primary font-fm-text text-fm-md leading-fm-md truncate font-medium">
|
|
295
|
+
{search || "—"}
|
|
518
296
|
</p>
|
|
519
297
|
</div>
|
|
520
|
-
</CommandEmpty>
|
|
521
298
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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>
|
|
547
453
|
</div>
|
|
548
454
|
</div>
|
|
549
|
-
|
|
455
|
+
</div>
|
|
550
456
|
</div>
|
|
551
457
|
)
|
|
552
458
|
},
|
|
@@ -554,432 +460,203 @@ export const SearchAndFilterCommands: Story = {
|
|
|
554
460
|
docs: {
|
|
555
461
|
description: {
|
|
556
462
|
story:
|
|
557
|
-
"
|
|
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.",
|
|
558
464
|
},
|
|
559
465
|
},
|
|
560
466
|
},
|
|
561
467
|
}
|
|
562
468
|
|
|
563
|
-
//
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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)
|
|
492
|
+
</h4>
|
|
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"
|
|
578
511
|
>
|
|
579
|
-
<CommandInput placeholder="
|
|
512
|
+
<CommandInput placeholder="Search everything…" />
|
|
580
513
|
<CommandList>
|
|
581
514
|
<CommandEmpty>No results found.</CommandEmpty>
|
|
582
515
|
<CommandGroup>
|
|
583
|
-
<CommandLabel>
|
|
584
|
-
<CommandItem>
|
|
585
|
-
<
|
|
586
|
-
|
|
587
|
-
<Badge color="positive" className="ml-auto">
|
|
588
|
-
Pro
|
|
589
|
-
</Badge>
|
|
516
|
+
<CommandLabel>Tracks</CommandLabel>
|
|
517
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
518
|
+
<MusicalNoteIcon />
|
|
519
|
+
Midnight Echoes — Luna Vex
|
|
590
520
|
</CommandItem>
|
|
591
|
-
<CommandItem>
|
|
592
|
-
<
|
|
593
|
-
|
|
521
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
522
|
+
<MusicalNoteIcon />
|
|
523
|
+
Solar Drift — The Velvet Faders
|
|
594
524
|
</CommandItem>
|
|
595
525
|
</CommandGroup>
|
|
596
|
-
|
|
597
|
-
</Command>
|
|
598
|
-
</div>
|
|
599
|
-
|
|
600
|
-
{/* Compact Command */}
|
|
601
|
-
<div className="space-y-4">
|
|
602
|
-
<h4 className="text-sm font-medium text-white/70">Compact Style</h4>
|
|
603
|
-
<Command
|
|
604
|
-
className="rounded-lg border border-white/10"
|
|
605
|
-
listProps={{ size: "sm" }}
|
|
606
|
-
>
|
|
607
|
-
<CommandInput
|
|
608
|
-
placeholder="Compact menu..."
|
|
609
|
-
classes={{ input: "text-xs" }}
|
|
610
|
-
/>
|
|
611
|
-
<CommandList>
|
|
612
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
526
|
+
<CommandSeparator />
|
|
613
527
|
<CommandGroup>
|
|
614
|
-
<CommandLabel>
|
|
615
|
-
<CommandItem>
|
|
616
|
-
<
|
|
617
|
-
|
|
618
|
-
<CommandShortcut>⌘N</CommandShortcut>
|
|
619
|
-
</CommandItem>
|
|
620
|
-
<CommandItem>
|
|
621
|
-
<SearchIcon />
|
|
622
|
-
Find
|
|
623
|
-
<CommandShortcut>⌘F</CommandShortcut>
|
|
528
|
+
<CommandLabel>Playlists</CommandLabel>
|
|
529
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
530
|
+
<AudioBarIcon />
|
|
531
|
+
Late Night Drive
|
|
624
532
|
</CommandItem>
|
|
625
|
-
<CommandItem>
|
|
626
|
-
<
|
|
627
|
-
|
|
628
|
-
<CommandShortcut>⌘R</CommandShortcut>
|
|
533
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
534
|
+
<AudioBarIcon />
|
|
535
|
+
Focus Mode
|
|
629
536
|
</CommandItem>
|
|
630
537
|
</CommandGroup>
|
|
631
|
-
|
|
632
|
-
</Command>
|
|
633
|
-
</div>
|
|
634
|
-
|
|
635
|
-
{/* Flat Style */}
|
|
636
|
-
<div className="space-y-4">
|
|
637
|
-
<h4 className="text-sm font-medium text-white/70">Flat Style</h4>
|
|
638
|
-
<Command
|
|
639
|
-
className="rounded-lg border border-white/10"
|
|
640
|
-
listProps={{ variant: "flat", rounded: "lg" }}
|
|
641
|
-
>
|
|
642
|
-
<CommandInput placeholder="Flat design menu..." />
|
|
643
|
-
<CommandList>
|
|
644
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
538
|
+
<CommandSeparator />
|
|
645
539
|
<CommandGroup>
|
|
646
|
-
<CommandLabel>
|
|
647
|
-
<CommandItem>
|
|
540
|
+
<CommandLabel>Settings</CommandLabel>
|
|
541
|
+
<CommandItem onSelect={() => setGlobalOpen(false)}>
|
|
648
542
|
<MaintenanceIcon />
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
<CommandItem>
|
|
652
|
-
<EyeOpenIcon />
|
|
653
|
-
Account
|
|
543
|
+
Audio Quality
|
|
544
|
+
<CommandShortcut>⌘,</CommandShortcut>
|
|
654
545
|
</CommandItem>
|
|
655
546
|
</CommandGroup>
|
|
656
547
|
</CommandList>
|
|
657
|
-
</
|
|
548
|
+
</CommandDialog>
|
|
658
549
|
</div>
|
|
659
550
|
|
|
660
|
-
{/*
|
|
661
|
-
<div className="space-y-
|
|
662
|
-
<h4 className="text-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
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
|
-
<Command className="rounded-lg border border-white/10">
|
|
714
|
-
<CommandInput placeholder="Search all commands..." />
|
|
715
|
-
<CommandList>
|
|
716
|
-
<CommandEmpty>
|
|
717
|
-
<div className="py-8 text-center">
|
|
718
|
-
<SearchIcon className="mx-auto h-12 w-12 text-white/20" />
|
|
719
|
-
<h4 className="mt-2 text-sm font-medium text-white">
|
|
720
|
-
No commands found
|
|
721
|
-
</h4>
|
|
722
|
-
<p className="mt-1 text-xs text-white/60">
|
|
723
|
-
Try adjusting your search to find what you're looking for.
|
|
724
|
-
</p>
|
|
725
|
-
</div>
|
|
726
|
-
</CommandEmpty>
|
|
727
|
-
|
|
728
|
-
<CommandGroup>
|
|
729
|
-
<CommandLabel>
|
|
730
|
-
<FileChartIcon className="mr-2" />
|
|
731
|
-
File Operations
|
|
732
|
-
</CommandLabel>
|
|
733
|
-
<CommandItem>
|
|
734
|
-
<FileChartIcon />
|
|
735
|
-
New Document
|
|
736
|
-
<Badge color="info" className="ml-auto">
|
|
737
|
-
Ctrl+N
|
|
738
|
-
</Badge>
|
|
739
|
-
</CommandItem>
|
|
740
|
-
<CommandItem>
|
|
741
|
-
<ImportFolderIcon />
|
|
742
|
-
Open Folder
|
|
743
|
-
<CommandShortcut>⌘O</CommandShortcut>
|
|
744
|
-
</CommandItem>
|
|
745
|
-
<CommandItem>
|
|
746
|
-
<EditBigIcon />
|
|
747
|
-
Recent Files
|
|
748
|
-
<Badge color="neutral" className="ml-auto">
|
|
749
|
-
5
|
|
750
|
-
</Badge>
|
|
751
|
-
</CommandItem>
|
|
752
|
-
</CommandGroup>
|
|
753
|
-
|
|
754
|
-
<CommandSeparator />
|
|
755
|
-
|
|
756
|
-
<CommandGroup>
|
|
757
|
-
<CommandLabel>
|
|
758
|
-
<EyeOpenIcon className="mr-2" />
|
|
759
|
-
User Management
|
|
760
|
-
</CommandLabel>
|
|
761
|
-
<CommandItem>
|
|
762
|
-
<EyeOpenIcon />
|
|
763
|
-
View Profile
|
|
764
|
-
<CommandShortcut>⌘P</CommandShortcut>
|
|
765
|
-
</CommandItem>
|
|
766
|
-
<CommandItem>
|
|
767
|
-
<MaintenanceIcon />
|
|
768
|
-
User Settings
|
|
769
|
-
<CommandShortcut>⌘,</CommandShortcut>
|
|
770
|
-
</CommandItem>
|
|
771
|
-
<CommandItem>
|
|
772
|
-
<BubbleSparkleIcon />
|
|
773
|
-
Share Profile
|
|
774
|
-
<Badge color="warning" className="ml-auto">
|
|
775
|
-
Beta
|
|
776
|
-
</Badge>
|
|
777
|
-
</CommandItem>
|
|
778
|
-
</CommandGroup>
|
|
779
|
-
|
|
780
|
-
<CommandSeparator />
|
|
781
|
-
|
|
782
|
-
<CommandGroup>
|
|
783
|
-
<CommandLabel>
|
|
784
|
-
<UploadIcon className="mr-2" />
|
|
785
|
-
Data Management
|
|
786
|
-
</CommandLabel>
|
|
787
|
-
<CommandItem>
|
|
788
|
-
<ArrowRightIcon />
|
|
789
|
-
Export Data
|
|
790
|
-
<CommandShortcut>⌘E</CommandShortcut>
|
|
791
|
-
</CommandItem>
|
|
792
|
-
<CommandItem>
|
|
793
|
-
<UploadIcon />
|
|
794
|
-
Import Data
|
|
795
|
-
<CommandShortcut>⌘I</CommandShortcut>
|
|
796
|
-
</CommandItem>
|
|
797
|
-
<CommandItem>
|
|
798
|
-
<MaintenanceIcon />
|
|
799
|
-
Sync Data
|
|
800
|
-
<Badge color="positive" className="ml-auto">
|
|
801
|
-
Auto
|
|
802
|
-
</Badge>
|
|
803
|
-
</CommandItem>
|
|
804
|
-
</CommandGroup>
|
|
805
|
-
|
|
806
|
-
<CommandSeparator />
|
|
807
|
-
|
|
808
|
-
<CommandGroup>
|
|
809
|
-
<CommandLabel>
|
|
810
|
-
<FeatureShineIcon className="mr-2" />
|
|
811
|
-
Features
|
|
812
|
-
</CommandLabel>
|
|
813
|
-
<CommandItem>
|
|
814
|
-
<MagicBookIcon />
|
|
815
|
-
Magic Features
|
|
816
|
-
<Badge color="neutral" className="ml-auto">
|
|
817
|
-
12
|
|
818
|
-
</Badge>
|
|
819
|
-
</CommandItem>
|
|
820
|
-
<CommandItem>
|
|
821
|
-
<LightBulbSimpleIcon />
|
|
822
|
-
Ideas
|
|
823
|
-
<Badge color="positive" className="ml-auto">
|
|
824
|
-
New
|
|
825
|
-
</Badge>
|
|
826
|
-
</CommandItem>
|
|
827
|
-
<CommandItem>
|
|
828
|
-
<FeatureShineIcon />
|
|
829
|
-
Special Features
|
|
830
|
-
<CommandShortcut>⌘⇧S</CommandShortcut>
|
|
831
|
-
</CommandItem>
|
|
832
|
-
</CommandGroup>
|
|
833
|
-
|
|
834
|
-
<CommandSeparator />
|
|
835
|
-
|
|
836
|
-
<CommandGroup>
|
|
837
|
-
<CommandLabel>
|
|
838
|
-
<TrashIcon className="mr-2" />
|
|
839
|
-
Dangerous Actions
|
|
840
|
-
</CommandLabel>
|
|
841
|
-
<CommandItem variant="destructive">
|
|
842
|
-
<TrashIcon />
|
|
843
|
-
Delete Account
|
|
844
|
-
<Badge color="negative" className="ml-auto">
|
|
845
|
-
!
|
|
846
|
-
</Badge>
|
|
847
|
-
</CommandItem>
|
|
848
|
-
<CommandItem variant="destructive">
|
|
849
|
-
<CrossCircleIcon />
|
|
850
|
-
Reset All Data
|
|
851
|
-
<CommandShortcut>⌘⇧R</CommandShortcut>
|
|
852
|
-
</CommandItem>
|
|
853
|
-
</CommandGroup>
|
|
854
|
-
</CommandList>
|
|
855
|
-
</Command>
|
|
856
|
-
</div>
|
|
857
|
-
),
|
|
858
|
-
parameters: {
|
|
859
|
-
docs: {
|
|
860
|
-
description: {
|
|
861
|
-
story:
|
|
862
|
-
"Complex command structure with multiple groups, icons in labels, badges for additional context, and both regular and destructive actions.",
|
|
863
|
-
},
|
|
864
|
-
},
|
|
865
|
-
},
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
// 7. Performance Demo
|
|
869
|
-
export const PerformanceDemo: Story = {
|
|
870
|
-
render: () => {
|
|
871
|
-
const [itemCount, setItemCount] = React.useState(100)
|
|
872
|
-
|
|
873
|
-
const generateItems = (count: number) => {
|
|
874
|
-
const categories = ["Files", "Actions", "Settings", "Images", "Tools"]
|
|
875
|
-
const icons = [
|
|
876
|
-
FileChartIcon,
|
|
877
|
-
EditBigIcon,
|
|
878
|
-
MaintenanceIcon,
|
|
879
|
-
ImageIcon,
|
|
880
|
-
CommandIcon,
|
|
881
|
-
]
|
|
882
|
-
const items = []
|
|
883
|
-
|
|
884
|
-
for (let i = 0; i < count; i++) {
|
|
885
|
-
const categoryIndex = i % categories.length
|
|
886
|
-
items.push({
|
|
887
|
-
id: i,
|
|
888
|
-
label: `${categories[categoryIndex]} Item ${i + 1}`,
|
|
889
|
-
icon: icons[categoryIndex],
|
|
890
|
-
category: categories[categoryIndex],
|
|
891
|
-
shortcut: i % 10 === 0 ? `⌘${i / 10}` : undefined,
|
|
892
|
-
})
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
return items
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
const items = React.useMemo(() => generateItems(itemCount), [itemCount])
|
|
899
|
-
const groupedItems = React.useMemo(() => {
|
|
900
|
-
return items.reduce(
|
|
901
|
-
(acc, item) => {
|
|
902
|
-
if (!acc[item.category]) {
|
|
903
|
-
acc[item.category] = []
|
|
904
|
-
}
|
|
905
|
-
acc[item.category].push(item)
|
|
906
|
-
return acc
|
|
907
|
-
},
|
|
908
|
-
{} as Record<string, typeof items>
|
|
909
|
-
)
|
|
910
|
-
}, [items])
|
|
911
|
-
|
|
912
|
-
return (
|
|
913
|
-
<div className="space-y-8 p-8">
|
|
914
|
-
<div className="space-y-4 text-center">
|
|
915
|
-
<h3 className="text-lg font-medium text-white">Performance Demo</h3>
|
|
916
|
-
<p className="text-sm text-white/60">
|
|
917
|
-
Test command menu performance with large datasets
|
|
918
|
-
</p>
|
|
919
|
-
|
|
920
|
-
<div className="flex items-center justify-center gap-4">
|
|
921
|
-
<label className="text-sm text-white/70">Items:</label>
|
|
922
|
-
<select
|
|
923
|
-
value={itemCount}
|
|
924
|
-
onChange={(e) => setItemCount(Number(e.target.value))}
|
|
925
|
-
className="rounded border border-white/20 bg-white/10 px-3 py-1 text-white"
|
|
926
|
-
>
|
|
927
|
-
<option value={50}>50</option>
|
|
928
|
-
<option value={100}>100</option>
|
|
929
|
-
<option value={500}>500</option>
|
|
930
|
-
<option value={1000}>1000</option>
|
|
931
|
-
</select>
|
|
932
|
-
<Badge color="info">{itemCount} items</Badge>
|
|
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
|
|
555
|
+
</h4>
|
|
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>
|
|
933
604
|
</div>
|
|
934
605
|
</div>
|
|
935
606
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
<
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
</
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
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
|
|
611
|
+
</h4>
|
|
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>
|
|
983
660
|
</div>
|
|
984
661
|
</div>
|
|
985
662
|
</div>
|
|
@@ -989,7 +666,7 @@ export const PerformanceDemo: Story = {
|
|
|
989
666
|
docs: {
|
|
990
667
|
description: {
|
|
991
668
|
story:
|
|
992
|
-
"
|
|
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.",
|
|
993
670
|
},
|
|
994
671
|
},
|
|
995
672
|
},
|