@umbra.ui/core 0.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/controls/Dropdown/types.d.ts +5 -0
- package/dist/components/controls/Dropdown/types.d.ts.map +1 -0
- package/dist/components/controls/Dropdown/types.js +1 -0
- package/dist/components/controls/SegmentedControl/types.d.ts +6 -0
- package/dist/components/controls/SegmentedControl/types.d.ts.map +1 -0
- package/dist/components/controls/SegmentedControl/types.js +1 -0
- package/dist/components/dialogs/Alert/types.d.ts +7 -0
- package/dist/components/dialogs/Alert/types.d.ts.map +1 -0
- package/dist/components/dialogs/Alert/types.js +1 -0
- package/dist/components/dialogs/Toast/types.d.ts +34 -0
- package/dist/components/dialogs/Toast/types.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/types.js +10 -0
- package/dist/components/dialogs/Toast/useToast.d.ts +36 -0
- package/dist/components/dialogs/Toast/useToast.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/useToast.js +90 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts +3 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/tooltip.js +33 -0
- package/dist/components/indicators/Tooltip/types.d.ts +14 -0
- package/dist/components/indicators/Tooltip/types.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/types.js +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts +18 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.js +57 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts +14 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts.map +1 -0
- package/dist/components/inputs/Tags/tag-bar-styles.js +313 -0
- package/dist/components/inputs/Tags/types.d.ts +93 -0
- package/dist/components/inputs/Tags/types.d.ts.map +1 -0
- package/dist/components/inputs/Tags/types.js +216 -0
- package/dist/components/inputs/search/types.d.ts +9 -0
- package/dist/components/inputs/search/types.d.ts.map +1 -0
- package/dist/components/inputs/search/types.js +1 -0
- package/dist/components/navigation/adaptive/types.d.ts +16 -0
- package/dist/components/navigation/adaptive/types.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/types.js +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts +27 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.js +40 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts +6 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useBreakpoints.js +37 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts +93 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.js +145 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts +31 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewAnimation.js +591 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts +52 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewResize.js +146 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts +25 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts.map +1 -0
- package/dist/components/navigation/navstack/useNavigationStack.js +133 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts +20 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts.map +1 -0
- package/dist/components/navigation/slideover/useSlideoverController.js +267 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts +20 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts.map +1 -0
- package/dist/components/navigation/splitview/useSplitViewController.js +325 -0
- package/dist/components/navigation/tabcontroller/types.d.ts +21 -0
- package/dist/components/navigation/tabcontroller/types.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/types.js +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts +5 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.js +10 -0
- package/dist/components/navigation/types.d.ts +8 -0
- package/dist/components/navigation/types.d.ts.map +1 -0
- package/dist/components/navigation/types.js +1 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts +11 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts.map +1 -0
- package/dist/components/pickers/CollectionPicker/types.js +1 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts +13 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts.map +1 -0
- package/dist/components/pickers/ColorPicker/colors.js +266 -0
- package/dist/components/pickers/FilePicker/types.d.ts +10 -0
- package/dist/components/pickers/FilePicker/types.d.ts.map +1 -0
- package/dist/components/pickers/FilePicker/types.js +1 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +196 -0
- package/dist/theme.d.ts +73 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +279 -0
- package/dist/themes/blank.d.ts +7 -0
- package/dist/themes/blank.d.ts.map +1 -0
- package/dist/themes/blank.js +543 -0
- package/dist/themes/crimson-dark.d.ts +4 -0
- package/dist/themes/crimson-dark.d.ts.map +1 -0
- package/dist/themes/crimson-dark.js +552 -0
- package/dist/themes/cyan-light.d.ts +4 -0
- package/dist/themes/cyan-light.d.ts.map +1 -0
- package/dist/themes/cyan-light.js +552 -0
- package/dist/themes/dark.d.ts +4 -0
- package/dist/themes/dark.d.ts.map +1 -0
- package/dist/themes/dark.js +551 -0
- package/dist/themes/gold-dark.d.ts +4 -0
- package/dist/themes/gold-dark.d.ts.map +1 -0
- package/dist/themes/gold-dark.js +552 -0
- package/dist/themes/grass-dark.d.ts +4 -0
- package/dist/themes/grass-dark.d.ts.map +1 -0
- package/dist/themes/grass-dark.js +552 -0
- package/dist/themes/indigo.d.ts +4 -0
- package/dist/themes/indigo.d.ts.map +1 -0
- package/dist/themes/indigo.js +552 -0
- package/dist/themes/light.d.ts +4 -0
- package/dist/themes/light.d.ts.map +1 -0
- package/dist/themes/light.js +551 -0
- package/dist/themes/orange-dark.d.ts +4 -0
- package/dist/themes/orange-dark.d.ts.map +1 -0
- package/dist/themes/orange-dark.js +551 -0
- package/dist/themes/orange-light.d.ts +4 -0
- package/dist/themes/orange-light.d.ts.map +1 -0
- package/dist/themes/orange-light.js +551 -0
- package/package.json +62 -0
- package/src/components/controls/Button/Button.vue +417 -0
- package/src/components/controls/Button/README.md +348 -0
- package/src/components/controls/Button/theme.css +200 -0
- package/src/components/controls/Checkbox/Checkbox.vue +164 -0
- package/src/components/controls/Checkbox/README.md +441 -0
- package/src/components/controls/Checkbox/theme.css +36 -0
- package/src/components/controls/Dropdown/Dropdown.vue +476 -0
- package/src/components/controls/Dropdown/README.md +370 -0
- package/src/components/controls/Dropdown/theme.css +50 -0
- package/src/components/controls/Dropdown/types.ts +6 -0
- package/src/components/controls/IconButton/IconButton.vue +267 -0
- package/src/components/controls/IconButton/README.md +502 -0
- package/src/components/controls/IconButton/theme.css +89 -0
- package/src/components/controls/Radio/README.md +591 -0
- package/src/components/controls/Radio/Radio.vue +89 -0
- package/src/components/controls/Radio/theme.css +14 -0
- package/src/components/controls/RangeSlider/README.md +608 -0
- package/src/components/controls/RangeSlider/RangeSlider.vue +535 -0
- package/src/components/controls/RangeSlider/theme.css +80 -0
- package/src/components/controls/SegmentedControl/README.md +587 -0
- package/src/components/controls/SegmentedControl/SegmentedControl.vue +284 -0
- package/src/components/controls/SegmentedControl/theme.css +60 -0
- package/src/components/controls/SegmentedControl/types.ts +5 -0
- package/src/components/controls/Slider/README.md +627 -0
- package/src/components/controls/Slider/Slider.vue +260 -0
- package/src/components/controls/Slider/theme.css +74 -0
- package/src/components/controls/Stepper/README.md +601 -0
- package/src/components/controls/Stepper/Stepper.vue +103 -0
- package/src/components/controls/Stepper/theme.css +53 -0
- package/src/components/controls/Switch/README.md +667 -0
- package/src/components/controls/Switch/Switch.vue +127 -0
- package/src/components/controls/Switch/theme.css +42 -0
- package/src/components/dialogs/Alert/Alert.vue +218 -0
- package/src/components/dialogs/Alert/README.md +450 -0
- package/src/components/dialogs/Alert/theme.css +44 -0
- package/src/components/dialogs/Alert/types.ts +11 -0
- package/src/components/dialogs/Toast/README.md +522 -0
- package/src/components/dialogs/Toast/Toast.vue +296 -0
- package/src/components/dialogs/Toast/ToastContainer.vue +330 -0
- package/src/components/dialogs/Toast/theme.css +44 -0
- package/src/components/dialogs/Toast/types.ts +46 -0
- package/src/components/dialogs/Toast/useToast.ts +127 -0
- package/src/components/indicators/ProgressBar/ProgressBar.vue +98 -0
- package/src/components/indicators/ProgressBar/README.md +744 -0
- package/src/components/indicators/ProgressBar/theme.css +36 -0
- package/src/components/indicators/Tooltip/README.md +723 -0
- package/src/components/indicators/Tooltip/TooltipProvider.vue +142 -0
- package/src/components/indicators/Tooltip/theme.css +18 -0
- package/src/components/indicators/Tooltip/tooltip.ts +48 -0
- package/src/components/indicators/Tooltip/types.ts +15 -0
- package/src/components/indicators/Tooltip/useTooltip.ts +71 -0
- package/src/components/inputs/AutogrowTextView/AutogrowTextView.vue +110 -0
- package/src/components/inputs/AutogrowTextView/README.md +643 -0
- package/src/components/inputs/AutogrowTextView/theme.css +28 -0
- package/src/components/inputs/InputCard/InputCard.vue +600 -0
- package/src/components/inputs/InputCard/README.md +636 -0
- package/src/components/inputs/InputEmail/InputEmail.vue +698 -0
- package/src/components/inputs/InputEmail/README.md +764 -0
- package/src/components/inputs/InputNumber/InputNumber.vue +300 -0
- package/src/components/inputs/InputNumber/README.md +749 -0
- package/src/components/inputs/InputPhone/InputPhone.vue +645 -0
- package/src/components/inputs/InputPhone/README.md +636 -0
- package/src/components/inputs/InputSecure/InputSecure.vue +646 -0
- package/src/components/inputs/InputSecure/README.md +771 -0
- package/src/components/inputs/InputText/InputText.vue +225 -0
- package/src/components/inputs/InputText/README.md +844 -0
- package/src/components/inputs/OTP/OTP.vue +349 -0
- package/src/components/inputs/OTP/README.md +736 -0
- package/src/components/inputs/OTP/theme.css +50 -0
- package/src/components/inputs/StringCapture/README.md +718 -0
- package/src/components/inputs/StringCapture/StringCapture.vue +315 -0
- package/src/components/inputs/StringCapture/theme.css +86 -0
- package/src/components/inputs/Tags/README.md +897 -0
- package/src/components/inputs/Tags/TagBar.vue +793 -0
- package/src/components/inputs/Tags/TagCreation.vue +219 -0
- package/src/components/inputs/Tags/TagPicker.vue +380 -0
- package/src/components/inputs/Tags/tag-bar-styles.ts +354 -0
- package/src/components/inputs/Tags/theme.css +121 -0
- package/src/components/inputs/Tags/types.ts +346 -0
- package/src/components/inputs/search/README.md +759 -0
- package/src/components/inputs/search/SearchBar.vue +394 -0
- package/src/components/inputs/search/SearchResults.vue +310 -0
- package/src/components/inputs/search/theme.css +187 -0
- package/src/components/inputs/search/types.ts +8 -0
- package/src/components/inputs/theme.css +102 -0
- package/src/components/menus/ActionMenu/ActionMenu.vue +383 -0
- package/src/components/menus/ActionMenu/README.md +825 -0
- package/src/components/menus/ActionMenu/theme.css +93 -0
- package/src/components/models/Popover/Popover.vue +551 -0
- package/src/components/models/Popover/README.md +885 -0
- package/src/components/models/Popover/theme.css +52 -0
- package/src/components/models/Sheet/README.md +1159 -0
- package/src/components/models/Sheet/Sheet.vue +465 -0
- package/src/components/models/Sheet/theme.css +72 -0
- package/src/components/models/Sidebar/README.md +1228 -0
- package/src/components/models/Sidebar/Sidebar.vue +480 -0
- package/src/components/models/Sidebar/theme.css +90 -0
- package/src/components/navigation/adaptive/AdaptiveLayout.vue +779 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutBreadcrumbs.vue +192 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutMenuButton.vue +149 -0
- package/src/components/navigation/adaptive/README.md +768 -0
- package/src/components/navigation/adaptive/types.ts +19 -0
- package/src/components/navigation/adaptive/useAdaptiveLayout.ts +89 -0
- package/src/components/navigation/adaptive/useBreakpoints.ts +41 -0
- package/src/components/navigation/adaptive/useContainerMonitor.ts +214 -0
- package/src/components/navigation/adaptive/useViewAnimation.ts +721 -0
- package/src/components/navigation/adaptive/useViewResize.ts +211 -0
- package/src/components/navigation/navstack/NavigationStack.vue +180 -0
- package/src/components/navigation/navstack/README.md +994 -0
- package/src/components/navigation/navstack/useNavigationStack.ts +164 -0
- package/src/components/navigation/slideover/README.md +1275 -0
- package/src/components/navigation/slideover/SlideoverController.vue +287 -0
- package/src/components/navigation/slideover/useSlideoverController.ts +320 -0
- package/src/components/navigation/splitview/README.md +1115 -0
- package/src/components/navigation/splitview/SplitViewController.vue +176 -0
- package/src/components/navigation/splitview/useSplitViewController.ts +388 -0
- package/src/components/navigation/tabcontroller/README.md +919 -0
- package/src/components/navigation/tabcontroller/TabController.vue +307 -0
- package/src/components/navigation/tabcontroller/TabItem.vue +57 -0
- package/src/components/navigation/tabcontroller/types.ts +24 -0
- package/src/components/navigation/tabcontroller/useTabController.ts +18 -0
- package/src/components/navigation/theme.css +91 -0
- package/src/components/navigation/types.ts +7 -0
- package/src/components/pickers/CollectionPicker/CollectionPicker.vue +398 -0
- package/src/components/pickers/CollectionPicker/README.md +1115 -0
- package/src/components/pickers/CollectionPicker/theme.css +14 -0
- package/src/components/pickers/CollectionPicker/types.ts +11 -0
- package/src/components/pickers/ColorPicker/ColorPicker.vue +376 -0
- package/src/components/pickers/ColorPicker/README.md +1439 -0
- package/src/components/pickers/ColorPicker/colors.ts +299 -0
- package/src/components/pickers/ColorPicker/theme.css +32 -0
- package/src/components/pickers/DatePicker/DatePicker.vue +660 -0
- package/src/components/pickers/DatePicker/README.md +1195 -0
- package/src/components/pickers/DatePicker/theme.css +22 -0
- package/src/components/pickers/FilePicker/FilePicker.vue +534 -0
- package/src/components/pickers/FilePicker/README.md +1542 -0
- package/src/components/pickers/FilePicker/theme.css +48 -0
- package/src/components/pickers/FilePicker/types.ts +10 -0
- package/src/components/pickers/IconPicker/IconPicker.vue +327 -0
- package/src/components/pickers/IconPicker/README.md +1161 -0
- package/src/components/pickers/IconPicker/theme.css +28 -0
- package/src/components/pickers/theme.css +82 -0
- package/src/components/views/MarkdownViewer/MarkdownViewer.vue +442 -0
- package/src/components/views/MarkdownViewer/README.md +833 -0
- package/src/components/views/MarkdownViewer/theme.css +130 -0
- package/src/index.ts +263 -0
- package/src/theme.ts +378 -0
- package/src/themes/crimson-dark.ts +556 -0
- package/src/themes/cyan-light.ts +556 -0
- package/src/themes/dark.ts +557 -0
- package/src/themes/gold-dark.ts +556 -0
- package/src/themes/grass-dark.ts +556 -0
- package/src/themes/indigo.ts +556 -0
- package/src/themes/light.ts +557 -0
- package/src/themes/orange-dark.ts +557 -0
- package/src/themes/orange-light.ts +557 -0
- package/src/vue.d.ts +45 -0
|
@@ -0,0 +1,1228 @@
|
|
|
1
|
+
# Sidebar
|
|
2
|
+
|
|
3
|
+
A flexible and animated sidebar component built with Vue 3 Composition API and TypeScript. The Sidebar component provides a powerful interface for displaying navigation panels, menus, and contextual content with smooth slide animations and comprehensive positioning options.
|
|
4
|
+
|
|
5
|
+
## Installation/Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { Sidebar } from "@umbra-ui/core";
|
|
9
|
+
import type { SidebarProps } from "@umbra-ui/core";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Dependencies:**
|
|
13
|
+
|
|
14
|
+
- Vue 3.x
|
|
15
|
+
- gsap (for animations)
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
|
|
19
|
+
```vue
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
import { ref } from "vue";
|
|
22
|
+
import { Sidebar, Button } from "@umbra-ui/core";
|
|
23
|
+
|
|
24
|
+
const isSidebarOpen = ref(false);
|
|
25
|
+
|
|
26
|
+
const handleOpen = () => {
|
|
27
|
+
console.log("Sidebar opened");
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const handleClose = () => {
|
|
31
|
+
console.log("Sidebar closed");
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleBackdropClick = () => {
|
|
35
|
+
console.log("Backdrop clicked");
|
|
36
|
+
};
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div>
|
|
41
|
+
<Button @click="isSidebarOpen = true">Open Sidebar</Button>
|
|
42
|
+
|
|
43
|
+
<Sidebar
|
|
44
|
+
v-model="isSidebarOpen"
|
|
45
|
+
side="left"
|
|
46
|
+
:dismiss-on-backdrop="true"
|
|
47
|
+
@open="handleOpen"
|
|
48
|
+
@close="handleClose"
|
|
49
|
+
@backdrop-click="handleBackdropClick"
|
|
50
|
+
>
|
|
51
|
+
<div class="sidebar-content">
|
|
52
|
+
<h2>Sidebar Title</h2>
|
|
53
|
+
<p>This is the sidebar content. It can contain any HTML elements.</p>
|
|
54
|
+
<Button @click="isSidebarOpen = false">Close</Button>
|
|
55
|
+
</div>
|
|
56
|
+
</Sidebar>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<style>
|
|
61
|
+
.sidebar-content {
|
|
62
|
+
padding: 2rem;
|
|
63
|
+
min-height: 200px;
|
|
64
|
+
}
|
|
65
|
+
</style>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Props
|
|
69
|
+
|
|
70
|
+
| Prop Name | Type | Required | Default | Description |
|
|
71
|
+
| ------------------- | ---------------------------------------- | -------- | --------- | ------------------------------------------------ |
|
|
72
|
+
| `modelValue` | `boolean` | Yes | - | Controls the open/closed state of the sidebar |
|
|
73
|
+
| `side` | `"top" \| "bottom" \| "left" \| "right"` | No | `"left"` | The side where the sidebar appears |
|
|
74
|
+
| `dismissOnBackdrop` | `boolean` | No | `true` | Whether clicking the backdrop closes the sidebar |
|
|
75
|
+
| `width` | `string` | No | `"280px"` | Width of the sidebar (for left/right) |
|
|
76
|
+
| `height` | `string` | No | `"280px"` | Height of the sidebar (for top/bottom) |
|
|
77
|
+
| `minWidth` | `string` | No | `"280px"` | Minimum width of the sidebar |
|
|
78
|
+
| `minHeight` | `string` | No | `"280px"` | Minimum height of the sidebar |
|
|
79
|
+
| `maxWidth` | `string` | No | `"90vw"` | Maximum width of the sidebar |
|
|
80
|
+
| `maxHeight` | `string` | No | `"90vh"` | Maximum height of the sidebar |
|
|
81
|
+
| `animationDuration` | `number` | No | `0.4` | Animation duration in seconds |
|
|
82
|
+
| `backdropStyle` | `"blur" \| "dim"` | No | `"blur"` | Backdrop style: blur or dim |
|
|
83
|
+
| `zIndex` | `number` | No | `1000` | Z-index for the sidebar |
|
|
84
|
+
| `teleportTo` | `string \| HTMLElement` | No | `"body"` | Teleport target element |
|
|
85
|
+
|
|
86
|
+
## Events
|
|
87
|
+
|
|
88
|
+
| Event Name | Payload Type | Description |
|
|
89
|
+
| ------------------- | ------------ | ------------------------------------------- |
|
|
90
|
+
| `update:modelValue` | `boolean` | Emitted when the sidebar open state changes |
|
|
91
|
+
| `backdrop-click` | `void` | Emitted when the backdrop is clicked |
|
|
92
|
+
| `open` | `void` | Emitted when the sidebar opens |
|
|
93
|
+
| `close` | `void` | Emitted when the sidebar closes |
|
|
94
|
+
| `after-enter` | `void` | Emitted after the open animation completes |
|
|
95
|
+
| `after-leave` | `void` | Emitted after the close animation completes |
|
|
96
|
+
|
|
97
|
+
## Slots
|
|
98
|
+
|
|
99
|
+
| Slot Name | Description |
|
|
100
|
+
| --------- | ---------------------------------------- |
|
|
101
|
+
| `default` | The content displayed inside the sidebar |
|
|
102
|
+
|
|
103
|
+
## Exposed Methods/Refs
|
|
104
|
+
|
|
105
|
+
The Sidebar component exposes the following methods and properties via template refs:
|
|
106
|
+
|
|
107
|
+
| Method/Property | Type | Description |
|
|
108
|
+
| --------------- | -------------- | -------------------------------------- |
|
|
109
|
+
| `open` | `() => void` | Opens the sidebar programmatically |
|
|
110
|
+
| `close` | `() => void` | Closes the sidebar programmatically |
|
|
111
|
+
| `isVisible` | `Ref<boolean>` | Reactive reference to visibility state |
|
|
112
|
+
| `isAnimating` | `Ref<boolean>` | Reactive reference to animation state |
|
|
113
|
+
|
|
114
|
+
### Example Usage
|
|
115
|
+
|
|
116
|
+
```vue
|
|
117
|
+
<script setup lang="ts">
|
|
118
|
+
import { ref } from "vue";
|
|
119
|
+
import { Sidebar } from "@umbra-ui/core";
|
|
120
|
+
|
|
121
|
+
const sidebarRef = ref<InstanceType<typeof Sidebar> | null>(null);
|
|
122
|
+
|
|
123
|
+
const openSidebar = () => {
|
|
124
|
+
sidebarRef.value?.open();
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const closeSidebar = () => {
|
|
128
|
+
sidebarRef.value?.close();
|
|
129
|
+
};
|
|
130
|
+
</script>
|
|
131
|
+
|
|
132
|
+
<template>
|
|
133
|
+
<Sidebar ref="sidebarRef" :model-value="false">
|
|
134
|
+
<div class="content">
|
|
135
|
+
<p>Sidebar content</p>
|
|
136
|
+
<button @click="closeSidebar">Close</button>
|
|
137
|
+
</div>
|
|
138
|
+
</Sidebar>
|
|
139
|
+
</template>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Positioning Options
|
|
143
|
+
|
|
144
|
+
### Left Sidebar
|
|
145
|
+
|
|
146
|
+
- **Default position**
|
|
147
|
+
- Slides in from the left edge
|
|
148
|
+
- Full height with configurable width
|
|
149
|
+
- Best for navigation menus and main content panels
|
|
150
|
+
|
|
151
|
+
### Right Sidebar
|
|
152
|
+
|
|
153
|
+
- Slides in from the right edge
|
|
154
|
+
- Full height with configurable width
|
|
155
|
+
- Good for secondary actions and settings panels
|
|
156
|
+
|
|
157
|
+
### Top Sidebar
|
|
158
|
+
|
|
159
|
+
- Slides in from the top edge
|
|
160
|
+
- Full width with configurable height
|
|
161
|
+
- Useful for notification bars and top navigation
|
|
162
|
+
|
|
163
|
+
### Bottom Sidebar
|
|
164
|
+
|
|
165
|
+
- Slides in from the bottom edge
|
|
166
|
+
- Full width with configurable height
|
|
167
|
+
- Good for mobile navigation and action sheets
|
|
168
|
+
|
|
169
|
+
## Backdrop Styles
|
|
170
|
+
|
|
171
|
+
### Blur Backdrop
|
|
172
|
+
|
|
173
|
+
- **Default backdrop style**
|
|
174
|
+
- Semi-transparent with blur effect
|
|
175
|
+
- Modern, iOS-like appearance
|
|
176
|
+
- Uses `backdrop-filter: blur(10px)`
|
|
177
|
+
|
|
178
|
+
### Dim Backdrop
|
|
179
|
+
|
|
180
|
+
- Simple semi-transparent overlay
|
|
181
|
+
- No blur effect
|
|
182
|
+
- More traditional modal appearance
|
|
183
|
+
- Better performance on older devices
|
|
184
|
+
|
|
185
|
+
## CSS Customization
|
|
186
|
+
|
|
187
|
+
The Sidebar component uses CSS custom properties for theming and customization:
|
|
188
|
+
|
|
189
|
+
### Light Theme Variables
|
|
190
|
+
|
|
191
|
+
```css
|
|
192
|
+
/* Sidebar colors */
|
|
193
|
+
--sidebar-bg: #ffffff;
|
|
194
|
+
|
|
195
|
+
/* Sidebar backdrop colors */
|
|
196
|
+
--sidebar-backdrop-blur-bg: rgba(0, 0, 0, 0.3);
|
|
197
|
+
--sidebar-backdrop-dim-bg: rgba(0, 0, 0, 0.7);
|
|
198
|
+
|
|
199
|
+
/* Sidebar shadow colors */
|
|
200
|
+
--sidebar-shadow-left: rgba(0, 0, 0, 0.15);
|
|
201
|
+
--sidebar-shadow-right: rgba(0, 0, 0, 0.15);
|
|
202
|
+
--sidebar-shadow-top: rgba(0, 0, 0, 0.15);
|
|
203
|
+
--sidebar-shadow-bottom: rgba(0, 0, 0, 0.15);
|
|
204
|
+
|
|
205
|
+
/* Sidebar scrollbar colors */
|
|
206
|
+
--sidebar-scrollbar-thumb: rgba(0, 0, 0, 0.2);
|
|
207
|
+
--sidebar-scrollbar-thumb-hover: rgba(0, 0, 0, 0.3);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Dark Theme Variables
|
|
211
|
+
|
|
212
|
+
```css
|
|
213
|
+
/* Sidebar colors */
|
|
214
|
+
--sidebar-bg: #111111;
|
|
215
|
+
|
|
216
|
+
/* Sidebar backdrop colors */
|
|
217
|
+
--sidebar-backdrop-blur-bg: rgba(0, 0, 0, 0.3);
|
|
218
|
+
--sidebar-backdrop-dim-bg: rgba(0, 0, 0, 0.85);
|
|
219
|
+
|
|
220
|
+
/* Sidebar shadow colors */
|
|
221
|
+
--sidebar-shadow-left: rgba(0, 0, 0, 0.5);
|
|
222
|
+
--sidebar-shadow-right: rgba(0, 0, 0, 0.5);
|
|
223
|
+
--sidebar-shadow-top: rgba(0, 0, 0, 0.5);
|
|
224
|
+
--sidebar-shadow-bottom: rgba(0, 0, 0, 0.5);
|
|
225
|
+
|
|
226
|
+
/* Sidebar scrollbar colors */
|
|
227
|
+
--sidebar-scrollbar-thumb: rgba(255, 255, 255, 0.2);
|
|
228
|
+
--sidebar-scrollbar-thumb-hover: rgba(255, 255, 255, 0.3);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Key Features
|
|
232
|
+
|
|
233
|
+
### Smart Positioning
|
|
234
|
+
|
|
235
|
+
- **Four Directions**: Slide in from top, bottom, left, or right
|
|
236
|
+
- **Responsive Sizing**: Configurable width, height, and constraints
|
|
237
|
+
- **Viewport Awareness**: Automatically respects viewport boundaries
|
|
238
|
+
- **Safe Area Support**: Handles mobile device safe areas
|
|
239
|
+
|
|
240
|
+
### Animation System
|
|
241
|
+
|
|
242
|
+
- **GSAP Animations**: Smooth, performant animations using GSAP
|
|
243
|
+
- **Slide Animations**: Directional slide-in/out effects
|
|
244
|
+
- **GPU Acceleration**: Hardware-accelerated transforms
|
|
245
|
+
- **Customizable Duration**: Configurable animation timing
|
|
246
|
+
|
|
247
|
+
### User Experience
|
|
248
|
+
|
|
249
|
+
- **Backdrop Interaction**: Click backdrop to dismiss (configurable)
|
|
250
|
+
- **Keyboard Support**: Escape key closes sidebar
|
|
251
|
+
- **Body Scroll Lock**: Prevents background scrolling when open
|
|
252
|
+
- **Teleport Support**: Renders outside component tree
|
|
253
|
+
|
|
254
|
+
### Visual Features
|
|
255
|
+
|
|
256
|
+
- **Directional Shadows**: Shadows adapt to sidebar position
|
|
257
|
+
- **Custom Scrollbars**: Styled scrollbars for better UX
|
|
258
|
+
- **Backdrop Effects**: Blur or dim backdrop options
|
|
259
|
+
- **Safe Area Handling**: Proper mobile device support
|
|
260
|
+
|
|
261
|
+
## Examples
|
|
262
|
+
|
|
263
|
+
### Basic Sidebar
|
|
264
|
+
|
|
265
|
+
```vue
|
|
266
|
+
<script setup lang="ts">
|
|
267
|
+
import { ref } from "vue";
|
|
268
|
+
import { Sidebar, Button } from "@umbra-ui/core";
|
|
269
|
+
|
|
270
|
+
const isOpen = ref(false);
|
|
271
|
+
|
|
272
|
+
const handleOpen = () => {
|
|
273
|
+
console.log("Sidebar opened");
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const handleClose = () => {
|
|
277
|
+
console.log("Sidebar closed");
|
|
278
|
+
};
|
|
279
|
+
</script>
|
|
280
|
+
|
|
281
|
+
<template>
|
|
282
|
+
<div class="basic-sidebar">
|
|
283
|
+
<h3>Basic Sidebar</h3>
|
|
284
|
+
|
|
285
|
+
<Button @click="isOpen = true">Open Sidebar</Button>
|
|
286
|
+
|
|
287
|
+
<Sidebar
|
|
288
|
+
v-model="isOpen"
|
|
289
|
+
side="left"
|
|
290
|
+
:dismiss-on-backdrop="true"
|
|
291
|
+
@open="handleOpen"
|
|
292
|
+
@close="handleClose"
|
|
293
|
+
>
|
|
294
|
+
<div class="sidebar-content">
|
|
295
|
+
<h2>Sidebar Title</h2>
|
|
296
|
+
<p>This is a basic sidebar with default settings.</p>
|
|
297
|
+
<p>
|
|
298
|
+
It slides in from the left and can be dismissed by clicking the
|
|
299
|
+
backdrop.
|
|
300
|
+
</p>
|
|
301
|
+
<div class="actions">
|
|
302
|
+
<Button @click="isOpen = false">Close</Button>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
</Sidebar>
|
|
306
|
+
|
|
307
|
+
<p class="status">Sidebar is {{ isOpen ? "open" : "closed" }}</p>
|
|
308
|
+
</div>
|
|
309
|
+
</template>
|
|
310
|
+
|
|
311
|
+
<style module>
|
|
312
|
+
.basic-sidebar {
|
|
313
|
+
padding: 2rem;
|
|
314
|
+
border: 1px solid #e0e0e0;
|
|
315
|
+
border-radius: 0.5rem;
|
|
316
|
+
max-width: 400px;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.sidebar-content {
|
|
320
|
+
padding: 2rem;
|
|
321
|
+
min-height: 200px;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.sidebar-content h2 {
|
|
325
|
+
margin: 0 0 1rem 0;
|
|
326
|
+
color: #333;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.sidebar-content p {
|
|
330
|
+
margin: 0 0 1rem 0;
|
|
331
|
+
color: #666;
|
|
332
|
+
line-height: 1.5;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.actions {
|
|
336
|
+
display: flex;
|
|
337
|
+
gap: 0.75rem;
|
|
338
|
+
justify-content: flex-end;
|
|
339
|
+
margin-top: 1.5rem;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.status {
|
|
343
|
+
margin-top: 1rem;
|
|
344
|
+
color: #666;
|
|
345
|
+
font-size: 0.875rem;
|
|
346
|
+
}
|
|
347
|
+
</style>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Different Sides
|
|
351
|
+
|
|
352
|
+
```vue
|
|
353
|
+
<script setup lang="ts">
|
|
354
|
+
import { ref } from "vue";
|
|
355
|
+
import { Sidebar, Button } from "@umbra-ui/core";
|
|
356
|
+
|
|
357
|
+
const sides = ["left", "right", "top", "bottom"];
|
|
358
|
+
const openSidebars = ref<Record<string, boolean>>({});
|
|
359
|
+
|
|
360
|
+
const toggleSidebar = (side: string) => {
|
|
361
|
+
openSidebars.value[side] = !openSidebars.value[side];
|
|
362
|
+
};
|
|
363
|
+
</script>
|
|
364
|
+
|
|
365
|
+
<template>
|
|
366
|
+
<div class="sides-demo">
|
|
367
|
+
<h3>Sidebar Sides</h3>
|
|
368
|
+
<p>Click the buttons to see different slide directions:</p>
|
|
369
|
+
|
|
370
|
+
<div class="sides-grid">
|
|
371
|
+
<div v-for="side in sides" :key="side" class="side-item">
|
|
372
|
+
<Button @click="toggleSidebar(side)" size="small">
|
|
373
|
+
{{ side }}
|
|
374
|
+
</Button>
|
|
375
|
+
|
|
376
|
+
<Sidebar
|
|
377
|
+
v-model="openSidebars[side]"
|
|
378
|
+
:side="side"
|
|
379
|
+
:dismiss-on-backdrop="true"
|
|
380
|
+
>
|
|
381
|
+
<div class="side-content">
|
|
382
|
+
<h4>{{ side }} Sidebar</h4>
|
|
383
|
+
<p>This sidebar slides in from the {{ side }}.</p>
|
|
384
|
+
<Button @click="openSidebars[side] = false" size="small">
|
|
385
|
+
Close
|
|
386
|
+
</Button>
|
|
387
|
+
</div>
|
|
388
|
+
</Sidebar>
|
|
389
|
+
</div>
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
</template>
|
|
393
|
+
|
|
394
|
+
<style module>
|
|
395
|
+
.sides-demo {
|
|
396
|
+
padding: 2rem;
|
|
397
|
+
border: 1px solid #e0e0e0;
|
|
398
|
+
border-radius: 0.5rem;
|
|
399
|
+
max-width: 600px;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.sides-grid {
|
|
403
|
+
display: grid;
|
|
404
|
+
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
405
|
+
gap: 1rem;
|
|
406
|
+
margin-top: 1rem;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.side-item {
|
|
410
|
+
display: flex;
|
|
411
|
+
justify-content: center;
|
|
412
|
+
align-items: center;
|
|
413
|
+
min-height: 60px;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.side-content {
|
|
417
|
+
padding: 1.5rem;
|
|
418
|
+
min-height: 150px;
|
|
419
|
+
text-align: center;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.side-content h4 {
|
|
423
|
+
margin: 0 0 1rem 0;
|
|
424
|
+
color: #333;
|
|
425
|
+
text-transform: capitalize;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.side-content p {
|
|
429
|
+
margin: 0 0 1rem 0;
|
|
430
|
+
color: #666;
|
|
431
|
+
}
|
|
432
|
+
</style>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Navigation Sidebar
|
|
436
|
+
|
|
437
|
+
```vue
|
|
438
|
+
<script setup lang="ts">
|
|
439
|
+
import { ref } from "vue";
|
|
440
|
+
import { Sidebar, Button } from "@umbra-ui/core";
|
|
441
|
+
|
|
442
|
+
const isNavOpen = ref(false);
|
|
443
|
+
const activeItem = ref("dashboard");
|
|
444
|
+
|
|
445
|
+
const navItems = [
|
|
446
|
+
{ id: "dashboard", label: "Dashboard", icon: "🏠" },
|
|
447
|
+
{ id: "projects", label: "Projects", icon: "📁" },
|
|
448
|
+
{ id: "tasks", label: "Tasks", icon: "✅" },
|
|
449
|
+
{ id: "calendar", label: "Calendar", icon: "📅" },
|
|
450
|
+
{ id: "messages", label: "Messages", icon: "💬" },
|
|
451
|
+
{ id: "settings", label: "Settings", icon: "⚙️" },
|
|
452
|
+
];
|
|
453
|
+
|
|
454
|
+
const handleNavClick = (itemId: string) => {
|
|
455
|
+
activeItem.value = itemId;
|
|
456
|
+
console.log("Navigated to:", itemId);
|
|
457
|
+
};
|
|
458
|
+
</script>
|
|
459
|
+
|
|
460
|
+
<template>
|
|
461
|
+
<div class="nav-sidebar">
|
|
462
|
+
<h3>Navigation Sidebar</h3>
|
|
463
|
+
|
|
464
|
+
<Button @click="isNavOpen = true">Open Navigation</Button>
|
|
465
|
+
|
|
466
|
+
<Sidebar
|
|
467
|
+
v-model="isNavOpen"
|
|
468
|
+
side="left"
|
|
469
|
+
width="280px"
|
|
470
|
+
:dismiss-on-backdrop="true"
|
|
471
|
+
>
|
|
472
|
+
<div class="nav-content">
|
|
473
|
+
<div class="nav-header">
|
|
474
|
+
<h2>Navigation</h2>
|
|
475
|
+
<button @click="isNavOpen = false" class="close-btn">×</button>
|
|
476
|
+
</div>
|
|
477
|
+
|
|
478
|
+
<nav class="nav-menu">
|
|
479
|
+
<div
|
|
480
|
+
v-for="item in navItems"
|
|
481
|
+
:key="item.id"
|
|
482
|
+
:class="[
|
|
483
|
+
'nav-item',
|
|
484
|
+
{ 'nav-item--active': activeItem === item.id },
|
|
485
|
+
]"
|
|
486
|
+
@click="handleNavClick(item.id)"
|
|
487
|
+
>
|
|
488
|
+
<span class="nav-icon">{{ item.icon }}</span>
|
|
489
|
+
<span class="nav-label">{{ item.label }}</span>
|
|
490
|
+
</div>
|
|
491
|
+
</nav>
|
|
492
|
+
|
|
493
|
+
<div class="nav-footer">
|
|
494
|
+
<div class="user-info">
|
|
495
|
+
<div class="user-avatar">👤</div>
|
|
496
|
+
<div class="user-details">
|
|
497
|
+
<div class="user-name">John Doe</div>
|
|
498
|
+
<div class="user-email">john@example.com</div>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
</div>
|
|
502
|
+
</div>
|
|
503
|
+
</Sidebar>
|
|
504
|
+
</div>
|
|
505
|
+
</template>
|
|
506
|
+
|
|
507
|
+
<style module>
|
|
508
|
+
.nav-sidebar {
|
|
509
|
+
padding: 2rem;
|
|
510
|
+
border: 1px solid #e0e0e0;
|
|
511
|
+
border-radius: 0.5rem;
|
|
512
|
+
max-width: 400px;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.nav-content {
|
|
516
|
+
height: 100vh;
|
|
517
|
+
display: flex;
|
|
518
|
+
flex-direction: column;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.nav-header {
|
|
522
|
+
display: flex;
|
|
523
|
+
justify-content: space-between;
|
|
524
|
+
align-items: center;
|
|
525
|
+
padding: 1.5rem 2rem 1rem;
|
|
526
|
+
border-bottom: 1px solid #e0e0e0;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.nav-header h2 {
|
|
530
|
+
margin: 0;
|
|
531
|
+
color: #333;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.close-btn {
|
|
535
|
+
background: none;
|
|
536
|
+
border: none;
|
|
537
|
+
font-size: 1.5rem;
|
|
538
|
+
cursor: pointer;
|
|
539
|
+
padding: 0;
|
|
540
|
+
width: 32px;
|
|
541
|
+
height: 32px;
|
|
542
|
+
display: flex;
|
|
543
|
+
align-items: center;
|
|
544
|
+
justify-content: center;
|
|
545
|
+
border-radius: 50%;
|
|
546
|
+
color: #666;
|
|
547
|
+
transition: background-color 0.2s;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.close-btn:hover {
|
|
551
|
+
background-color: #f0f0f0;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.nav-menu {
|
|
555
|
+
flex: 1;
|
|
556
|
+
padding: 1rem 0;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.nav-item {
|
|
560
|
+
display: flex;
|
|
561
|
+
align-items: center;
|
|
562
|
+
gap: 1rem;
|
|
563
|
+
padding: 0.75rem 2rem;
|
|
564
|
+
cursor: pointer;
|
|
565
|
+
transition: background-color 0.2s;
|
|
566
|
+
color: #666;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.nav-item:hover {
|
|
570
|
+
background-color: #f8f9fa;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.nav-item--active {
|
|
574
|
+
background-color: #e3f2fd;
|
|
575
|
+
color: #1976d2;
|
|
576
|
+
border-right: 3px solid #1976d2;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.nav-icon {
|
|
580
|
+
font-size: 1.25rem;
|
|
581
|
+
width: 1.5rem;
|
|
582
|
+
text-align: center;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.nav-label {
|
|
586
|
+
font-weight: 500;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
.nav-footer {
|
|
590
|
+
padding: 1.5rem 2rem;
|
|
591
|
+
border-top: 1px solid #e0e0e0;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.user-info {
|
|
595
|
+
display: flex;
|
|
596
|
+
align-items: center;
|
|
597
|
+
gap: 0.75rem;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.user-avatar {
|
|
601
|
+
width: 40px;
|
|
602
|
+
height: 40px;
|
|
603
|
+
background-color: #e0e0e0;
|
|
604
|
+
border-radius: 50%;
|
|
605
|
+
display: flex;
|
|
606
|
+
align-items: center;
|
|
607
|
+
justify-content: center;
|
|
608
|
+
font-size: 1.25rem;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.user-name {
|
|
612
|
+
font-weight: 600;
|
|
613
|
+
color: #333;
|
|
614
|
+
margin-bottom: 0.25rem;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
.user-email {
|
|
618
|
+
font-size: 0.875rem;
|
|
619
|
+
color: #666;
|
|
620
|
+
}
|
|
621
|
+
</style>
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Settings Panel
|
|
625
|
+
|
|
626
|
+
```vue
|
|
627
|
+
<script setup lang="ts">
|
|
628
|
+
import { ref } from "vue";
|
|
629
|
+
import { Sidebar, Button } from "@umbra-ui/core";
|
|
630
|
+
|
|
631
|
+
const isSettingsOpen = ref(false);
|
|
632
|
+
const settings = ref({
|
|
633
|
+
notifications: true,
|
|
634
|
+
darkMode: false,
|
|
635
|
+
autoSave: true,
|
|
636
|
+
language: "en",
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
const handleSave = () => {
|
|
640
|
+
console.log("Settings saved:", settings.value);
|
|
641
|
+
isSettingsOpen.value = false;
|
|
642
|
+
};
|
|
643
|
+
</script>
|
|
644
|
+
|
|
645
|
+
<template>
|
|
646
|
+
<div class="settings-sidebar">
|
|
647
|
+
<h3>Settings Panel</h3>
|
|
648
|
+
|
|
649
|
+
<Button @click="isSettingsOpen = true">Open Settings</Button>
|
|
650
|
+
|
|
651
|
+
<Sidebar
|
|
652
|
+
v-model="isSettingsOpen"
|
|
653
|
+
side="right"
|
|
654
|
+
width="350px"
|
|
655
|
+
:dismiss-on-backdrop="false"
|
|
656
|
+
>
|
|
657
|
+
<div class="settings-content">
|
|
658
|
+
<div class="settings-header">
|
|
659
|
+
<h2>Settings</h2>
|
|
660
|
+
<button @click="isSettingsOpen = false" class="close-btn">×</button>
|
|
661
|
+
</div>
|
|
662
|
+
|
|
663
|
+
<div class="settings-body">
|
|
664
|
+
<div class="setting-group">
|
|
665
|
+
<h3>Preferences</h3>
|
|
666
|
+
|
|
667
|
+
<div class="setting-item">
|
|
668
|
+
<div class="setting-info">
|
|
669
|
+
<h4>Notifications</h4>
|
|
670
|
+
<p>Receive push notifications</p>
|
|
671
|
+
</div>
|
|
672
|
+
<label class="toggle">
|
|
673
|
+
<input v-model="settings.notifications" type="checkbox" />
|
|
674
|
+
<span class="slider"></span>
|
|
675
|
+
</label>
|
|
676
|
+
</div>
|
|
677
|
+
|
|
678
|
+
<div class="setting-item">
|
|
679
|
+
<div class="setting-info">
|
|
680
|
+
<h4>Dark Mode</h4>
|
|
681
|
+
<p>Use dark theme</p>
|
|
682
|
+
</div>
|
|
683
|
+
<label class="toggle">
|
|
684
|
+
<input v-model="settings.darkMode" type="checkbox" />
|
|
685
|
+
<span class="slider"></span>
|
|
686
|
+
</label>
|
|
687
|
+
</div>
|
|
688
|
+
|
|
689
|
+
<div class="setting-item">
|
|
690
|
+
<div class="setting-info">
|
|
691
|
+
<h4>Auto Save</h4>
|
|
692
|
+
<p>Automatically save changes</p>
|
|
693
|
+
</div>
|
|
694
|
+
<label class="toggle">
|
|
695
|
+
<input v-model="settings.autoSave" type="checkbox" />
|
|
696
|
+
<span class="slider"></span>
|
|
697
|
+
</label>
|
|
698
|
+
</div>
|
|
699
|
+
</div>
|
|
700
|
+
|
|
701
|
+
<div class="setting-group">
|
|
702
|
+
<h3>Language</h3>
|
|
703
|
+
|
|
704
|
+
<div class="setting-item">
|
|
705
|
+
<div class="setting-info">
|
|
706
|
+
<h4>Language</h4>
|
|
707
|
+
<p>Select your preferred language</p>
|
|
708
|
+
</div>
|
|
709
|
+
<select v-model="settings.language" class="select">
|
|
710
|
+
<option value="en">English</option>
|
|
711
|
+
<option value="es">Spanish</option>
|
|
712
|
+
<option value="fr">French</option>
|
|
713
|
+
<option value="de">German</option>
|
|
714
|
+
</select>
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
|
|
719
|
+
<div class="settings-footer">
|
|
720
|
+
<Button @click="isSettingsOpen = false" variant="secondary">
|
|
721
|
+
Cancel
|
|
722
|
+
</Button>
|
|
723
|
+
<Button @click="handleSave">Save Changes</Button>
|
|
724
|
+
</div>
|
|
725
|
+
</div>
|
|
726
|
+
</Sidebar>
|
|
727
|
+
</div>
|
|
728
|
+
</template>
|
|
729
|
+
|
|
730
|
+
<style module>
|
|
731
|
+
.settings-sidebar {
|
|
732
|
+
padding: 2rem;
|
|
733
|
+
border: 1px solid #e0e0e0;
|
|
734
|
+
border-radius: 0.5rem;
|
|
735
|
+
max-width: 400px;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.settings-content {
|
|
739
|
+
height: 100vh;
|
|
740
|
+
display: flex;
|
|
741
|
+
flex-direction: column;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.settings-header {
|
|
745
|
+
display: flex;
|
|
746
|
+
justify-content: space-between;
|
|
747
|
+
align-items: center;
|
|
748
|
+
padding: 1.5rem 2rem 1rem;
|
|
749
|
+
border-bottom: 1px solid #e0e0e0;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.settings-header h2 {
|
|
753
|
+
margin: 0;
|
|
754
|
+
color: #333;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
.close-btn {
|
|
758
|
+
background: none;
|
|
759
|
+
border: none;
|
|
760
|
+
font-size: 1.5rem;
|
|
761
|
+
cursor: pointer;
|
|
762
|
+
padding: 0;
|
|
763
|
+
width: 32px;
|
|
764
|
+
height: 32px;
|
|
765
|
+
display: flex;
|
|
766
|
+
align-items: center;
|
|
767
|
+
justify-content: center;
|
|
768
|
+
border-radius: 50%;
|
|
769
|
+
color: #666;
|
|
770
|
+
transition: background-color 0.2s;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.close-btn:hover {
|
|
774
|
+
background-color: #f0f0f0;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.settings-body {
|
|
778
|
+
flex: 1;
|
|
779
|
+
padding: 2rem;
|
|
780
|
+
overflow-y: auto;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.setting-group {
|
|
784
|
+
margin-bottom: 2rem;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
.setting-group h3 {
|
|
788
|
+
margin: 0 0 1rem 0;
|
|
789
|
+
color: #333;
|
|
790
|
+
font-size: 1.125rem;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.setting-item {
|
|
794
|
+
display: flex;
|
|
795
|
+
justify-content: space-between;
|
|
796
|
+
align-items: center;
|
|
797
|
+
padding: 1rem 0;
|
|
798
|
+
border-bottom: 1px solid #f0f0f0;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.setting-info h4 {
|
|
802
|
+
margin: 0 0 0.25rem 0;
|
|
803
|
+
color: #333;
|
|
804
|
+
font-size: 1rem;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
.setting-info p {
|
|
808
|
+
margin: 0;
|
|
809
|
+
color: #666;
|
|
810
|
+
font-size: 0.875rem;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.toggle {
|
|
814
|
+
position: relative;
|
|
815
|
+
display: inline-block;
|
|
816
|
+
width: 50px;
|
|
817
|
+
height: 24px;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
.toggle input {
|
|
821
|
+
opacity: 0;
|
|
822
|
+
width: 0;
|
|
823
|
+
height: 0;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.slider {
|
|
827
|
+
position: absolute;
|
|
828
|
+
cursor: pointer;
|
|
829
|
+
top: 0;
|
|
830
|
+
left: 0;
|
|
831
|
+
right: 0;
|
|
832
|
+
bottom: 0;
|
|
833
|
+
background-color: #ccc;
|
|
834
|
+
transition: 0.2s;
|
|
835
|
+
border-radius: 24px;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
.slider:before {
|
|
839
|
+
position: absolute;
|
|
840
|
+
content: "";
|
|
841
|
+
height: 18px;
|
|
842
|
+
width: 18px;
|
|
843
|
+
left: 3px;
|
|
844
|
+
bottom: 3px;
|
|
845
|
+
background-color: white;
|
|
846
|
+
transition: 0.2s;
|
|
847
|
+
border-radius: 50%;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
input:checked + .slider {
|
|
851
|
+
background-color: #007bff;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
input:checked + .slider:before {
|
|
855
|
+
transform: translateX(26px);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
.select {
|
|
859
|
+
padding: 0.5rem;
|
|
860
|
+
border: 1px solid #ddd;
|
|
861
|
+
border-radius: 0.25rem;
|
|
862
|
+
background-color: white;
|
|
863
|
+
color: #333;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.settings-footer {
|
|
867
|
+
display: flex;
|
|
868
|
+
gap: 0.75rem;
|
|
869
|
+
justify-content: flex-end;
|
|
870
|
+
padding: 1.5rem 2rem;
|
|
871
|
+
border-top: 1px solid #e0e0e0;
|
|
872
|
+
}
|
|
873
|
+
</style>
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
### Custom Styled Sidebar
|
|
877
|
+
|
|
878
|
+
```vue
|
|
879
|
+
<script setup lang="ts">
|
|
880
|
+
import { ref } from "vue";
|
|
881
|
+
import { Sidebar, Button } from "@umbra-ui/core";
|
|
882
|
+
|
|
883
|
+
const isCustomOpen = ref(false);
|
|
884
|
+
</script>
|
|
885
|
+
|
|
886
|
+
<template>
|
|
887
|
+
<div class="custom-sidebar">
|
|
888
|
+
<h3>Custom Styled Sidebar</h3>
|
|
889
|
+
|
|
890
|
+
<Button @click="isCustomOpen = true" class="custom-trigger">
|
|
891
|
+
Open Custom Sidebar
|
|
892
|
+
</Button>
|
|
893
|
+
|
|
894
|
+
<Sidebar
|
|
895
|
+
v-model="isCustomOpen"
|
|
896
|
+
side="right"
|
|
897
|
+
width="400px"
|
|
898
|
+
:animation-duration="0.6"
|
|
899
|
+
backdrop-style="dim"
|
|
900
|
+
>
|
|
901
|
+
<div class="custom-content">
|
|
902
|
+
<div class="custom-header">
|
|
903
|
+
<h2>Custom Sidebar</h2>
|
|
904
|
+
<p>This sidebar has custom styling and positioning.</p>
|
|
905
|
+
</div>
|
|
906
|
+
|
|
907
|
+
<div class="custom-body">
|
|
908
|
+
<div class="feature-list">
|
|
909
|
+
<div class="feature-item">
|
|
910
|
+
<div class="feature-icon">🎨</div>
|
|
911
|
+
<div class="feature-text">
|
|
912
|
+
<h4>Custom Colors</h4>
|
|
913
|
+
<p>Gradient backgrounds and custom styling</p>
|
|
914
|
+
</div>
|
|
915
|
+
</div>
|
|
916
|
+
|
|
917
|
+
<div class="feature-item">
|
|
918
|
+
<div class="feature-icon">⚡</div>
|
|
919
|
+
<div class="feature-text">
|
|
920
|
+
<h4>Right Side</h4>
|
|
921
|
+
<p>Slides in from the right side</p>
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
|
|
925
|
+
<div class="feature-item">
|
|
926
|
+
<div class="feature-icon">🔧</div>
|
|
927
|
+
<div class="feature-text">
|
|
928
|
+
<h4>Custom Size</h4>
|
|
929
|
+
<p>Fixed width and custom dimensions</p>
|
|
930
|
+
</div>
|
|
931
|
+
</div>
|
|
932
|
+
</div>
|
|
933
|
+
</div>
|
|
934
|
+
|
|
935
|
+
<div class="custom-footer">
|
|
936
|
+
<Button @click="isCustomOpen = false" class="custom-close">
|
|
937
|
+
Close
|
|
938
|
+
</Button>
|
|
939
|
+
</div>
|
|
940
|
+
</div>
|
|
941
|
+
</Sidebar>
|
|
942
|
+
</div>
|
|
943
|
+
</template>
|
|
944
|
+
|
|
945
|
+
<style module>
|
|
946
|
+
.custom-sidebar {
|
|
947
|
+
padding: 2rem;
|
|
948
|
+
border: 1px solid #e0e0e0;
|
|
949
|
+
border-radius: 0.5rem;
|
|
950
|
+
max-width: 400px;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.custom-trigger {
|
|
954
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
955
|
+
color: white;
|
|
956
|
+
border: none;
|
|
957
|
+
padding: 0.75rem 1.5rem;
|
|
958
|
+
border-radius: 0.5rem;
|
|
959
|
+
font-weight: 600;
|
|
960
|
+
transition: transform 0.2s;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
.custom-trigger:hover {
|
|
964
|
+
transform: translateY(-2px);
|
|
965
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.custom-content {
|
|
969
|
+
height: 100vh;
|
|
970
|
+
display: flex;
|
|
971
|
+
flex-direction: column;
|
|
972
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
973
|
+
color: white;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
.custom-header {
|
|
977
|
+
padding: 2rem;
|
|
978
|
+
text-align: center;
|
|
979
|
+
background: rgba(255, 255, 255, 0.1);
|
|
980
|
+
backdrop-filter: blur(10px);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.custom-header h2 {
|
|
984
|
+
margin: 0 0 0.5rem 0;
|
|
985
|
+
font-size: 1.5rem;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
.custom-header p {
|
|
989
|
+
margin: 0;
|
|
990
|
+
opacity: 0.9;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
.custom-body {
|
|
994
|
+
flex: 1;
|
|
995
|
+
padding: 2rem;
|
|
996
|
+
overflow-y: auto;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.feature-list {
|
|
1000
|
+
display: flex;
|
|
1001
|
+
flex-direction: column;
|
|
1002
|
+
gap: 1.5rem;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
.feature-item {
|
|
1006
|
+
display: flex;
|
|
1007
|
+
align-items: flex-start;
|
|
1008
|
+
gap: 1rem;
|
|
1009
|
+
padding: 1rem;
|
|
1010
|
+
background: rgba(255, 255, 255, 0.1);
|
|
1011
|
+
border-radius: 0.5rem;
|
|
1012
|
+
backdrop-filter: blur(5px);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
.feature-icon {
|
|
1016
|
+
font-size: 1.5rem;
|
|
1017
|
+
width: 2rem;
|
|
1018
|
+
text-align: center;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
.feature-text h4 {
|
|
1022
|
+
margin: 0 0 0.25rem 0;
|
|
1023
|
+
font-size: 1rem;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.feature-text p {
|
|
1027
|
+
margin: 0;
|
|
1028
|
+
font-size: 0.875rem;
|
|
1029
|
+
opacity: 0.8;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
.custom-footer {
|
|
1033
|
+
padding: 2rem;
|
|
1034
|
+
background: rgba(255, 255, 255, 0.1);
|
|
1035
|
+
backdrop-filter: blur(10px);
|
|
1036
|
+
display: flex;
|
|
1037
|
+
justify-content: center;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
.custom-close {
|
|
1041
|
+
background: rgba(255, 255, 255, 0.2);
|
|
1042
|
+
color: white;
|
|
1043
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
1044
|
+
padding: 0.75rem 2rem;
|
|
1045
|
+
border-radius: 0.5rem;
|
|
1046
|
+
font-weight: 600;
|
|
1047
|
+
transition: all 0.2s;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
.custom-close:hover {
|
|
1051
|
+
background: rgba(255, 255, 255, 0.3);
|
|
1052
|
+
transform: translateY(-1px);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/* Override sidebar CSS variables */
|
|
1056
|
+
:global(.custom-sidebar) {
|
|
1057
|
+
--sidebar-bg: transparent;
|
|
1058
|
+
--sidebar-backdrop-dim-bg: rgba(0, 0, 0, 0.8);
|
|
1059
|
+
}
|
|
1060
|
+
</style>
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
### Mobile Action Sheet
|
|
1064
|
+
|
|
1065
|
+
```vue
|
|
1066
|
+
<script setup lang="ts">
|
|
1067
|
+
import { ref } from "vue";
|
|
1068
|
+
import { Sidebar, Button } from "@umbra-ui/core";
|
|
1069
|
+
|
|
1070
|
+
const isActionSheetOpen = ref(false);
|
|
1071
|
+
|
|
1072
|
+
const actions = [
|
|
1073
|
+
{ id: "edit", label: "Edit", icon: "✏️", color: "#007bff" },
|
|
1074
|
+
{ id: "share", label: "Share", icon: "📤", color: "#28a745" },
|
|
1075
|
+
{ id: "download", label: "Download", icon: "⬇️", color: "#6c757d" },
|
|
1076
|
+
{ id: "delete", label: "Delete", icon: "🗑️", color: "#dc3545" },
|
|
1077
|
+
];
|
|
1078
|
+
|
|
1079
|
+
const handleAction = (actionId: string) => {
|
|
1080
|
+
console.log("Action selected:", actionId);
|
|
1081
|
+
isActionSheetOpen.value = false;
|
|
1082
|
+
};
|
|
1083
|
+
</script>
|
|
1084
|
+
|
|
1085
|
+
<template>
|
|
1086
|
+
<div class="action-sheet">
|
|
1087
|
+
<h3>Mobile Action Sheet</h3>
|
|
1088
|
+
<p>
|
|
1089
|
+
This example shows a mobile-style action sheet using the bottom sidebar:
|
|
1090
|
+
</p>
|
|
1091
|
+
|
|
1092
|
+
<Button @click="isActionSheetOpen = true">Show Actions</Button>
|
|
1093
|
+
|
|
1094
|
+
<Sidebar
|
|
1095
|
+
v-model="isActionSheetOpen"
|
|
1096
|
+
side="bottom"
|
|
1097
|
+
height="auto"
|
|
1098
|
+
min-height="200px"
|
|
1099
|
+
max-height="400px"
|
|
1100
|
+
:dismiss-on-backdrop="true"
|
|
1101
|
+
>
|
|
1102
|
+
<div class="action-sheet-content">
|
|
1103
|
+
<div class="action-sheet-header">
|
|
1104
|
+
<h3>Choose an Action</h3>
|
|
1105
|
+
<p>Select what you'd like to do with this item</p>
|
|
1106
|
+
</div>
|
|
1107
|
+
|
|
1108
|
+
<div class="action-list">
|
|
1109
|
+
<button
|
|
1110
|
+
v-for="action in actions"
|
|
1111
|
+
:key="action.id"
|
|
1112
|
+
class="action-item"
|
|
1113
|
+
:style="{ '--action-color': action.color }"
|
|
1114
|
+
@click="handleAction(action.id)"
|
|
1115
|
+
>
|
|
1116
|
+
<span class="action-icon">{{ action.icon }}</span>
|
|
1117
|
+
<span class="action-label">{{ action.label }}</span>
|
|
1118
|
+
</button>
|
|
1119
|
+
</div>
|
|
1120
|
+
|
|
1121
|
+
<div class="action-sheet-footer">
|
|
1122
|
+
<Button
|
|
1123
|
+
@click="isActionSheetOpen = false"
|
|
1124
|
+
variant="secondary"
|
|
1125
|
+
class="cancel-btn"
|
|
1126
|
+
>
|
|
1127
|
+
Cancel
|
|
1128
|
+
</Button>
|
|
1129
|
+
</div>
|
|
1130
|
+
</div>
|
|
1131
|
+
</Sidebar>
|
|
1132
|
+
</div>
|
|
1133
|
+
</template>
|
|
1134
|
+
|
|
1135
|
+
<style module>
|
|
1136
|
+
.action-sheet {
|
|
1137
|
+
padding: 2rem;
|
|
1138
|
+
border: 1px solid #e0e0e0;
|
|
1139
|
+
border-radius: 0.5rem;
|
|
1140
|
+
max-width: 400px;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
.action-sheet-content {
|
|
1144
|
+
padding: 1rem;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.action-sheet-header {
|
|
1148
|
+
text-align: center;
|
|
1149
|
+
padding: 1rem 0 2rem;
|
|
1150
|
+
border-bottom: 1px solid #e0e0e0;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
.action-sheet-header h3 {
|
|
1154
|
+
margin: 0 0 0.5rem 0;
|
|
1155
|
+
color: #333;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
.action-sheet-header p {
|
|
1159
|
+
margin: 0;
|
|
1160
|
+
color: #666;
|
|
1161
|
+
font-size: 0.875rem;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
.action-list {
|
|
1165
|
+
padding: 1rem 0;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
.action-item {
|
|
1169
|
+
display: flex;
|
|
1170
|
+
align-items: center;
|
|
1171
|
+
gap: 1rem;
|
|
1172
|
+
width: 100%;
|
|
1173
|
+
padding: 1rem;
|
|
1174
|
+
border: none;
|
|
1175
|
+
background: none;
|
|
1176
|
+
text-align: left;
|
|
1177
|
+
cursor: pointer;
|
|
1178
|
+
transition: background-color 0.2s;
|
|
1179
|
+
border-radius: 0.5rem;
|
|
1180
|
+
margin-bottom: 0.5rem;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
.action-item:hover {
|
|
1184
|
+
background-color: #f8f9fa;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
.action-item:last-child {
|
|
1188
|
+
margin-bottom: 0;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
.action-icon {
|
|
1192
|
+
font-size: 1.25rem;
|
|
1193
|
+
width: 2rem;
|
|
1194
|
+
text-align: center;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
.action-label {
|
|
1198
|
+
font-weight: 500;
|
|
1199
|
+
color: var(--action-color, #333);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
.action-sheet-footer {
|
|
1203
|
+
padding: 1rem 0 0;
|
|
1204
|
+
border-top: 1px solid #e0e0e0;
|
|
1205
|
+
text-align: center;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.cancel-btn {
|
|
1209
|
+
width: 100%;
|
|
1210
|
+
}
|
|
1211
|
+
</style>
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
## Technical Notes
|
|
1215
|
+
|
|
1216
|
+
- Sidebar provides a comprehensive overlay system with smooth animations and flexible positioning
|
|
1217
|
+
- GSAP animations ensure smooth, performant transitions with hardware acceleration
|
|
1218
|
+
- Teleport usage ensures proper z-index layering and positioning outside component tree
|
|
1219
|
+
- Body scroll locking prevents background scrolling when sidebar is open
|
|
1220
|
+
- Safe area support handles mobile device notches and home indicators
|
|
1221
|
+
- Directional shadows adapt to sidebar position for better visual depth
|
|
1222
|
+
- Custom scrollbar styling provides better visual consistency
|
|
1223
|
+
- Backdrop blur effects create modern, iOS-like appearance
|
|
1224
|
+
- Keyboard navigation includes Escape key support for accessibility
|
|
1225
|
+
- TypeScript interfaces ensure type safety for all props and events
|
|
1226
|
+
- CSS custom properties enable easy theming and customization
|
|
1227
|
+
- Responsive design adapts to different screen sizes and orientations
|
|
1228
|
+
- Animation cleanup prevents memory leaks and ensures smooth performance
|