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,24 +1,20 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import React, { useState } from "react"
|
|
3
|
-
import { Badge } from "@components/badge"
|
|
4
3
|
import { Button } from "@components/button"
|
|
5
4
|
import { Checkbox } from "@components/checkbox"
|
|
6
|
-
import { IconButton } from "@components/icon-button"
|
|
7
5
|
import Input from "@components/input"
|
|
8
6
|
import { Label } from "@components/label"
|
|
9
|
-
import Textarea from "@components/textarea"
|
|
10
7
|
import { AlertIcon } from "@icons/alert-icon"
|
|
11
|
-
import { ArrowRightIcon } from "@icons/arrow-right-icon"
|
|
12
8
|
import { ChevronRightIcon } from "@icons/chevron-right-icon"
|
|
13
|
-
import { FeatureShineIcon } from "@icons/feature-shine-icon"
|
|
14
|
-
import { FileChartIcon } from "@icons/file-chart-icon"
|
|
15
|
-
import { MagicBookIcon } from "@icons/magic-book-icon"
|
|
16
9
|
import { MaintenanceIcon } from "@icons/maintenance-icon"
|
|
10
|
+
import { MusicalNoteIcon } from "@icons/musical-note-icon"
|
|
17
11
|
import { SearchIcon } from "@icons/search-icon"
|
|
18
12
|
import { SiteLogoIcon } from "@icons/site-logo-icon"
|
|
19
13
|
import { TickCircleIcon } from "@icons/tick-circle-icon"
|
|
20
14
|
import type { Meta, StoryObj } from "@storybook/react-vite"
|
|
21
15
|
|
|
16
|
+
import { AuralComponentDocsPage } from "src/ui/story-spec/components/component-story-docs-page"
|
|
17
|
+
|
|
22
18
|
import {
|
|
23
19
|
Sheet,
|
|
24
20
|
SheetClose,
|
|
@@ -34,115 +30,30 @@ const meta: Meta<typeof Sheet> = {
|
|
|
34
30
|
title: "Components/UI/Sheet",
|
|
35
31
|
component: Sheet,
|
|
36
32
|
parameters: {
|
|
37
|
-
layout: "
|
|
38
|
-
backgrounds: {
|
|
39
|
-
default: "dark",
|
|
40
|
-
values: [
|
|
41
|
-
{ name: "dark", value: "#0a0a0a" },
|
|
42
|
-
{ name: "light", value: "#ffffff" },
|
|
43
|
-
],
|
|
44
|
-
},
|
|
33
|
+
layout: "centered",
|
|
45
34
|
docs: {
|
|
46
35
|
description: {
|
|
47
|
-
component:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
A slide-out panel component built on Radix UI Dialog primitives that provides a drawer-like interface for displaying content from different sides of the screen.
|
|
51
|
-
|
|
52
|
-
## Features
|
|
53
|
-
|
|
54
|
-
- **Multiple Sides**: Sheet can slide in from top, right, bottom, or left
|
|
55
|
-
- **Variant Colors**: Neutral, positive, negative, warning, and info color variants
|
|
56
|
-
- **Customizable Overlays**: Configurable opacity, glass effects, and noise textures
|
|
57
|
-
- **Smooth Animations**: Slide animations with proper easing for each direction
|
|
58
|
-
- **Accessible**: Full keyboard navigation and screen reader support
|
|
59
|
-
- **Flexible Content**: Header, footer, and body sections with custom styling
|
|
60
|
-
- **Auto Close Button**: Positioned close button with CrossIcon
|
|
61
|
-
- **Portal Rendering**: Renders outside normal DOM hierarchy
|
|
62
|
-
- **Focus Management**: Automatic focus trapping and restoration
|
|
63
|
-
- **Border Accents**: Colored borders that match the variant
|
|
64
|
-
|
|
65
|
-
## Component Structure
|
|
66
|
-
|
|
67
|
-
- **Sheet**: Root component that manages sheet state
|
|
68
|
-
- **SheetTrigger**: Button or element that opens the sheet
|
|
69
|
-
- **SheetContent**: Main sheet container with overlay, content, and close button
|
|
70
|
-
- **SheetHeader**: Header section for title and description
|
|
71
|
-
- **SheetFooter**: Footer section for action buttons
|
|
72
|
-
- **SheetTitle**: Accessible title element
|
|
73
|
-
- **SheetDescription**: Optional description text
|
|
74
|
-
- **SheetClose**: Close button component
|
|
75
|
-
|
|
76
|
-
## Usage Examples
|
|
77
|
-
|
|
78
|
-
### Basic Sheet
|
|
79
|
-
\`\`\`tsx
|
|
80
|
-
<Sheet>
|
|
81
|
-
<SheetTrigger asChild>
|
|
82
|
-
<Button>Open Sheet</Button>
|
|
83
|
-
</SheetTrigger>
|
|
84
|
-
<SheetContent>
|
|
85
|
-
<SheetHeader>
|
|
86
|
-
<SheetTitle>Sheet Title</SheetTitle>
|
|
87
|
-
<SheetDescription>Sheet description text.</SheetDescription>
|
|
88
|
-
</SheetHeader>
|
|
89
|
-
<div>Sheet content goes here.</div>
|
|
90
|
-
<SheetFooter>
|
|
91
|
-
<SheetClose asChild>
|
|
92
|
-
<Button variant="outline">Cancel</Button>
|
|
93
|
-
</SheetClose>
|
|
94
|
-
<Button>Confirm</Button>
|
|
95
|
-
</SheetFooter>
|
|
96
|
-
</SheetContent>
|
|
97
|
-
</Sheet>
|
|
98
|
-
\`\`\`
|
|
99
|
-
|
|
100
|
-
### Sheet from Different Sides
|
|
101
|
-
\`\`\`tsx
|
|
102
|
-
<SheetContent side="left">
|
|
103
|
-
{/* Left side sheet */}
|
|
104
|
-
</SheetContent>
|
|
105
|
-
|
|
106
|
-
<SheetContent side="right">
|
|
107
|
-
{/* Right side sheet (default) */}
|
|
108
|
-
</SheetContent>
|
|
109
|
-
|
|
110
|
-
<SheetContent side="top">
|
|
111
|
-
{/* Top side sheet */}
|
|
112
|
-
</SheetContent>
|
|
113
|
-
|
|
114
|
-
<SheetContent side="bottom">
|
|
115
|
-
{/* Bottom side sheet */}
|
|
116
|
-
</SheetContent>
|
|
117
|
-
\`\`\`
|
|
118
|
-
|
|
119
|
-
### Colored Variants
|
|
120
|
-
\`\`\`tsx
|
|
121
|
-
<SheetContent variant="positive">
|
|
122
|
-
{/* Success/positive themed sheet */}
|
|
123
|
-
</SheetContent>
|
|
124
|
-
|
|
125
|
-
<SheetContent variant="negative">
|
|
126
|
-
{/* Error/negative themed sheet */}
|
|
127
|
-
</SheetContent>
|
|
128
|
-
|
|
129
|
-
<SheetContent variant="warning">
|
|
130
|
-
{/* Warning themed sheet */}
|
|
131
|
-
</SheetContent>
|
|
132
|
-
|
|
133
|
-
<SheetContent variant="info">
|
|
134
|
-
{/* Info themed sheet */}
|
|
135
|
-
</SheetContent>
|
|
136
|
-
\`\`\`
|
|
137
|
-
|
|
138
|
-
### Custom Overlay
|
|
139
|
-
\`\`\`tsx
|
|
140
|
-
<SheetContent opacity="high" glass="medium" noise="low">
|
|
141
|
-
{/* High opacity overlay with glass effect and subtle noise */}
|
|
142
|
-
</SheetContent>
|
|
143
|
-
\`\`\`
|
|
144
|
-
`,
|
|
36
|
+
component:
|
|
37
|
+
"A slide-out panel built on Radix UI Dialog primitives. Supports four entry sides, five semantic variants with matching gradient border accents, and configurable glass/noise overlays. Ideal for navigation drawers, detail panels, filter sidebars, and contextual action sheets.",
|
|
145
38
|
},
|
|
39
|
+
page: () => (
|
|
40
|
+
<AuralComponentDocsPage
|
|
41
|
+
features={[
|
|
42
|
+
{
|
|
43
|
+
title: "4 Entry Sides",
|
|
44
|
+
description: "Top, bottom, left, right",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: "5 Variant Borders",
|
|
48
|
+
description: "Neutral to negative",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: "Glass & Noise",
|
|
52
|
+
description: "Overlay blur and grain",
|
|
53
|
+
},
|
|
54
|
+
]}
|
|
55
|
+
/>
|
|
56
|
+
),
|
|
146
57
|
},
|
|
147
58
|
},
|
|
148
59
|
tags: ["autodocs"],
|
|
@@ -151,900 +62,724 @@ A slide-out panel component built on Radix UI Dialog primitives that provides a
|
|
|
151
62
|
export default meta
|
|
152
63
|
type Story = StoryObj<typeof Sheet>
|
|
153
64
|
|
|
154
|
-
//
|
|
155
|
-
const BackgroundContent = () => (
|
|
156
|
-
<div className="min-h-screen bg-gradient-to-br from-blue-900 via-purple-900 to-pink-900 p-8">
|
|
157
|
-
<div className="mx-auto max-w-4xl space-y-8">
|
|
158
|
-
<header className="text-center">
|
|
159
|
-
<h1 className="mb-4 text-4xl font-bold text-white">
|
|
160
|
-
Main Content Area
|
|
161
|
-
</h1>
|
|
162
|
-
<p className="text-white/80">
|
|
163
|
-
This is the main content that sits behind the sheet overlay
|
|
164
|
-
</p>
|
|
165
|
-
</header>
|
|
65
|
+
// ─── Configurations ────────────────────────────────────────────────────────────
|
|
166
66
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
>
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
</h3>
|
|
176
|
-
<p className="mb-4 text-sm text-white/70">
|
|
177
|
-
Sample content that demonstrates the sheet overlay effect
|
|
178
|
-
</p>
|
|
179
|
-
<Button size="sm" variant="outline">
|
|
180
|
-
Action
|
|
67
|
+
export const Configurations: Story = {
|
|
68
|
+
render: () => {
|
|
69
|
+
const SideSheet = ({ side, variant, label, description }: any) => (
|
|
70
|
+
<div className="space-y-2 text-center">
|
|
71
|
+
<Sheet>
|
|
72
|
+
<SheetTrigger asChild>
|
|
73
|
+
<Button variant="outline" size="sm">
|
|
74
|
+
{label}
|
|
181
75
|
</Button>
|
|
182
|
-
</
|
|
183
|
-
|
|
76
|
+
</SheetTrigger>
|
|
77
|
+
<SheetContent side={side} variant={variant} container={null}>
|
|
78
|
+
<SheetHeader>
|
|
79
|
+
<SheetTitle>{label} Sheet</SheetTitle>
|
|
80
|
+
<SheetDescription>{description}</SheetDescription>
|
|
81
|
+
</SheetHeader>
|
|
82
|
+
<div className="py-4">
|
|
83
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
84
|
+
<code className="text-fm-secondary text-fm-sm leading-fm-sm font-(--font-fm-mono)">
|
|
85
|
+
side="{side}" variant="{variant}"
|
|
86
|
+
</code>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
<SheetFooter>
|
|
90
|
+
<SheetClose asChild>
|
|
91
|
+
<Button>Close</Button>
|
|
92
|
+
</SheetClose>
|
|
93
|
+
</SheetFooter>
|
|
94
|
+
</SheetContent>
|
|
95
|
+
</Sheet>
|
|
96
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
97
|
+
{label}
|
|
98
|
+
</p>
|
|
184
99
|
</div>
|
|
185
|
-
|
|
186
|
-
</div>
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
// 1. Sheet Sides and Variants
|
|
190
|
-
export const SidesAndVariants: Story = {
|
|
191
|
-
render: () => (
|
|
192
|
-
<div className="relative">
|
|
193
|
-
<BackgroundContent />
|
|
194
|
-
|
|
195
|
-
{/* Control Panel */}
|
|
196
|
-
<div className="fixed top-4 left-1/2 z-50 -translate-x-1/2 transform">
|
|
197
|
-
<div className="space-y-4 rounded-lg bg-black/80 p-6 backdrop-blur-sm">
|
|
198
|
-
<h3 className="text-center text-sm font-medium text-white">
|
|
199
|
-
Sheet Sides & Variants
|
|
200
|
-
</h3>
|
|
201
|
-
|
|
202
|
-
{/* Sides */}
|
|
203
|
-
<div className="space-y-2">
|
|
204
|
-
<h4 className="text-xs font-medium tracking-wide text-white/70 uppercase">
|
|
205
|
-
Sides
|
|
206
|
-
</h4>
|
|
207
|
-
<div className="grid grid-cols-2 gap-2">
|
|
208
|
-
{/* Left Sheet - Neutral */}
|
|
209
|
-
<Sheet>
|
|
210
|
-
<SheetTrigger asChild>
|
|
211
|
-
<Button size="sm" variant="outline">
|
|
212
|
-
Left
|
|
213
|
-
</Button>
|
|
214
|
-
</SheetTrigger>
|
|
215
|
-
<SheetContent side="left" variant="neutral">
|
|
216
|
-
<SheetHeader>
|
|
217
|
-
<SheetTitle>Left Side Sheet</SheetTitle>
|
|
218
|
-
<SheetDescription>
|
|
219
|
-
Slides in from the left with neutral styling
|
|
220
|
-
</SheetDescription>
|
|
221
|
-
</SheetHeader>
|
|
222
|
-
<div className="py-4">
|
|
223
|
-
<div className="space-y-4">
|
|
224
|
-
<div className="rounded-lg bg-white/5 p-4">
|
|
225
|
-
<h4 className="mb-2 font-medium text-white">
|
|
226
|
-
Navigation Menu
|
|
227
|
-
</h4>
|
|
228
|
-
<div className="space-y-2">
|
|
229
|
-
{["Dashboard", "Projects", "Team", "Settings"].map(
|
|
230
|
-
(item) => (
|
|
231
|
-
<div
|
|
232
|
-
key={item}
|
|
233
|
-
className="flex items-center gap-3 rounded p-2 hover:bg-white/10"
|
|
234
|
-
>
|
|
235
|
-
<SiteLogoIcon className="h-4 w-4 text-white/60" />
|
|
236
|
-
<span className="text-white">{item}</span>
|
|
237
|
-
</div>
|
|
238
|
-
)
|
|
239
|
-
)}
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
</div>
|
|
244
|
-
</SheetContent>
|
|
245
|
-
</Sheet>
|
|
100
|
+
)
|
|
246
101
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
102
|
+
const OverlaySheet = ({ label, opacity, glass, noise }: any) => (
|
|
103
|
+
<div className="space-y-2 text-center">
|
|
104
|
+
<Sheet>
|
|
105
|
+
<SheetTrigger asChild>
|
|
106
|
+
<Button variant="outline" size="sm">
|
|
107
|
+
{label}
|
|
108
|
+
</Button>
|
|
109
|
+
</SheetTrigger>
|
|
110
|
+
<SheetContent
|
|
111
|
+
side="right"
|
|
112
|
+
variant="neutral"
|
|
113
|
+
opacity={opacity}
|
|
114
|
+
glass={glass}
|
|
115
|
+
noise={noise}
|
|
116
|
+
container={null}
|
|
117
|
+
>
|
|
118
|
+
<SheetHeader>
|
|
119
|
+
<SheetTitle>{label}</SheetTitle>
|
|
120
|
+
<SheetDescription>Overlay configuration demo.</SheetDescription>
|
|
121
|
+
</SheetHeader>
|
|
122
|
+
<div className="py-4">
|
|
123
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
124
|
+
<code className="text-fm-secondary text-fm-sm leading-fm-sm font-(--font-fm-mono)">
|
|
125
|
+
{[
|
|
126
|
+
opacity && `opacity="${opacity}"`,
|
|
127
|
+
glass && `glass="${glass}"`,
|
|
128
|
+
noise && `noise="${noise}"`,
|
|
129
|
+
]
|
|
130
|
+
.filter(Boolean)
|
|
131
|
+
.join(" ")}
|
|
132
|
+
</code>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
<SheetFooter>
|
|
136
|
+
<SheetClose asChild>
|
|
137
|
+
<Button>Close</Button>
|
|
138
|
+
</SheetClose>
|
|
139
|
+
</SheetFooter>
|
|
140
|
+
</SheetContent>
|
|
141
|
+
</Sheet>
|
|
142
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
143
|
+
{label}
|
|
144
|
+
</p>
|
|
145
|
+
</div>
|
|
146
|
+
)
|
|
277
147
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
148
|
+
return (
|
|
149
|
+
<div className="space-y-8">
|
|
150
|
+
{/* All four sides */}
|
|
151
|
+
<div className="space-y-3">
|
|
152
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
153
|
+
All Four Sides
|
|
154
|
+
</h4>
|
|
155
|
+
<div className="flex flex-wrap gap-6">
|
|
156
|
+
<SideSheet
|
|
157
|
+
side="left"
|
|
158
|
+
variant="neutral"
|
|
159
|
+
label="Left"
|
|
160
|
+
description="Slides in from the left — navigation and filter panels."
|
|
161
|
+
/>
|
|
162
|
+
<SideSheet
|
|
163
|
+
side="right"
|
|
164
|
+
variant="neutral"
|
|
165
|
+
label="Right"
|
|
166
|
+
description="Slides in from the right — detail and settings panels."
|
|
167
|
+
/>
|
|
168
|
+
<SideSheet
|
|
169
|
+
side="top"
|
|
170
|
+
variant="neutral"
|
|
171
|
+
label="Top"
|
|
172
|
+
description="Slides down from the top — notifications and alerts."
|
|
173
|
+
/>
|
|
174
|
+
<SideSheet
|
|
175
|
+
side="bottom"
|
|
176
|
+
variant="neutral"
|
|
177
|
+
label="Bottom"
|
|
178
|
+
description="Slides up from the bottom — mobile-style action sheets."
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
307
182
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
183
|
+
{/* Variant types */}
|
|
184
|
+
<div className="space-y-3">
|
|
185
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
186
|
+
Semantic Variants
|
|
187
|
+
</h4>
|
|
188
|
+
<div className="flex flex-wrap gap-6">
|
|
189
|
+
<SideSheet
|
|
190
|
+
side="right"
|
|
191
|
+
variant="neutral"
|
|
192
|
+
label="Neutral"
|
|
193
|
+
description="Default neutral border accent."
|
|
194
|
+
/>
|
|
195
|
+
<SideSheet
|
|
196
|
+
side="right"
|
|
197
|
+
variant="positive"
|
|
198
|
+
label="Positive"
|
|
199
|
+
description="Green border accent for success states."
|
|
200
|
+
/>
|
|
201
|
+
<SideSheet
|
|
202
|
+
side="right"
|
|
203
|
+
variant="negative"
|
|
204
|
+
label="Negative"
|
|
205
|
+
description="Red border accent for error states."
|
|
206
|
+
/>
|
|
207
|
+
<SideSheet
|
|
208
|
+
side="right"
|
|
209
|
+
variant="warning"
|
|
210
|
+
label="Warning"
|
|
211
|
+
description="Yellow border accent for cautionary states."
|
|
212
|
+
/>
|
|
213
|
+
<SideSheet
|
|
214
|
+
side="right"
|
|
215
|
+
variant="info"
|
|
216
|
+
label="Info"
|
|
217
|
+
description="Blue border accent for informational states."
|
|
218
|
+
/>
|
|
338
219
|
</div>
|
|
220
|
+
</div>
|
|
339
221
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
</SheetTrigger>
|
|
351
|
-
<SheetContent side="right" variant="negative">
|
|
352
|
-
<SheetHeader>
|
|
353
|
-
<SheetTitle>Error Sheet</SheetTitle>
|
|
354
|
-
<SheetDescription>
|
|
355
|
-
Demonstrates the negative variant for error states
|
|
356
|
-
</SheetDescription>
|
|
357
|
-
</SheetHeader>
|
|
358
|
-
<div className="py-4">
|
|
359
|
-
<div className="rounded-lg border border-red-500/20 bg-red-500/10 p-4">
|
|
360
|
-
<div className="mb-2 flex items-center gap-2">
|
|
361
|
-
<AlertIcon className="h-5 w-5 text-red-400" />
|
|
362
|
-
<h4 className="font-medium text-white">Error Details</h4>
|
|
363
|
-
</div>
|
|
364
|
-
<p className="mb-3 text-sm text-white/80">
|
|
365
|
-
Something went wrong. Please check the details below.
|
|
366
|
-
</p>
|
|
367
|
-
<div className="space-y-2">
|
|
368
|
-
<div className="text-xs text-red-200">
|
|
369
|
-
• Network connection failed
|
|
370
|
-
</div>
|
|
371
|
-
<div className="text-xs text-red-200">
|
|
372
|
-
• Invalid response format
|
|
373
|
-
</div>
|
|
374
|
-
</div>
|
|
375
|
-
</div>
|
|
376
|
-
</div>
|
|
377
|
-
<SheetFooter>
|
|
378
|
-
<Button variant="outline" size="sm">
|
|
379
|
-
Retry
|
|
380
|
-
</Button>
|
|
381
|
-
<SheetClose asChild>
|
|
382
|
-
<Button size="sm">Close</Button>
|
|
383
|
-
</SheetClose>
|
|
384
|
-
</SheetFooter>
|
|
385
|
-
</SheetContent>
|
|
386
|
-
</Sheet>
|
|
222
|
+
{/* Overlay options */}
|
|
223
|
+
<div className="space-y-3">
|
|
224
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
225
|
+
Glass & Noise Overlay Options
|
|
226
|
+
</h4>
|
|
227
|
+
<div className="flex flex-wrap gap-6">
|
|
228
|
+
<OverlaySheet label="Low opacity" opacity="low" />
|
|
229
|
+
<OverlaySheet label="High opacity" opacity="high" />
|
|
230
|
+
<OverlaySheet label="High glass" glass="high" />
|
|
231
|
+
<OverlaySheet label="Noise texture" noise="medium" />
|
|
387
232
|
</div>
|
|
388
233
|
</div>
|
|
389
234
|
</div>
|
|
390
|
-
|
|
391
|
-
|
|
235
|
+
)
|
|
236
|
+
},
|
|
392
237
|
parameters: {
|
|
393
238
|
docs: {
|
|
394
239
|
description: {
|
|
395
240
|
story:
|
|
396
|
-
"
|
|
241
|
+
"Comparison of all four slide sides, all five semantic variants with gradient border accents, and overlay configuration options (opacity, glass, noise).",
|
|
397
242
|
},
|
|
398
243
|
},
|
|
399
244
|
},
|
|
400
245
|
}
|
|
401
246
|
|
|
402
|
-
//
|
|
403
|
-
export const NavigationSheet: Story = {
|
|
404
|
-
render: () => (
|
|
405
|
-
<div className="relative">
|
|
406
|
-
<BackgroundContent />
|
|
247
|
+
// ─── Interactive ───────────────────────────────────────────────────────────────
|
|
407
248
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
{
|
|
455
|
-
label: "Settings",
|
|
456
|
-
icon: MaintenanceIcon,
|
|
457
|
-
active: false,
|
|
458
|
-
badge: null,
|
|
459
|
-
},
|
|
460
|
-
].map((item) => (
|
|
461
|
-
<a
|
|
462
|
-
key={item.label}
|
|
463
|
-
href="#"
|
|
464
|
-
className={`flex items-center gap-3 rounded-lg p-3 transition-colors ${
|
|
465
|
-
item.active
|
|
466
|
-
? "bg-blue-500/20 text-blue-300"
|
|
467
|
-
: "text-white hover:bg-white/10"
|
|
468
|
-
}`}
|
|
469
|
-
>
|
|
470
|
-
<item.icon className="h-5 w-5" />
|
|
471
|
-
<span className="flex-1">{item.label}</span>
|
|
472
|
-
{item.badge && (
|
|
473
|
-
<Badge
|
|
474
|
-
color={item.badge === "New" ? "positive" : "neutral"}
|
|
475
|
-
size="sm"
|
|
476
|
-
>
|
|
477
|
-
{item.badge}
|
|
478
|
-
</Badge>
|
|
479
|
-
)}
|
|
480
|
-
<ChevronRightIcon className="h-4 w-4" />
|
|
481
|
-
</a>
|
|
482
|
-
))}
|
|
483
|
-
</nav>
|
|
249
|
+
export const Interactive: Story = {
|
|
250
|
+
render: () => {
|
|
251
|
+
const InteractiveDemo = () => {
|
|
252
|
+
const [side, setSide] = useState<"top" | "bottom" | "left" | "right">(
|
|
253
|
+
"right"
|
|
254
|
+
)
|
|
255
|
+
const [variant, setVariant] = useState<
|
|
256
|
+
"neutral" | "positive" | "negative" | "warning" | "info"
|
|
257
|
+
>("neutral")
|
|
258
|
+
const [opacity, setOpacity] = useState<
|
|
259
|
+
"high" | "medium" | "low" | "none"
|
|
260
|
+
>("medium")
|
|
261
|
+
const [glass, setGlass] = useState<"high" | "medium" | "low" | "none">(
|
|
262
|
+
"none"
|
|
263
|
+
)
|
|
264
|
+
const [noise, setNoise] = useState<"high" | "medium" | "low" | "none">(
|
|
265
|
+
"none"
|
|
266
|
+
)
|
|
267
|
+
const [lastAction, setLastAction] = useState<string | null>(null)
|
|
268
|
+
|
|
269
|
+
const sides = ["left", "right", "top", "bottom"] as const
|
|
270
|
+
const variants = [
|
|
271
|
+
"neutral",
|
|
272
|
+
"positive",
|
|
273
|
+
"negative",
|
|
274
|
+
"warning",
|
|
275
|
+
"info",
|
|
276
|
+
] as const
|
|
277
|
+
const levels = ["none", "low", "medium", "high"] as const
|
|
278
|
+
|
|
279
|
+
const btnCls = (active: boolean) =>
|
|
280
|
+
`font-fm-text text-fm-sm leading-fm-sm rounded px-2 py-1 outline-none transition-colors ${
|
|
281
|
+
active
|
|
282
|
+
? "bg-fm-surface-contrast text-fm-contrast"
|
|
283
|
+
: "bg-fm-surface-secondary text-fm-secondary hover:text-fm-primary"
|
|
284
|
+
}`
|
|
285
|
+
|
|
286
|
+
return (
|
|
287
|
+
<div className="w-full p-8">
|
|
288
|
+
<div className="mx-auto max-w-3xl space-y-6">
|
|
289
|
+
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
|
290
|
+
{/* Controls panel */}
|
|
291
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-5 rounded-xl border p-5">
|
|
292
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
293
|
+
Configuration
|
|
294
|
+
</p>
|
|
484
295
|
|
|
485
|
-
<div className="
|
|
486
|
-
<
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
<
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
className=
|
|
495
|
-
>
|
|
496
|
-
<SearchIcon className="mr-2 h-4 w-4" />
|
|
497
|
-
Search
|
|
498
|
-
</Button>
|
|
499
|
-
<Button
|
|
500
|
-
size="sm"
|
|
501
|
-
variant="outline"
|
|
502
|
-
className="w-full justify-start"
|
|
296
|
+
<div className="space-y-2">
|
|
297
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
298
|
+
Side
|
|
299
|
+
</p>
|
|
300
|
+
<div className="flex flex-wrap gap-1">
|
|
301
|
+
{sides.map((s) => (
|
|
302
|
+
<button
|
|
303
|
+
key={s}
|
|
304
|
+
onClick={() => setSide(s)}
|
|
305
|
+
className={btnCls(side === s)}
|
|
503
306
|
>
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
</div>
|
|
307
|
+
{s}
|
|
308
|
+
</button>
|
|
309
|
+
))}
|
|
508
310
|
</div>
|
|
509
311
|
</div>
|
|
510
|
-
</div>
|
|
511
312
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
313
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
314
|
+
|
|
315
|
+
<div className="space-y-2">
|
|
316
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
317
|
+
Variant
|
|
318
|
+
</p>
|
|
319
|
+
<div className="flex flex-wrap gap-1">
|
|
320
|
+
{variants.map((v) => (
|
|
321
|
+
<button
|
|
322
|
+
key={v}
|
|
323
|
+
onClick={() => setVariant(v)}
|
|
324
|
+
className={btnCls(variant === v)}
|
|
325
|
+
>
|
|
326
|
+
{v}
|
|
327
|
+
</button>
|
|
328
|
+
))}
|
|
520
329
|
</div>
|
|
521
|
-
<SheetClose asChild>
|
|
522
|
-
<Button variant="outline" className="w-full">
|
|
523
|
-
Close Menu
|
|
524
|
-
</Button>
|
|
525
|
-
</SheetClose>
|
|
526
330
|
</div>
|
|
527
|
-
</SheetFooter>
|
|
528
|
-
</SheetContent>
|
|
529
|
-
</Sheet>
|
|
530
|
-
|
|
531
|
-
<h1 className="text-lg font-semibold text-white">App Title</h1>
|
|
532
|
-
|
|
533
|
-
<IconButton
|
|
534
|
-
variant="ghost"
|
|
535
|
-
icon={<MaintenanceIcon />}
|
|
536
|
-
label="Settings"
|
|
537
|
-
/>
|
|
538
|
-
</div>
|
|
539
|
-
</div>
|
|
540
|
-
|
|
541
|
-
{/* Add padding top to account for fixed header */}
|
|
542
|
-
<div className="pt-16">
|
|
543
|
-
<BackgroundContent />
|
|
544
|
-
</div>
|
|
545
|
-
</div>
|
|
546
|
-
),
|
|
547
|
-
parameters: {
|
|
548
|
-
docs: {
|
|
549
|
-
description: {
|
|
550
|
-
story:
|
|
551
|
-
"Mobile-style navigation sheet with menu items, badges, user profile, and quick actions demonstrating common mobile app patterns.",
|
|
552
|
-
},
|
|
553
|
-
},
|
|
554
|
-
},
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// 3. Form Sheet
|
|
558
|
-
export const FormSheet: Story = {
|
|
559
|
-
render: () => {
|
|
560
|
-
const [formData, setFormData] = useState({
|
|
561
|
-
name: "",
|
|
562
|
-
email: "",
|
|
563
|
-
subject: "",
|
|
564
|
-
message: "",
|
|
565
|
-
newsletter: false,
|
|
566
|
-
})
|
|
567
|
-
|
|
568
|
-
return (
|
|
569
|
-
<div className="relative">
|
|
570
|
-
<BackgroundContent />
|
|
571
331
|
|
|
572
|
-
|
|
573
|
-
<Sheet>
|
|
574
|
-
<SheetTrigger asChild>
|
|
575
|
-
<Button className="rounded-full shadow-lg">
|
|
576
|
-
<SearchIcon className="mr-2 h-4 w-4" />
|
|
577
|
-
Contact Us
|
|
578
|
-
</Button>
|
|
579
|
-
</SheetTrigger>
|
|
580
|
-
<SheetContent side="right" className="w-96">
|
|
581
|
-
<SheetHeader>
|
|
582
|
-
<SheetTitle>Contact Form</SheetTitle>
|
|
583
|
-
<SheetDescription>
|
|
584
|
-
Send us a message and we'll get back to you soon.
|
|
585
|
-
</SheetDescription>
|
|
586
|
-
</SheetHeader>
|
|
332
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
587
333
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
/>
|
|
334
|
+
<div className="space-y-2">
|
|
335
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
336
|
+
Opacity
|
|
337
|
+
</p>
|
|
338
|
+
<div className="flex flex-wrap gap-1">
|
|
339
|
+
{levels.map((l) => (
|
|
340
|
+
<button
|
|
341
|
+
key={l}
|
|
342
|
+
onClick={() => setOpacity(l)}
|
|
343
|
+
className={btnCls(opacity === l)}
|
|
344
|
+
>
|
|
345
|
+
{l}
|
|
346
|
+
</button>
|
|
347
|
+
))}
|
|
603
348
|
</div>
|
|
349
|
+
</div>
|
|
604
350
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
|
|
351
|
+
<div className="space-y-2">
|
|
352
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
353
|
+
Glass
|
|
354
|
+
</p>
|
|
355
|
+
<div className="flex flex-wrap gap-1">
|
|
356
|
+
{levels.map((l) => (
|
|
357
|
+
<button
|
|
358
|
+
key={l}
|
|
359
|
+
onClick={() => setGlass(l)}
|
|
360
|
+
className={btnCls(glass === l)}
|
|
361
|
+
>
|
|
362
|
+
{l}
|
|
363
|
+
</button>
|
|
364
|
+
))}
|
|
619
365
|
</div>
|
|
366
|
+
</div>
|
|
620
367
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
368
|
+
<div className="space-y-2">
|
|
369
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
370
|
+
Noise
|
|
371
|
+
</p>
|
|
372
|
+
<div className="flex flex-wrap gap-1">
|
|
373
|
+
{levels.map((l) => (
|
|
374
|
+
<button
|
|
375
|
+
key={l}
|
|
376
|
+
onClick={() => setNoise(l)}
|
|
377
|
+
className={btnCls(noise === l)}
|
|
378
|
+
>
|
|
379
|
+
{l}
|
|
380
|
+
</button>
|
|
381
|
+
))}
|
|
634
382
|
</div>
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
635
385
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
386
|
+
{/* Preview stage */}
|
|
387
|
+
<div className="flex flex-col gap-3 lg:col-span-2">
|
|
388
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary flex min-h-48 flex-col items-center justify-center gap-4 rounded-xl border p-8">
|
|
389
|
+
{lastAction && (
|
|
390
|
+
<div
|
|
391
|
+
className={`rounded-lg border px-4 py-2 ${
|
|
392
|
+
lastAction === "confirmed"
|
|
393
|
+
? "border-fm-divider-positive bg-fm-surface-positive-sec"
|
|
394
|
+
: "border-fm-divider-secondary bg-fm-surface-secondary"
|
|
395
|
+
}`}
|
|
396
|
+
>
|
|
397
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
398
|
+
Last action:{" "}
|
|
399
|
+
<span className="text-fm-primary font-medium">
|
|
400
|
+
{lastAction}
|
|
401
|
+
</span>
|
|
402
|
+
</p>
|
|
403
|
+
</div>
|
|
404
|
+
)}
|
|
651
405
|
|
|
652
|
-
<
|
|
653
|
-
<
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
406
|
+
<Sheet>
|
|
407
|
+
<SheetTrigger asChild>
|
|
408
|
+
<Button onClick={() => setLastAction(null)}>
|
|
409
|
+
Open Sheet
|
|
410
|
+
</Button>
|
|
411
|
+
</SheetTrigger>
|
|
412
|
+
<SheetContent
|
|
413
|
+
side={side}
|
|
414
|
+
variant={variant}
|
|
415
|
+
opacity={opacity}
|
|
416
|
+
glass={glass}
|
|
417
|
+
noise={noise}
|
|
418
|
+
container={null}
|
|
419
|
+
>
|
|
420
|
+
<SheetHeader>
|
|
421
|
+
<SheetTitle>Sheet Preview</SheetTitle>
|
|
422
|
+
<SheetDescription>
|
|
423
|
+
Interact with content inside the sheet, then confirm
|
|
424
|
+
or cancel.
|
|
425
|
+
</SheetDescription>
|
|
426
|
+
</SheetHeader>
|
|
427
|
+
|
|
428
|
+
<div className="py-4">
|
|
429
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
430
|
+
<code className="text-fm-secondary text-fm-sm leading-fm-sm font-(--font-fm-mono)">
|
|
431
|
+
{`side="${side}" variant="${variant}" opacity="${opacity}" glass="${glass}" noise="${noise}"`}
|
|
432
|
+
</code>
|
|
433
|
+
</div>
|
|
434
|
+
</div>
|
|
667
435
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
436
|
+
<SheetFooter>
|
|
437
|
+
<Button
|
|
438
|
+
variant="outline"
|
|
439
|
+
onClick={() => setLastAction("cancelled")}
|
|
440
|
+
>
|
|
441
|
+
Cancel
|
|
442
|
+
</Button>
|
|
443
|
+
<SheetClose asChild>
|
|
444
|
+
<Button onClick={() => setLastAction("confirmed")}>
|
|
445
|
+
Confirm
|
|
446
|
+
</Button>
|
|
447
|
+
</SheetClose>
|
|
448
|
+
</SheetFooter>
|
|
449
|
+
</SheetContent>
|
|
450
|
+
</Sheet>
|
|
451
|
+
</div>
|
|
676
452
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
Cancel
|
|
682
|
-
</Button>
|
|
683
|
-
</SheetClose>
|
|
684
|
-
<Button
|
|
685
|
-
className="flex-1"
|
|
686
|
-
disabled={
|
|
687
|
-
!formData.name || !formData.email || !formData.message
|
|
688
|
-
}
|
|
689
|
-
>
|
|
690
|
-
Send Message
|
|
691
|
-
</Button>
|
|
453
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
454
|
+
<code className="text-fm-secondary text-fm-sm leading-fm-sm font-(--font-fm-mono)">
|
|
455
|
+
{`<SheetContent side="${side}" variant="${variant}" opacity="${opacity}" glass="${glass}" noise="${noise}" />`}
|
|
456
|
+
</code>
|
|
692
457
|
</div>
|
|
693
|
-
</
|
|
694
|
-
</
|
|
695
|
-
</
|
|
458
|
+
</div>
|
|
459
|
+
</div>
|
|
460
|
+
</div>
|
|
696
461
|
</div>
|
|
697
|
-
|
|
698
|
-
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return <InteractiveDemo />
|
|
699
466
|
},
|
|
700
467
|
parameters: {
|
|
701
468
|
docs: {
|
|
702
469
|
description: {
|
|
703
470
|
story:
|
|
704
|
-
"
|
|
471
|
+
"Live configurator — pick side, variant, opacity, glass, and noise, then open the sheet and confirm or cancel to see state feedback.",
|
|
705
472
|
},
|
|
706
473
|
},
|
|
707
474
|
},
|
|
708
475
|
}
|
|
709
476
|
|
|
710
|
-
//
|
|
711
|
-
export const SettingsPanelSheet: Story = {
|
|
712
|
-
render: () => {
|
|
713
|
-
const [settings, setSettings] = useState({
|
|
714
|
-
notifications: true,
|
|
715
|
-
darkMode: true,
|
|
716
|
-
analytics: false,
|
|
717
|
-
autoSave: true,
|
|
718
|
-
emailUpdates: false,
|
|
719
|
-
})
|
|
720
|
-
|
|
721
|
-
const toggleSetting = (key: string) => {
|
|
722
|
-
setSettings((prev) => ({
|
|
723
|
-
...prev,
|
|
724
|
-
[key]: !prev[key as keyof typeof prev],
|
|
725
|
-
}))
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
return (
|
|
729
|
-
<div className="relative">
|
|
730
|
-
<BackgroundContent />
|
|
731
|
-
|
|
732
|
-
<div className="fixed top-4 right-4 z-50">
|
|
733
|
-
<Sheet>
|
|
734
|
-
<SheetTrigger asChild>
|
|
735
|
-
<Button variant="outline">
|
|
736
|
-
<MaintenanceIcon className="mr-2 h-4 w-4" />
|
|
737
|
-
Settings
|
|
738
|
-
</Button>
|
|
739
|
-
</SheetTrigger>
|
|
740
|
-
<SheetContent side="right" className="w-80">
|
|
741
|
-
<SheetHeader>
|
|
742
|
-
<SheetTitle>Application Settings</SheetTitle>
|
|
743
|
-
<SheetDescription>
|
|
744
|
-
Customize your experience and preferences
|
|
745
|
-
</SheetDescription>
|
|
746
|
-
</SheetHeader>
|
|
747
|
-
|
|
748
|
-
<div className="py-4">
|
|
749
|
-
<div className="space-y-6">
|
|
750
|
-
{/* Notifications Section */}
|
|
751
|
-
<div className="space-y-3">
|
|
752
|
-
<h4 className="text-sm font-medium text-white">
|
|
753
|
-
Notifications
|
|
754
|
-
</h4>
|
|
755
|
-
<div className="space-y-3">
|
|
756
|
-
<div className="flex items-center justify-between">
|
|
757
|
-
<span className="text-sm text-white">
|
|
758
|
-
Push Notifications
|
|
759
|
-
</span>
|
|
760
|
-
<Checkbox
|
|
761
|
-
checked={settings.notifications}
|
|
762
|
-
onCheckedChange={() => toggleSetting("notifications")}
|
|
763
|
-
/>
|
|
764
|
-
</div>
|
|
765
|
-
|
|
766
|
-
<div className="flex items-center justify-between">
|
|
767
|
-
<span className="text-sm text-white">
|
|
768
|
-
Email Updates
|
|
769
|
-
</span>
|
|
770
|
-
<Checkbox
|
|
771
|
-
checked={settings.emailUpdates}
|
|
772
|
-
onCheckedChange={() => toggleSetting("emailUpdates")}
|
|
773
|
-
/>
|
|
774
|
-
</div>
|
|
775
|
-
|
|
776
|
-
<div className="flex items-center justify-between">
|
|
777
|
-
<span className="text-sm text-white">Analytics</span>
|
|
778
|
-
<Checkbox
|
|
779
|
-
checked={settings.analytics}
|
|
780
|
-
onCheckedChange={() => toggleSetting("analytics")}
|
|
781
|
-
/>
|
|
782
|
-
</div>
|
|
783
|
-
</div>
|
|
784
|
-
</div>
|
|
477
|
+
// ─── UseCases ─────────────────────────────────────────────────────────────────
|
|
785
478
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
479
|
+
export const UseCases: Story = {
|
|
480
|
+
render: () => {
|
|
481
|
+
// Left: Filter panel
|
|
482
|
+
const FilterPanel = () => {
|
|
483
|
+
const [genre, setGenre] = useState<string[]>([])
|
|
484
|
+
const [mood, setMood] = useState<string[]>([])
|
|
485
|
+
|
|
486
|
+
const toggleFilter = (
|
|
487
|
+
list: string[],
|
|
488
|
+
set: (v: string[]) => void,
|
|
489
|
+
item: string
|
|
490
|
+
) => {
|
|
491
|
+
set(
|
|
492
|
+
list.includes(item) ? list.filter((i) => i !== item) : [...list, item]
|
|
493
|
+
)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const genres = ["Lo-fi", "Jazz", "Electronic", "Acoustic", "Classical"]
|
|
497
|
+
const moods = ["Chill", "Focus", "Energetic", "Melancholic"]
|
|
498
|
+
|
|
499
|
+
return (
|
|
500
|
+
<Sheet>
|
|
501
|
+
<SheetTrigger asChild>
|
|
502
|
+
<Button variant="outline" size="sm">
|
|
503
|
+
Filter panel
|
|
504
|
+
</Button>
|
|
505
|
+
</SheetTrigger>
|
|
506
|
+
<SheetContent side="left" variant="neutral" container={null}>
|
|
507
|
+
<SheetHeader>
|
|
508
|
+
<SheetTitle>Filter Tracks</SheetTitle>
|
|
509
|
+
<SheetDescription>
|
|
510
|
+
Narrow your library by genre and mood.
|
|
511
|
+
</SheetDescription>
|
|
512
|
+
</SheetHeader>
|
|
513
|
+
|
|
514
|
+
<div className="space-y-6 py-4">
|
|
515
|
+
<div className="space-y-3">
|
|
516
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
517
|
+
Genre
|
|
518
|
+
</p>
|
|
519
|
+
<div className="space-y-2">
|
|
520
|
+
{genres.map((g) => (
|
|
521
|
+
<div key={g} className="flex items-center gap-3">
|
|
522
|
+
<Checkbox
|
|
523
|
+
id={`genre-${g}`}
|
|
524
|
+
checked={genre.includes(g)}
|
|
525
|
+
onCheckedChange={() => toggleFilter(genre, setGenre, g)}
|
|
526
|
+
/>
|
|
527
|
+
<Label
|
|
528
|
+
htmlFor={`genre-${g}`}
|
|
529
|
+
className="text-fm-primary font-fm-text text-fm-md leading-fm-md"
|
|
530
|
+
>
|
|
531
|
+
{g}
|
|
532
|
+
</Label>
|
|
799
533
|
</div>
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
<div className="space-y-3">
|
|
804
|
-
<h4 className="text-sm font-medium text-white">Advanced</h4>
|
|
805
|
-
<div className="space-y-3">
|
|
806
|
-
<div className="flex items-center justify-between">
|
|
807
|
-
<span className="text-sm text-white">Auto Save</span>
|
|
808
|
-
<Checkbox
|
|
809
|
-
checked={settings.autoSave}
|
|
810
|
-
onCheckedChange={() => toggleSetting("autoSave")}
|
|
811
|
-
/>
|
|
812
|
-
</div>
|
|
534
|
+
))}
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
813
537
|
|
|
814
|
-
|
|
815
|
-
<FileChartIcon className="mr-2 h-4 w-4" />
|
|
816
|
-
Clear Cache
|
|
817
|
-
</Button>
|
|
538
|
+
<div className="border-fm-divider-secondary border-t" />
|
|
818
539
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
540
|
+
<div className="space-y-3">
|
|
541
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
542
|
+
Mood
|
|
543
|
+
</p>
|
|
544
|
+
<div className="space-y-2">
|
|
545
|
+
{moods.map((m) => (
|
|
546
|
+
<div key={m} className="flex items-center gap-3">
|
|
547
|
+
<Checkbox
|
|
548
|
+
id={`mood-${m}`}
|
|
549
|
+
checked={mood.includes(m)}
|
|
550
|
+
onCheckedChange={() => toggleFilter(mood, setMood, m)}
|
|
551
|
+
/>
|
|
552
|
+
<Label
|
|
553
|
+
htmlFor={`mood-${m}`}
|
|
554
|
+
className="text-fm-primary font-fm-text text-fm-md leading-fm-md"
|
|
555
|
+
>
|
|
556
|
+
{m}
|
|
557
|
+
</Label>
|
|
823
558
|
</div>
|
|
824
|
-
|
|
559
|
+
))}
|
|
825
560
|
</div>
|
|
826
561
|
</div>
|
|
827
562
|
|
|
828
|
-
|
|
829
|
-
<div className="
|
|
830
|
-
<
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
</Button>
|
|
837
|
-
</SheetClose>
|
|
563
|
+
{(genre.length > 0 || mood.length > 0) && (
|
|
564
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-3">
|
|
565
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
566
|
+
Active filters:{" "}
|
|
567
|
+
<span className="text-fm-primary font-medium">
|
|
568
|
+
{[...genre, ...mood].join(", ")}
|
|
569
|
+
</span>
|
|
570
|
+
</p>
|
|
838
571
|
</div>
|
|
839
|
-
|
|
840
|
-
</
|
|
841
|
-
</Sheet>
|
|
842
|
-
</div>
|
|
843
|
-
</div>
|
|
844
|
-
)
|
|
845
|
-
},
|
|
846
|
-
parameters: {
|
|
847
|
-
docs: {
|
|
848
|
-
description: {
|
|
849
|
-
story:
|
|
850
|
-
"Settings panel sheet with checkboxes, sections, and action buttons demonstrating configuration interfaces.",
|
|
851
|
-
},
|
|
852
|
-
},
|
|
853
|
-
},
|
|
854
|
-
}
|
|
572
|
+
)}
|
|
573
|
+
</div>
|
|
855
574
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
575
|
+
<SheetFooter>
|
|
576
|
+
<Button
|
|
577
|
+
variant="outline"
|
|
578
|
+
onClick={() => {
|
|
579
|
+
setGenre([])
|
|
580
|
+
setMood([])
|
|
581
|
+
}}
|
|
582
|
+
>
|
|
583
|
+
Clear all
|
|
584
|
+
</Button>
|
|
585
|
+
<SheetClose asChild>
|
|
586
|
+
<Button>Apply filters</Button>
|
|
587
|
+
</SheetClose>
|
|
588
|
+
</SheetFooter>
|
|
589
|
+
</SheetContent>
|
|
590
|
+
</Sheet>
|
|
591
|
+
)
|
|
592
|
+
}
|
|
861
593
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
</h3>
|
|
867
|
-
<div className="flex gap-2">
|
|
868
|
-
{/* Low Opacity */}
|
|
869
|
-
<Sheet>
|
|
870
|
-
<SheetTrigger asChild>
|
|
871
|
-
<Button size="sm" variant="outline">
|
|
872
|
-
Low Opacity
|
|
873
|
-
</Button>
|
|
874
|
-
</SheetTrigger>
|
|
875
|
-
<SheetContent side="right" opacity="low">
|
|
876
|
-
<SheetHeader>
|
|
877
|
-
<SheetTitle>Low Opacity</SheetTitle>
|
|
878
|
-
<SheetDescription>
|
|
879
|
-
Subtle background overlay that maintains visibility
|
|
880
|
-
</SheetDescription>
|
|
881
|
-
</SheetHeader>
|
|
882
|
-
<div className="py-4">
|
|
883
|
-
<p className="text-sm text-white/80">
|
|
884
|
-
This sheet uses low opacity overlay, allowing more of the
|
|
885
|
-
background content to remain visible.
|
|
886
|
-
</p>
|
|
887
|
-
</div>
|
|
888
|
-
</SheetContent>
|
|
889
|
-
</Sheet>
|
|
594
|
+
// Right: Track details
|
|
595
|
+
const TrackDetails = () => {
|
|
596
|
+
const [liked, setLiked] = useState(false)
|
|
597
|
+
const [queued, setQueued] = useState(false)
|
|
890
598
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
599
|
+
return (
|
|
600
|
+
<Sheet>
|
|
601
|
+
<SheetTrigger asChild>
|
|
602
|
+
<Button variant="outline" size="sm">
|
|
603
|
+
Track details
|
|
604
|
+
</Button>
|
|
605
|
+
</SheetTrigger>
|
|
606
|
+
<SheetContent side="right" variant="info" container={null}>
|
|
607
|
+
<SheetHeader>
|
|
608
|
+
<SheetTitle>Midnight Drive</SheetTitle>
|
|
609
|
+
<SheetDescription>
|
|
610
|
+
Lo-fi Chill · Album: Late Nights · 3:42
|
|
611
|
+
</SheetDescription>
|
|
612
|
+
</SheetHeader>
|
|
613
|
+
|
|
614
|
+
<div className="space-y-4 py-4">
|
|
615
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
616
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm mb-3 font-semibold tracking-widest uppercase">
|
|
617
|
+
About this track
|
|
618
|
+
</p>
|
|
619
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-xl">
|
|
620
|
+
A smooth lo-fi track perfect for late-night focus sessions.
|
|
621
|
+
Released in 2024 as part of the Late Nights collection.
|
|
622
|
+
</p>
|
|
623
|
+
</div>
|
|
914
624
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
<
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
625
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-3 rounded-lg border p-4">
|
|
626
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
627
|
+
Track info
|
|
628
|
+
</p>
|
|
629
|
+
{[
|
|
630
|
+
{ label: "Artist", value: "Chill Collective" },
|
|
631
|
+
{ label: "BPM", value: "85" },
|
|
632
|
+
{ label: "Key", value: "F Minor" },
|
|
633
|
+
{ label: "Plays", value: "124,381" },
|
|
634
|
+
].map((row) => (
|
|
635
|
+
<div
|
|
636
|
+
key={row.label}
|
|
637
|
+
className="flex items-center justify-between"
|
|
638
|
+
>
|
|
639
|
+
<span className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
640
|
+
{row.label}
|
|
641
|
+
</span>
|
|
642
|
+
<span className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm font-medium">
|
|
643
|
+
{row.value}
|
|
644
|
+
</span>
|
|
645
|
+
</div>
|
|
646
|
+
))}
|
|
647
|
+
</div>
|
|
937
648
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
649
|
+
<div className="flex gap-2">
|
|
650
|
+
<Button
|
|
651
|
+
variant="outline"
|
|
652
|
+
size="sm"
|
|
653
|
+
className="flex-1 gap-2"
|
|
654
|
+
onClick={() => setLiked((v) => !v)}
|
|
655
|
+
>
|
|
656
|
+
<TickCircleIcon className="h-4 w-4" />
|
|
657
|
+
{liked ? "Liked" : "Like"}
|
|
943
658
|
</Button>
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
interest and depth to the background.
|
|
956
|
-
</p>
|
|
957
|
-
</div>
|
|
958
|
-
</SheetContent>
|
|
959
|
-
</Sheet>
|
|
960
|
-
</div>
|
|
961
|
-
</div>
|
|
962
|
-
</div>
|
|
963
|
-
</div>
|
|
964
|
-
),
|
|
965
|
-
parameters: {
|
|
966
|
-
docs: {
|
|
967
|
-
description: {
|
|
968
|
-
story:
|
|
969
|
-
"Different overlay configurations showing opacity levels, glass effects, and noise textures for various visual requirements.",
|
|
970
|
-
},
|
|
971
|
-
},
|
|
972
|
-
},
|
|
973
|
-
}
|
|
659
|
+
<Button
|
|
660
|
+
variant="outline"
|
|
661
|
+
size="sm"
|
|
662
|
+
className="flex-1 gap-2"
|
|
663
|
+
onClick={() => setQueued((v) => !v)}
|
|
664
|
+
>
|
|
665
|
+
<MusicalNoteIcon className="h-4 w-4" />
|
|
666
|
+
{queued ? "In queue" : "Add to queue"}
|
|
667
|
+
</Button>
|
|
668
|
+
</div>
|
|
669
|
+
</div>
|
|
974
670
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
671
|
+
<SheetFooter>
|
|
672
|
+
<SheetClose asChild>
|
|
673
|
+
<Button variant="outline">Close</Button>
|
|
674
|
+
</SheetClose>
|
|
675
|
+
<Button>Play now</Button>
|
|
676
|
+
</SheetFooter>
|
|
677
|
+
</SheetContent>
|
|
678
|
+
</Sheet>
|
|
679
|
+
)
|
|
680
|
+
}
|
|
979
681
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
682
|
+
// Bottom: Quick action sheet
|
|
683
|
+
const QuickActions = () => {
|
|
684
|
+
const [search, setSearch] = useState("")
|
|
685
|
+
const actions = [
|
|
686
|
+
{ label: "Add to playlist", icon: MusicalNoteIcon },
|
|
687
|
+
{ label: "Go to artist", icon: ChevronRightIcon },
|
|
688
|
+
{ label: "Find similar tracks", icon: SearchIcon },
|
|
689
|
+
{ label: "Report issue", icon: AlertIcon },
|
|
690
|
+
{ label: "Share", icon: SiteLogoIcon },
|
|
691
|
+
{ label: "Settings", icon: MaintenanceIcon },
|
|
692
|
+
]
|
|
693
|
+
const filtered = actions.filter((a) =>
|
|
694
|
+
a.label.toLowerCase().includes(search.toLowerCase())
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
return (
|
|
698
|
+
<Sheet>
|
|
699
|
+
<SheetTrigger asChild>
|
|
700
|
+
<Button variant="outline" size="sm">
|
|
701
|
+
Quick actions
|
|
702
|
+
</Button>
|
|
703
|
+
</SheetTrigger>
|
|
704
|
+
<SheetContent side="bottom" variant="neutral" container={null}>
|
|
705
|
+
<SheetHeader>
|
|
706
|
+
<SheetTitle>Quick Actions</SheetTitle>
|
|
707
|
+
<SheetDescription>
|
|
708
|
+
Search and pick an action for this track.
|
|
709
|
+
</SheetDescription>
|
|
710
|
+
</SheetHeader>
|
|
711
|
+
|
|
712
|
+
<div className="space-y-4 py-4">
|
|
713
|
+
<Input
|
|
714
|
+
placeholder="Search actions..."
|
|
715
|
+
value={search}
|
|
716
|
+
onChange={(e) => setSearch(e.target.value)}
|
|
717
|
+
/>
|
|
718
|
+
<div className="space-y-1">
|
|
719
|
+
{filtered.length === 0 && (
|
|
720
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm py-2 text-center">
|
|
721
|
+
No actions match your search.
|
|
722
|
+
</p>
|
|
723
|
+
)}
|
|
724
|
+
{filtered.map((action) => (
|
|
725
|
+
<button
|
|
726
|
+
key={action.label}
|
|
727
|
+
className="text-fm-primary hover:bg-fm-surface-secondary flex w-full items-center gap-3 rounded-lg px-3 py-3 text-left transition-colors"
|
|
728
|
+
>
|
|
729
|
+
<action.icon className="text-fm-secondary h-5 w-5 shrink-0" />
|
|
730
|
+
<span className="font-fm-text text-fm-md leading-fm-md">
|
|
731
|
+
{action.label}
|
|
732
|
+
</span>
|
|
733
|
+
</button>
|
|
734
|
+
))}
|
|
735
|
+
</div>
|
|
736
|
+
</div>
|
|
983
737
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
</SheetDescription>
|
|
996
|
-
</SheetHeader>
|
|
738
|
+
<SheetFooter>
|
|
739
|
+
<SheetClose asChild>
|
|
740
|
+
<Button variant="outline" className="w-full">
|
|
741
|
+
Dismiss
|
|
742
|
+
</Button>
|
|
743
|
+
</SheetClose>
|
|
744
|
+
</SheetFooter>
|
|
745
|
+
</SheetContent>
|
|
746
|
+
</Sheet>
|
|
747
|
+
)
|
|
748
|
+
}
|
|
997
749
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
selectedOption === option.name
|
|
1011
|
-
? "bg-blue-500/20 text-blue-300"
|
|
1012
|
-
: "text-white hover:bg-white/10"
|
|
1013
|
-
}`}
|
|
1014
|
-
>
|
|
1015
|
-
<option.icon className="h-6 w-6" />
|
|
1016
|
-
<span className="text-xs">{option.name}</span>
|
|
1017
|
-
</button>
|
|
1018
|
-
))}
|
|
1019
|
-
</div>
|
|
750
|
+
return (
|
|
751
|
+
<div className="mx-auto max-w-3xl space-y-8 p-8">
|
|
752
|
+
<div className="space-y-3">
|
|
753
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
754
|
+
Filter Panel — Left Side
|
|
755
|
+
</h4>
|
|
756
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-xl">
|
|
757
|
+
A left-side filter panel for narrowing a music library by genre and
|
|
758
|
+
mood. Selected filters are summarised and can be cleared.
|
|
759
|
+
</p>
|
|
760
|
+
<FilterPanel />
|
|
761
|
+
</div>
|
|
1020
762
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
<span className="text-sm text-white">
|
|
1032
|
-
Contact {i + 1}
|
|
1033
|
-
</span>
|
|
1034
|
-
</div>
|
|
1035
|
-
))}
|
|
1036
|
-
</div>
|
|
1037
|
-
</div>
|
|
763
|
+
<div className="space-y-3">
|
|
764
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
765
|
+
Track Details — Right Side
|
|
766
|
+
</h4>
|
|
767
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-xl">
|
|
768
|
+
A right-side detail panel showing metadata, stats, and contextual
|
|
769
|
+
actions for the currently selected track.
|
|
770
|
+
</p>
|
|
771
|
+
<TrackDetails />
|
|
772
|
+
</div>
|
|
1038
773
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
774
|
+
<div className="space-y-3">
|
|
775
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
776
|
+
Quick Action Sheet — Bottom
|
|
777
|
+
</h4>
|
|
778
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-xl">
|
|
779
|
+
A searchable bottom action sheet for quickly finding and triggering
|
|
780
|
+
contextual commands on a track.
|
|
781
|
+
</p>
|
|
782
|
+
<QuickActions />
|
|
1048
783
|
</div>
|
|
1049
784
|
</div>
|
|
1050
785
|
)
|
|
@@ -1053,7 +788,7 @@ export const MobileBottomSheet: Story = {
|
|
|
1053
788
|
docs: {
|
|
1054
789
|
description: {
|
|
1055
790
|
story:
|
|
1056
|
-
"
|
|
791
|
+
"Three realistic product scenarios: a left filter panel for library browsing, a right track-details panel, and a searchable bottom quick-action sheet.",
|
|
1057
792
|
},
|
|
1058
793
|
},
|
|
1059
794
|
},
|