aural-ui 4.0.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1228
- package/dist/components/avatar/Avatar.stories.tsx +219 -235
- package/dist/components/badge/Badge.stories.tsx +379 -116
- package/dist/components/banner/Banner.stories.tsx +445 -391
- package/dist/components/breadcrumb/Breadcrumb.stories.tsx +453 -199
- package/dist/components/button/Button.stories.tsx +585 -230
- package/dist/components/card/Card.stories.tsx +619 -301
- package/dist/components/char-count/CharCount.stories.tsx +350 -248
- package/dist/components/checkbox/Checkbox.stories.tsx +309 -167
- package/dist/components/chip/Chip.stories.tsx +362 -168
- package/dist/components/circular-loader/CircularLoader.stories.tsx +221 -636
- package/dist/components/clamp-lines/ClampLines.stories.tsx +246 -117
- package/dist/components/collapsible/Collapsible.stories.tsx +391 -252
- package/dist/components/command/Command.stories.tsx +530 -867
- package/dist/components/dialog/Dialog.stories.tsx +501 -950
- package/dist/components/divider/Divider.stories.tsx +264 -527
- package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
- package/dist/components/drawer/Drawer.stories.tsx +659 -1023
- package/dist/components/dropdown/Dropdown.stories.tsx +643 -1028
- package/dist/components/form/Form.stories.tsx +560 -274
- package/dist/components/helper-text/HelperText.stories.tsx +199 -200
- package/dist/components/hover-card/HoverCard.stories.tsx +318 -1254
- package/dist/components/icon-button/IconButton.stories.tsx +837 -194
- package/dist/components/if-else/if-else.stories.tsx +370 -83
- package/dist/components/input/Input.stories.tsx +436 -368
- package/dist/components/label/Label.stories.tsx +156 -154
- package/dist/components/list/List.stories.tsx +484 -835
- package/dist/components/marquee/Marquee.stories.tsx +356 -712
- package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -422
- package/dist/components/overlay/Overlay.stories.tsx +452 -824
- package/dist/components/pagination/Pagination.stories.tsx +721 -210
- package/dist/components/popover/Popover.stories.tsx +481 -896
- package/dist/components/radio/Radio.stories.tsx +432 -124
- package/dist/components/resizable/Resizable.stories.tsx +495 -799
- package/dist/components/scroll-area/ScrollArea.stories.tsx +383 -1059
- package/dist/components/search/Search.stories.tsx +312 -595
- package/dist/components/select/Select.stories.tsx +684 -789
- package/dist/components/sheet/Sheet.stories.tsx +671 -950
- package/dist/components/skelton/Skelton.stories.tsx +230 -764
- package/dist/components/slider/Slider.stories.tsx +383 -760
- package/dist/components/stepper/Stepper.stories.tsx +371 -514
- package/dist/components/switch/Switch.stories.tsx +461 -208
- package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
- package/dist/components/table/Table.stories.tsx +770 -916
- package/dist/components/tabs/Tabs.stories.tsx +458 -1455
- package/dist/components/tag/Tag.stories.tsx +714 -542
- package/dist/components/textarea/TextArea.stories.tsx +621 -562
- package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -154
- package/dist/components/toast/Toast.stories.tsx +452 -1339
- package/dist/components/toggle/Toggle.stories.tsx +488 -931
- package/dist/components/tooltip/Tooltip.stories.tsx +344 -1388
- package/dist/components/typography/Typography.stories.tsx +406 -89
- package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
- package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
- package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
- package/dist/icons/Icons.stories.tsx +0 -12
- package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +223 -1060
- package/dist/icons/alert-icon/AlertIcon.stories.tsx +106 -968
- package/dist/icons/all-icons.tsx +37 -16
- package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +137 -1010
- package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +145 -935
- package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +132 -1046
- package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +134 -986
- package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +135 -1028
- package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +133 -971
- package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +145 -1123
- package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +143 -1252
- package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +123 -632
- package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +141 -1223
- package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +164 -1018
- package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +121 -1236
- package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +121 -1213
- package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +116 -893
- package/dist/icons/camera-icon/CameraIcon.stories.tsx +109 -1254
- package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +114 -975
- package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +157 -994
- package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +160 -992
- package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +140 -970
- package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +126 -993
- package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +144 -987
- package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +141 -1007
- package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +147 -1187
- package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +110 -476
- package/dist/icons/coin-icon/CoinIcon.stories.tsx +120 -1364
- package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +113 -1360
- package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +111 -942
- package/dist/icons/command-icon/CommandIcon.stories.tsx +124 -1087
- package/dist/icons/copy-icon/CopyIcon.stories.tsx +119 -996
- package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +144 -1046
- package/dist/icons/cross-icon/CrossIcon.stories.tsx +136 -999
- package/dist/icons/download-icon/DownloadIcon.stories.tsx +123 -857
- package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +121 -1080
- package/dist/icons/email-icon/EmailIcon.stories.tsx +112 -979
- package/dist/icons/expand-icon/ExpandIcon.stories.tsx +109 -1146
- package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +141 -1068
- package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +140 -1081
- package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +124 -1050
- package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +123 -1091
- package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +122 -633
- package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +116 -1087
- package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +166 -1020
- package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +112 -1182
- package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +112 -1155
- package/dist/icons/globe-icon/GlobeIcon.stories.tsx +127 -325
- package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +142 -985
- package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +116 -1217
- package/dist/icons/head-icon/HeadIcon.stories.tsx +108 -953
- package/dist/icons/heart-icon/HeartIcon.stories.tsx +117 -1060
- package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +116 -716
- package/dist/icons/image-icon/ImageIcon.stories.tsx +102 -1164
- package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +108 -1233
- package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +133 -1289
- package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +155 -1012
- package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +158 -1438
- package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +121 -1011
- package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +116 -981
- package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +116 -979
- package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +105 -1252
- package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +151 -1554
- package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +107 -1227
- package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +116 -707
- package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +119 -1226
- package/dist/icons/message-icon/MessageIcon.stories.tsx +111 -557
- package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +112 -1198
- package/dist/icons/moon-icon/MoonIcon.stories.tsx +117 -557
- package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +106 -1235
- package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +112 -1185
- package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +116 -1012
- package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +108 -1137
- package/dist/icons/notes-icon/NotesIcon.stories.tsx +116 -1138
- package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +106 -1146
- package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +119 -719
- package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +110 -999
- package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +109 -912
- package/dist/icons/pause-icon/PauseIcon.stories.tsx +110 -1041
- package/dist/icons/pencil-icon/PencilIcon.stories.tsx +112 -1109
- package/dist/icons/phone-icon/PhoneIcon.stories.tsx +112 -1023
- package/dist/icons/plus-icon/PlusIcon.stories.tsx +103 -1132
- package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +104 -870
- package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +99 -476
- package/dist/icons/search-icon/SearchIcon.stories.tsx +108 -1161
- package/dist/icons/setting-icon/SettingIcon.stories.tsx +104 -1009
- package/dist/icons/share-icon/ShareIcon.stories.tsx +117 -1064
- package/dist/icons/shield-icon/ShieldIcon.stories.tsx +114 -974
- package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +134 -1160
- package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +169 -1017
- package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +161 -1016
- package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +102 -1001
- package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +155 -593
- package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +155 -608
- package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +142 -712
- package/dist/icons/star-icon/StarIcon.stories.tsx +120 -946
- package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +109 -1013
- package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +113 -891
- package/dist/icons/sun-icon/SunIcon.stories.tsx +117 -864
- package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +113 -989
- package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +120 -1027
- package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +153 -1476
- package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +143 -1187
- package/dist/icons/tick-icon/TickIcon.stories.tsx +142 -1322
- package/dist/icons/trash-icon/TrashIcon.stories.tsx +105 -970
- package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +154 -1457
- package/dist/icons/upload-icon/UploadIcon.stories.tsx +112 -930
- package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +115 -1019
- package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +122 -1092
- package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +120 -1401
- package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +107 -1212
- package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +109 -1122
- package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +112 -1124
- package/dist/icons/warning-icon/WarningIcon.stories.tsx +119 -1083
- package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +158 -983
- package/dist/index.cjs +90 -90
- package/dist/index.js +90 -90
- package/package.json +8 -3
|
@@ -1,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,914 +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-fm-primary text-center text-sm font-medium">
|
|
199
|
-
Sheet Sides & Variants
|
|
200
|
-
</h3>
|
|
201
|
-
|
|
202
|
-
{/* Sides */}
|
|
203
|
-
<div className="space-y-2">
|
|
204
|
-
<h4 className="text-fm-secondary text-xs font-medium tracking-wide 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="bg-fm-surface-secondary rounded-lg p-4">
|
|
225
|
-
<h4 className="text-fm-primary mb-2 font-medium">
|
|
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="hover:bg-fm-surface-tertiary flex items-center gap-3 rounded p-2"
|
|
234
|
-
>
|
|
235
|
-
<SiteLogoIcon className="text-fm-secondary h-4 w-4" />
|
|
236
|
-
<span className="text-fm-primary">{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="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
360
|
-
<div className="mb-2 flex items-center gap-2">
|
|
361
|
-
<AlertIcon className="text-fm-icon-negative h-5 w-5" />
|
|
362
|
-
<h4 className="text-fm-primary font-medium">
|
|
363
|
-
Error Details
|
|
364
|
-
</h4>
|
|
365
|
-
</div>
|
|
366
|
-
<p className="text-fm-secondary mb-3 text-sm">
|
|
367
|
-
Something went wrong. Please check the details below.
|
|
368
|
-
</p>
|
|
369
|
-
<div className="space-y-2">
|
|
370
|
-
<div className="text-fm-secondary text-xs">
|
|
371
|
-
• Network connection failed
|
|
372
|
-
</div>
|
|
373
|
-
<div className="text-fm-secondary text-xs">
|
|
374
|
-
• Invalid response format
|
|
375
|
-
</div>
|
|
376
|
-
</div>
|
|
377
|
-
</div>
|
|
378
|
-
</div>
|
|
379
|
-
<SheetFooter>
|
|
380
|
-
<Button variant="outline" size="sm">
|
|
381
|
-
Retry
|
|
382
|
-
</Button>
|
|
383
|
-
<SheetClose asChild>
|
|
384
|
-
<Button size="sm">Close</Button>
|
|
385
|
-
</SheetClose>
|
|
386
|
-
</SheetFooter>
|
|
387
|
-
</SheetContent>
|
|
388
|
-
</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" />
|
|
389
232
|
</div>
|
|
390
233
|
</div>
|
|
391
234
|
</div>
|
|
392
|
-
|
|
393
|
-
|
|
235
|
+
)
|
|
236
|
+
},
|
|
394
237
|
parameters: {
|
|
395
238
|
docs: {
|
|
396
239
|
description: {
|
|
397
240
|
story:
|
|
398
|
-
"
|
|
241
|
+
"Comparison of all four slide sides, all five semantic variants with gradient border accents, and overlay configuration options (opacity, glass, noise).",
|
|
399
242
|
},
|
|
400
243
|
},
|
|
401
244
|
},
|
|
402
245
|
}
|
|
403
246
|
|
|
404
|
-
//
|
|
405
|
-
export const NavigationSheet: Story = {
|
|
406
|
-
render: () => (
|
|
407
|
-
<div className="relative">
|
|
408
|
-
<BackgroundContent />
|
|
409
|
-
|
|
410
|
-
{/* Mobile-style header */}
|
|
411
|
-
<div className="fixed top-0 right-0 left-0 z-40 bg-black/80 backdrop-blur-sm">
|
|
412
|
-
<div className="flex items-center justify-between p-4">
|
|
413
|
-
<Sheet>
|
|
414
|
-
<SheetTrigger asChild>
|
|
415
|
-
<IconButton
|
|
416
|
-
variant="ghost"
|
|
417
|
-
icon={<SiteLogoIcon />}
|
|
418
|
-
label="Menu"
|
|
419
|
-
/>
|
|
420
|
-
</SheetTrigger>
|
|
421
|
-
<SheetContent side="left" className="w-80">
|
|
422
|
-
<SheetHeader>
|
|
423
|
-
<SheetTitle>Navigation Menu</SheetTitle>
|
|
424
|
-
<SheetDescription>
|
|
425
|
-
Main navigation for the application
|
|
426
|
-
</SheetDescription>
|
|
427
|
-
</SheetHeader>
|
|
247
|
+
// ─── Interactive ───────────────────────────────────────────────────────────────
|
|
428
248
|
|
|
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
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
<Badge
|
|
476
|
-
color={item.badge === "New" ? "positive" : "neutral"}
|
|
477
|
-
size="sm"
|
|
478
|
-
>
|
|
479
|
-
{item.badge}
|
|
480
|
-
</Badge>
|
|
481
|
-
)}
|
|
482
|
-
<ChevronRightIcon className="h-4 w-4" />
|
|
483
|
-
</a>
|
|
484
|
-
))}
|
|
485
|
-
</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>
|
|
486
295
|
|
|
487
|
-
<div className="
|
|
488
|
-
<
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
<
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
className=
|
|
497
|
-
>
|
|
498
|
-
<SearchIcon className="mr-2 h-4 w-4" />
|
|
499
|
-
Search
|
|
500
|
-
</Button>
|
|
501
|
-
<Button
|
|
502
|
-
size="sm"
|
|
503
|
-
variant="outline"
|
|
504
|
-
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)}
|
|
505
306
|
>
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
</div>
|
|
307
|
+
{s}
|
|
308
|
+
</button>
|
|
309
|
+
))}
|
|
510
310
|
</div>
|
|
511
311
|
</div>
|
|
512
|
-
</div>
|
|
513
312
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
<
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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
|
+
))}
|
|
526
329
|
</div>
|
|
527
|
-
<SheetClose asChild>
|
|
528
|
-
<Button variant="outline" className="w-full">
|
|
529
|
-
Close Menu
|
|
530
|
-
</Button>
|
|
531
|
-
</SheetClose>
|
|
532
330
|
</div>
|
|
533
|
-
</SheetFooter>
|
|
534
|
-
</SheetContent>
|
|
535
|
-
</Sheet>
|
|
536
|
-
|
|
537
|
-
<h1 className="text-fm-primary text-lg font-semibold">App Title</h1>
|
|
538
331
|
|
|
539
|
-
|
|
540
|
-
variant="ghost"
|
|
541
|
-
icon={<MaintenanceIcon />}
|
|
542
|
-
label="Settings"
|
|
543
|
-
/>
|
|
544
|
-
</div>
|
|
545
|
-
</div>
|
|
332
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
546
333
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// 3. Form Sheet
|
|
564
|
-
export const FormSheet: Story = {
|
|
565
|
-
render: () => {
|
|
566
|
-
const [formData, setFormData] = useState({
|
|
567
|
-
name: "",
|
|
568
|
-
email: "",
|
|
569
|
-
subject: "",
|
|
570
|
-
message: "",
|
|
571
|
-
newsletter: false,
|
|
572
|
-
})
|
|
573
|
-
|
|
574
|
-
return (
|
|
575
|
-
<div className="relative">
|
|
576
|
-
<BackgroundContent />
|
|
577
|
-
|
|
578
|
-
<div className="fixed right-4 bottom-4 z-50">
|
|
579
|
-
<Sheet>
|
|
580
|
-
<SheetTrigger asChild>
|
|
581
|
-
<Button className="rounded-full shadow-lg">
|
|
582
|
-
<SearchIcon className="mr-2 h-4 w-4" />
|
|
583
|
-
Contact Us
|
|
584
|
-
</Button>
|
|
585
|
-
</SheetTrigger>
|
|
586
|
-
<SheetContent side="right" className="w-96">
|
|
587
|
-
<SheetHeader>
|
|
588
|
-
<SheetTitle>Contact Form</SheetTitle>
|
|
589
|
-
<SheetDescription>
|
|
590
|
-
Send us a message and we'll get back to you soon.
|
|
591
|
-
</SheetDescription>
|
|
592
|
-
</SheetHeader>
|
|
593
|
-
|
|
594
|
-
<div className="py-4">
|
|
595
|
-
<form className="space-y-4">
|
|
596
|
-
<div className="space-y-2">
|
|
597
|
-
<Label htmlFor="name">Name</Label>
|
|
598
|
-
<Input
|
|
599
|
-
id="name"
|
|
600
|
-
placeholder="Your full name"
|
|
601
|
-
value={formData.name}
|
|
602
|
-
onChange={(e: any) =>
|
|
603
|
-
setFormData((prev) => ({
|
|
604
|
-
...prev,
|
|
605
|
-
name: e.target.value,
|
|
606
|
-
}))
|
|
607
|
-
}
|
|
608
|
-
/>
|
|
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
|
+
))}
|
|
609
348
|
</div>
|
|
349
|
+
</div>
|
|
610
350
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
|
|
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
|
+
))}
|
|
625
365
|
</div>
|
|
366
|
+
</div>
|
|
626
367
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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
|
+
))}
|
|
640
382
|
</div>
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
641
385
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
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
|
+
)}
|
|
657
405
|
|
|
658
|
-
<
|
|
659
|
-
<
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
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>
|
|
673
435
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
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>
|
|
682
452
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
Cancel
|
|
688
|
-
</Button>
|
|
689
|
-
</SheetClose>
|
|
690
|
-
<Button
|
|
691
|
-
className="flex-1"
|
|
692
|
-
disabled={
|
|
693
|
-
!formData.name || !formData.email || !formData.message
|
|
694
|
-
}
|
|
695
|
-
>
|
|
696
|
-
Send Message
|
|
697
|
-
</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>
|
|
698
457
|
</div>
|
|
699
|
-
</
|
|
700
|
-
</
|
|
701
|
-
</
|
|
458
|
+
</div>
|
|
459
|
+
</div>
|
|
460
|
+
</div>
|
|
702
461
|
</div>
|
|
703
|
-
|
|
704
|
-
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return <InteractiveDemo />
|
|
705
466
|
},
|
|
706
467
|
parameters: {
|
|
707
468
|
docs: {
|
|
708
469
|
description: {
|
|
709
470
|
story:
|
|
710
|
-
"
|
|
471
|
+
"Live configurator — pick side, variant, opacity, glass, and noise, then open the sheet and confirm or cancel to see state feedback.",
|
|
711
472
|
},
|
|
712
473
|
},
|
|
713
474
|
},
|
|
714
475
|
}
|
|
715
476
|
|
|
716
|
-
//
|
|
717
|
-
export const SettingsPanelSheet: Story = {
|
|
718
|
-
render: () => {
|
|
719
|
-
const [settings, setSettings] = useState({
|
|
720
|
-
notifications: true,
|
|
721
|
-
darkMode: true,
|
|
722
|
-
analytics: false,
|
|
723
|
-
autoSave: true,
|
|
724
|
-
emailUpdates: false,
|
|
725
|
-
})
|
|
726
|
-
|
|
727
|
-
const toggleSetting = (key: string) => {
|
|
728
|
-
setSettings((prev) => ({
|
|
729
|
-
...prev,
|
|
730
|
-
[key]: !prev[key as keyof typeof prev],
|
|
731
|
-
}))
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
return (
|
|
735
|
-
<div className="relative">
|
|
736
|
-
<BackgroundContent />
|
|
737
|
-
|
|
738
|
-
<div className="fixed top-4 right-4 z-50">
|
|
739
|
-
<Sheet>
|
|
740
|
-
<SheetTrigger asChild>
|
|
741
|
-
<Button variant="outline">
|
|
742
|
-
<MaintenanceIcon className="mr-2 h-4 w-4" />
|
|
743
|
-
Settings
|
|
744
|
-
</Button>
|
|
745
|
-
</SheetTrigger>
|
|
746
|
-
<SheetContent side="right" className="w-80">
|
|
747
|
-
<SheetHeader>
|
|
748
|
-
<SheetTitle>Application Settings</SheetTitle>
|
|
749
|
-
<SheetDescription>
|
|
750
|
-
Customize your experience and preferences
|
|
751
|
-
</SheetDescription>
|
|
752
|
-
</SheetHeader>
|
|
753
|
-
|
|
754
|
-
<div className="py-4">
|
|
755
|
-
<div className="space-y-6">
|
|
756
|
-
{/* Notifications Section */}
|
|
757
|
-
<div className="space-y-3">
|
|
758
|
-
<h4 className="text-fm-primary text-sm font-medium">
|
|
759
|
-
Notifications
|
|
760
|
-
</h4>
|
|
761
|
-
<div className="space-y-3">
|
|
762
|
-
<div className="flex items-center justify-between">
|
|
763
|
-
<span className="text-fm-primary text-sm">
|
|
764
|
-
Push Notifications
|
|
765
|
-
</span>
|
|
766
|
-
<Checkbox
|
|
767
|
-
checked={settings.notifications}
|
|
768
|
-
onCheckedChange={() => toggleSetting("notifications")}
|
|
769
|
-
/>
|
|
770
|
-
</div>
|
|
771
|
-
|
|
772
|
-
<div className="flex items-center justify-between">
|
|
773
|
-
<span className="text-fm-primary text-sm">
|
|
774
|
-
Email Updates
|
|
775
|
-
</span>
|
|
776
|
-
<Checkbox
|
|
777
|
-
checked={settings.emailUpdates}
|
|
778
|
-
onCheckedChange={() => toggleSetting("emailUpdates")}
|
|
779
|
-
/>
|
|
780
|
-
</div>
|
|
781
|
-
|
|
782
|
-
<div className="flex items-center justify-between">
|
|
783
|
-
<span className="text-fm-primary text-sm">
|
|
784
|
-
Analytics
|
|
785
|
-
</span>
|
|
786
|
-
<Checkbox
|
|
787
|
-
checked={settings.analytics}
|
|
788
|
-
onCheckedChange={() => toggleSetting("analytics")}
|
|
789
|
-
/>
|
|
790
|
-
</div>
|
|
791
|
-
</div>
|
|
792
|
-
</div>
|
|
477
|
+
// ─── UseCases ─────────────────────────────────────────────────────────────────
|
|
793
478
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
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>
|
|
809
533
|
</div>
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
<div className="space-y-3">
|
|
814
|
-
<h4 className="text-fm-primary text-sm font-medium">
|
|
815
|
-
Advanced
|
|
816
|
-
</h4>
|
|
817
|
-
<div className="space-y-3">
|
|
818
|
-
<div className="flex items-center justify-between">
|
|
819
|
-
<span className="text-fm-primary text-sm">
|
|
820
|
-
Auto Save
|
|
821
|
-
</span>
|
|
822
|
-
<Checkbox
|
|
823
|
-
checked={settings.autoSave}
|
|
824
|
-
onCheckedChange={() => toggleSetting("autoSave")}
|
|
825
|
-
/>
|
|
826
|
-
</div>
|
|
534
|
+
))}
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
827
537
|
|
|
828
|
-
|
|
829
|
-
<FileChartIcon className="mr-2 h-4 w-4" />
|
|
830
|
-
Clear Cache
|
|
831
|
-
</Button>
|
|
538
|
+
<div className="border-fm-divider-secondary border-t" />
|
|
832
539
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
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>
|
|
837
558
|
</div>
|
|
838
|
-
|
|
559
|
+
))}
|
|
839
560
|
</div>
|
|
840
561
|
</div>
|
|
841
562
|
|
|
842
|
-
|
|
843
|
-
<div className="
|
|
844
|
-
<
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
</Button>
|
|
851
|
-
</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>
|
|
852
571
|
</div>
|
|
853
|
-
|
|
854
|
-
</
|
|
855
|
-
</Sheet>
|
|
856
|
-
</div>
|
|
857
|
-
</div>
|
|
858
|
-
)
|
|
859
|
-
},
|
|
860
|
-
parameters: {
|
|
861
|
-
docs: {
|
|
862
|
-
description: {
|
|
863
|
-
story:
|
|
864
|
-
"Settings panel sheet with checkboxes, sections, and action buttons demonstrating configuration interfaces.",
|
|
865
|
-
},
|
|
866
|
-
},
|
|
867
|
-
},
|
|
868
|
-
}
|
|
572
|
+
)}
|
|
573
|
+
</div>
|
|
869
574
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
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
|
+
}
|
|
875
593
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
</h3>
|
|
881
|
-
<div className="flex gap-2">
|
|
882
|
-
{/* Low Opacity */}
|
|
883
|
-
<Sheet>
|
|
884
|
-
<SheetTrigger asChild>
|
|
885
|
-
<Button size="sm" variant="outline">
|
|
886
|
-
Low Opacity
|
|
887
|
-
</Button>
|
|
888
|
-
</SheetTrigger>
|
|
889
|
-
<SheetContent side="right" opacity="low">
|
|
890
|
-
<SheetHeader>
|
|
891
|
-
<SheetTitle>Low Opacity</SheetTitle>
|
|
892
|
-
<SheetDescription>
|
|
893
|
-
Subtle background overlay that maintains visibility
|
|
894
|
-
</SheetDescription>
|
|
895
|
-
</SheetHeader>
|
|
896
|
-
<div className="py-4">
|
|
897
|
-
<p className="text-fm-secondary text-sm">
|
|
898
|
-
This sheet uses low opacity overlay, allowing more of the
|
|
899
|
-
background content to remain visible.
|
|
900
|
-
</p>
|
|
901
|
-
</div>
|
|
902
|
-
</SheetContent>
|
|
903
|
-
</Sheet>
|
|
594
|
+
// Right: Track details
|
|
595
|
+
const TrackDetails = () => {
|
|
596
|
+
const [liked, setLiked] = useState(false)
|
|
597
|
+
const [queued, setQueued] = useState(false)
|
|
904
598
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
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>
|
|
928
624
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
<
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
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>
|
|
951
648
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
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"}
|
|
957
658
|
</Button>
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
interest and depth to the background.
|
|
970
|
-
</p>
|
|
971
|
-
</div>
|
|
972
|
-
</SheetContent>
|
|
973
|
-
</Sheet>
|
|
974
|
-
</div>
|
|
975
|
-
</div>
|
|
976
|
-
</div>
|
|
977
|
-
</div>
|
|
978
|
-
),
|
|
979
|
-
parameters: {
|
|
980
|
-
docs: {
|
|
981
|
-
description: {
|
|
982
|
-
story:
|
|
983
|
-
"Different overlay configurations showing opacity levels, glass effects, and noise textures for various visual requirements.",
|
|
984
|
-
},
|
|
985
|
-
},
|
|
986
|
-
},
|
|
987
|
-
}
|
|
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>
|
|
988
670
|
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
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
|
+
}
|
|
993
681
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
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>
|
|
997
737
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
</SheetDescription>
|
|
1010
|
-
</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
|
+
}
|
|
1011
749
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
selectedOption === option.name
|
|
1025
|
-
? "bg-fm-surface-info-sec text-fm-info"
|
|
1026
|
-
: "text-fm-primary hover:bg-fm-surface-secondary"
|
|
1027
|
-
}`}
|
|
1028
|
-
>
|
|
1029
|
-
<option.icon className="h-6 w-6" />
|
|
1030
|
-
<span className="text-xs">{option.name}</span>
|
|
1031
|
-
</button>
|
|
1032
|
-
))}
|
|
1033
|
-
</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>
|
|
1034
762
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
<span className="text-fm-primary text-sm">
|
|
1046
|
-
Contact {i + 1}
|
|
1047
|
-
</span>
|
|
1048
|
-
</div>
|
|
1049
|
-
))}
|
|
1050
|
-
</div>
|
|
1051
|
-
</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>
|
|
1052
773
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
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 />
|
|
1062
783
|
</div>
|
|
1063
784
|
</div>
|
|
1064
785
|
)
|
|
@@ -1067,7 +788,7 @@ export const MobileBottomSheet: Story = {
|
|
|
1067
788
|
docs: {
|
|
1068
789
|
description: {
|
|
1069
790
|
story:
|
|
1070
|
-
"
|
|
791
|
+
"Three realistic product scenarios: a left filter panel for library browsing, a right track-details panel, and a searchable bottom quick-action sheet.",
|
|
1071
792
|
},
|
|
1072
793
|
},
|
|
1073
794
|
},
|