Complete 1 fase docs components
This commit is contained in:
918
docs/components/drawer.md
Normal file
918
docs/components/drawer.md
Normal file
@@ -0,0 +1,918 @@
|
||||
# Drawer
|
||||
|
||||
Drawer component for creating off-canvas side panels with overlay and toggle functionality.
|
||||
|
||||
## Tag
|
||||
|
||||
`Drawer`
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| :----------- | :--------------------------- | :---------- | :----------------------------------------------- |
|
||||
| `id` | `string` | Required | Unique identifier for the drawer |
|
||||
| `open` | `boolean \| Signal<boolean>` | `false` | Drawer open state |
|
||||
| `side` | `VNode` | Required | Content to display in the drawer panel |
|
||||
| `content` | `VNode` | Required | Main page content |
|
||||
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
|
||||
|
||||
## Live Examples
|
||||
|
||||
### Basic Drawer
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-basic" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const BasicDemo = () => {
|
||||
const isOpen = $(false);
|
||||
|
||||
return Drawer({
|
||||
id: 'basic-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'p-4' }, [
|
||||
Div({ class: 'text-lg font-bold mb-4' }, 'Menu'),
|
||||
Div({ class: 'flex flex-col gap-2' }, [
|
||||
Button({ class: 'btn btn-ghost justify-start' }, 'Home'),
|
||||
Button({ class: 'btn btn-ghost justify-start' }, 'About'),
|
||||
Button({ class: 'btn btn-ghost justify-start' }, 'Contact')
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4 text-center' }, [
|
||||
Button({
|
||||
class: 'btn btn-primary',
|
||||
onclick: () => isOpen(true)
|
||||
}, 'Open Drawer')
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(BasicDemo, '#demo-basic');
|
||||
```
|
||||
|
||||
### Navigation Drawer
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-nav" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const NavDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const activePage = $('home');
|
||||
|
||||
const pages = {
|
||||
home: 'Welcome to the Home Page!',
|
||||
about: 'About Us - Learn more about our company',
|
||||
services: 'Our Services - What we offer',
|
||||
contact: 'Contact Us - Get in touch'
|
||||
};
|
||||
|
||||
return Drawer({
|
||||
id: 'nav-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'p-4 w-64' }, [
|
||||
Div({ class: 'text-xl font-bold mb-6' }, 'MyApp'),
|
||||
Div({ class: 'flex flex-col gap-1' }, [
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'home' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('home');
|
||||
isOpen(false);
|
||||
}
|
||||
}, '🏠 Home'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'about' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('about');
|
||||
isOpen(false);
|
||||
}
|
||||
}, 'ℹ️ About'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'services' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('services');
|
||||
isOpen(false);
|
||||
}
|
||||
}, '⚙️ Services'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'contact' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('contact');
|
||||
isOpen(false);
|
||||
}
|
||||
}, '📧 Contact')
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4' }, [
|
||||
Div({ class: 'flex justify-between items-center mb-4' }, [
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle',
|
||||
onclick: () => isOpen(true)
|
||||
}, '☰'),
|
||||
Span({ class: 'text-lg font-bold' }, 'MyApp')
|
||||
]),
|
||||
Div({ class: 'card bg-base-200 shadow-lg' }, [
|
||||
Div({ class: 'card-body' }, [
|
||||
Div({ class: 'text-2xl font-bold mb-2' }, () => activePage().charAt(0).toUpperCase() + activePage().slice(1)),
|
||||
Div({ class: 'text-lg' }, () => pages[activePage()])
|
||||
])
|
||||
])
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(NavDrawer, '#demo-nav');
|
||||
```
|
||||
|
||||
### Settings Drawer
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-settings" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const SettingsDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const darkMode = $(false);
|
||||
const notifications = $(true);
|
||||
const autoSave = $(false);
|
||||
|
||||
return Drawer({
|
||||
id: 'settings-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'p-4 w-80' }, [
|
||||
Div({ class: 'flex justify-between items-center mb-6' }, [
|
||||
Span({ class: 'text-xl font-bold' }, 'Settings'),
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle btn-sm',
|
||||
onclick: () => isOpen(false)
|
||||
}, '✕')
|
||||
]),
|
||||
Div({ class: 'flex flex-col gap-4' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({}, 'Dark Mode'),
|
||||
Swap({
|
||||
value: darkMode,
|
||||
on: "🌙",
|
||||
off: "☀️",
|
||||
onclick: () => darkMode(!darkMode())
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({}, 'Notifications'),
|
||||
Swap({
|
||||
value: notifications,
|
||||
on: "🔔",
|
||||
off: "🔕",
|
||||
onclick: () => notifications(!notifications())
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({}, 'Auto Save'),
|
||||
Swap({
|
||||
value: autoSave,
|
||||
on: "✅",
|
||||
off: "⭕",
|
||||
onclick: () => autoSave(!autoSave())
|
||||
})
|
||||
])
|
||||
]),
|
||||
Div({ class: 'divider my-4' }),
|
||||
Div({ class: 'flex gap-2' }, [
|
||||
Button({
|
||||
class: 'btn btn-primary flex-1',
|
||||
onclick: () => {
|
||||
isOpen(false);
|
||||
Toast('Settings saved!', 'alert-success', 2000);
|
||||
}
|
||||
}, 'Save'),
|
||||
Button({
|
||||
class: 'btn btn-ghost flex-1',
|
||||
onclick: () => isOpen(false)
|
||||
}, 'Cancel')
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-lg font-bold' }, 'Dashboard'),
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle',
|
||||
onclick: () => isOpen(true)
|
||||
}, '⚙️')
|
||||
]),
|
||||
Div({ class: 'mt-4 grid grid-cols-2 gap-4' }, [
|
||||
Div({ class: 'stat bg-base-200 rounded-lg p-4' }, [
|
||||
Div({ class: 'stat-title' }, 'Users'),
|
||||
Div({ class: 'stat-value' }, '1,234')
|
||||
]),
|
||||
Div({ class: 'stat bg-base-200 rounded-lg p-4' }, [
|
||||
Div({ class: 'stat-title' }, 'Revenue'),
|
||||
Div({ class: 'stat-value' }, '$45K')
|
||||
])
|
||||
])
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(SettingsDrawer, '#demo-settings');
|
||||
```
|
||||
|
||||
### Cart Drawer
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-cart" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const CartDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const cart = $([
|
||||
{ id: 1, name: 'Product 1', price: 29, quantity: 2 },
|
||||
{ id: 2, name: 'Product 2', price: 49, quantity: 1 }
|
||||
]);
|
||||
|
||||
const updateQuantity = (id, delta) => {
|
||||
cart(cart().map(item => {
|
||||
if (item.id === id) {
|
||||
const newQty = Math.max(0, item.quantity + delta);
|
||||
return newQty === 0 ? null : { ...item, quantity: newQty };
|
||||
}
|
||||
return item;
|
||||
}).filter(Boolean));
|
||||
};
|
||||
|
||||
const total = () => cart().reduce((sum, item) => sum + (item.price * item.quantity), 0);
|
||||
|
||||
return Drawer({
|
||||
id: 'cart-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'flex flex-col h-full' }, [
|
||||
Div({ class: 'p-4 border-b border-base-300' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-xl font-bold' }, `Cart (${cart().length} items)`),
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle btn-sm',
|
||||
onclick: () => isOpen(false)
|
||||
}, '✕')
|
||||
])
|
||||
]),
|
||||
Div({ class: 'flex-1 overflow-y-auto p-4' }, cart().length === 0
|
||||
? Div({ class: 'text-center text-gray-500 mt-8' }, 'Your cart is empty')
|
||||
: Div({ class: 'flex flex-col gap-3' }, cart().map(item =>
|
||||
Div({ class: 'flex gap-3 items-center p-2 bg-base-200 rounded-lg' }, [
|
||||
Div({ class: 'flex-1' }, [
|
||||
Div({ class: 'font-medium' }, item.name),
|
||||
Div({ class: 'text-sm' }, `$${item.price} each`)
|
||||
]),
|
||||
Div({ class: 'flex items-center gap-2' }, [
|
||||
Button({
|
||||
class: 'btn btn-xs btn-circle',
|
||||
onclick: () => updateQuantity(item.id, -1)
|
||||
}, '-'),
|
||||
Span({ class: 'w-8 text-center' }, item.quantity),
|
||||
Button({
|
||||
class: 'btn btn-xs btn-circle',
|
||||
onclick: () => updateQuantity(item.id, 1)
|
||||
}, '+')
|
||||
]),
|
||||
Span({ class: 'font-bold w-16 text-right' }, `$${item.price * item.quantity}`)
|
||||
])
|
||||
))
|
||||
),
|
||||
Div({ class: 'p-4 border-t border-base-300' }, [
|
||||
Div({ class: 'flex justify-between items-center mb-4' }, [
|
||||
Span({ class: 'font-bold' }, 'Total'),
|
||||
Span({ class: 'text-xl font-bold' }, () => `$${total()}`)
|
||||
]),
|
||||
Button({
|
||||
class: 'btn btn-primary w-full',
|
||||
onclick: () => {
|
||||
isOpen(false);
|
||||
Toast('Checkout initiated!', 'alert-success', 2000);
|
||||
},
|
||||
disabled: () => cart().length === 0
|
||||
}, 'Checkout')
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-lg font-bold' }, 'Store'),
|
||||
Button({
|
||||
class: 'btn btn-primary',
|
||||
onclick: () => isOpen(true)
|
||||
}, () => `🛒 Cart (${cart().length})`)
|
||||
]),
|
||||
Div({ class: 'mt-4 grid grid-cols-2 gap-4' }, [
|
||||
Button({
|
||||
class: 'btn btn-outline h-32 flex flex-col',
|
||||
onclick: () => {
|
||||
cart([...cart(), { id: Date.now(), name: 'New Product', price: 39, quantity: 1 }]);
|
||||
Toast('Added to cart!', 'alert-success', 1500);
|
||||
}
|
||||
}, ['📦', 'Add to Cart'])
|
||||
])
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(CartDrawer, '#demo-cart');
|
||||
```
|
||||
|
||||
### Responsive Drawer
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-responsive" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const ResponsiveDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const activePage = $('home');
|
||||
|
||||
const MenuItems = () => Div({ class: 'flex flex-col gap-1 p-4' }, [
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'home' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('home');
|
||||
if (window.innerWidth < 1024) isOpen(false);
|
||||
}
|
||||
}, '🏠 Home'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'analytics' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('analytics');
|
||||
if (window.innerWidth < 1024) isOpen(false);
|
||||
}
|
||||
}, '📊 Analytics'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'settings' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('settings');
|
||||
if (window.innerWidth < 1024) isOpen(false);
|
||||
}
|
||||
}, '⚙️ Settings')
|
||||
]);
|
||||
|
||||
return Drawer({
|
||||
id: 'responsive-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'w-64' }, [
|
||||
Div({ class: 'text-xl font-bold p-4 border-b border-base-300' }, 'Menu'),
|
||||
MenuItems()
|
||||
]),
|
||||
content: Div({ class: 'flex' }, [
|
||||
Div({ class: 'hidden lg:block w-64 border-r border-base-300' }, [MenuItems()]),
|
||||
Div({ class: 'flex-1 p-4' }, [
|
||||
Div({ class: 'flex justify-between items-center lg:hidden mb-4' }, [
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle',
|
||||
onclick: () => isOpen(true)
|
||||
}, '☰'),
|
||||
Span({ class: 'text-lg font-bold' }, 'MyApp')
|
||||
]),
|
||||
Div({ class: 'card bg-base-200' }, [
|
||||
Div({ class: 'card-body' }, [
|
||||
Div({ class: 'text-2xl font-bold' }, () => activePage().charAt(0).toUpperCase() + activePage().slice(1)),
|
||||
Div({}, 'Content area. On desktop, the menu is always visible on the left.')
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(ResponsiveDrawer, '#demo-responsive');
|
||||
```
|
||||
|
||||
### Form Drawer
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-form" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const FormDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const name = $('');
|
||||
const email = $('');
|
||||
const message = $('');
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (name() && email() && message()) {
|
||||
Toast('Message sent!', 'alert-success', 2000);
|
||||
isOpen(false);
|
||||
name('');
|
||||
email('');
|
||||
message('');
|
||||
} else {
|
||||
Toast('Please fill all fields', 'alert-warning', 2000);
|
||||
}
|
||||
};
|
||||
|
||||
return Drawer({
|
||||
id: 'form-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'p-4 w-96' }, [
|
||||
Div({ class: 'flex justify-between items-center mb-4' }, [
|
||||
Span({ class: 'text-xl font-bold' }, 'Contact Us'),
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle btn-sm',
|
||||
onclick: () => isOpen(false)
|
||||
}, '✕')
|
||||
]),
|
||||
Div({ class: 'flex flex-col gap-4' }, [
|
||||
Input({
|
||||
label: 'Name',
|
||||
value: name,
|
||||
placeholder: 'Your name',
|
||||
oninput: (e) => name(e.target.value)
|
||||
}),
|
||||
Input({
|
||||
label: 'Email',
|
||||
type: 'email',
|
||||
value: email,
|
||||
placeholder: 'your@email.com',
|
||||
oninput: (e) => email(e.target.value)
|
||||
}),
|
||||
Div({ class: 'form-control' }, [
|
||||
Span({ class: 'label-text mb-1' }, 'Message'),
|
||||
$html('textarea', {
|
||||
class: 'textarea textarea-bordered h-24',
|
||||
placeholder: 'Your message',
|
||||
value: message,
|
||||
oninput: (e) => message(e.target.value)
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex gap-2 mt-2' }, [
|
||||
Button({
|
||||
class: 'btn btn-primary flex-1',
|
||||
onclick: handleSubmit
|
||||
}, 'Send'),
|
||||
Button({
|
||||
class: 'btn btn-ghost flex-1',
|
||||
onclick: () => isOpen(false)
|
||||
}, 'Cancel')
|
||||
])
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4 text-center' }, [
|
||||
Button({
|
||||
class: 'btn btn-primary',
|
||||
onclick: () => isOpen(true)
|
||||
}, 'Contact Us')
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(FormDrawer, '#demo-form');
|
||||
```
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const initDrawerExamples = () => {
|
||||
|
||||
// 1. Basic Drawer
|
||||
const basicTarget = document.querySelector('#demo-basic');
|
||||
if (basicTarget && !basicTarget.hasChildNodes()) {
|
||||
const BasicDemo = () => {
|
||||
const isOpen = $(false);
|
||||
|
||||
return Drawer({
|
||||
id: 'basic-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'p-4' }, [
|
||||
Div({ class: 'text-lg font-bold mb-4' }, 'Menu'),
|
||||
Div({ class: 'flex flex-col gap-2' }, [
|
||||
Button({ class: 'btn btn-ghost justify-start' }, 'Home'),
|
||||
Button({ class: 'btn btn-ghost justify-start' }, 'About'),
|
||||
Button({ class: 'btn btn-ghost justify-start' }, 'Contact')
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4 text-center' }, [
|
||||
Button({
|
||||
class: 'btn btn-primary',
|
||||
onclick: () => isOpen(true)
|
||||
}, 'Open Drawer')
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(BasicDemo, basicTarget);
|
||||
}
|
||||
|
||||
// 2. Navigation Drawer
|
||||
const navTarget = document.querySelector('#demo-nav');
|
||||
if (navTarget && !navTarget.hasChildNodes()) {
|
||||
const NavDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const activePage = $('home');
|
||||
|
||||
const pages = {
|
||||
home: 'Welcome to the Home Page!',
|
||||
about: 'About Us - Learn more about our company',
|
||||
services: 'Our Services - What we offer',
|
||||
contact: 'Contact Us - Get in touch'
|
||||
};
|
||||
|
||||
return Drawer({
|
||||
id: 'nav-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'p-4 w-64' }, [
|
||||
Div({ class: 'text-xl font-bold mb-6' }, 'MyApp'),
|
||||
Div({ class: 'flex flex-col gap-1' }, [
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'home' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('home');
|
||||
isOpen(false);
|
||||
}
|
||||
}, '🏠 Home'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'about' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('about');
|
||||
isOpen(false);
|
||||
}
|
||||
}, 'ℹ️ About'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'services' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('services');
|
||||
isOpen(false);
|
||||
}
|
||||
}, '⚙️ Services'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'contact' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('contact');
|
||||
isOpen(false);
|
||||
}
|
||||
}, '📧 Contact')
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4' }, [
|
||||
Div({ class: 'flex justify-between items-center mb-4' }, [
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle',
|
||||
onclick: () => isOpen(true)
|
||||
}, '☰'),
|
||||
Span({ class: 'text-lg font-bold' }, 'MyApp')
|
||||
]),
|
||||
Div({ class: 'card bg-base-200 shadow-lg' }, [
|
||||
Div({ class: 'card-body' }, [
|
||||
Div({ class: 'text-2xl font-bold mb-2' }, () => activePage().charAt(0).toUpperCase() + activePage().slice(1)),
|
||||
Div({ class: 'text-lg' }, () => pages[activePage()])
|
||||
])
|
||||
])
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(NavDrawer, navTarget);
|
||||
}
|
||||
|
||||
// 3. Settings Drawer
|
||||
const settingsTarget = document.querySelector('#demo-settings');
|
||||
if (settingsTarget && !settingsTarget.hasChildNodes()) {
|
||||
const SettingsDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const darkMode = $(false);
|
||||
const notifications = $(true);
|
||||
const autoSave = $(false);
|
||||
|
||||
return Drawer({
|
||||
id: 'settings-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'p-4 w-80' }, [
|
||||
Div({ class: 'flex justify-between items-center mb-6' }, [
|
||||
Span({ class: 'text-xl font-bold' }, 'Settings'),
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle btn-sm',
|
||||
onclick: () => isOpen(false)
|
||||
}, '✕')
|
||||
]),
|
||||
Div({ class: 'flex flex-col gap-4' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({}, 'Dark Mode'),
|
||||
Swap({
|
||||
value: darkMode,
|
||||
on: "🌙",
|
||||
off: "☀️",
|
||||
onclick: () => darkMode(!darkMode())
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({}, 'Notifications'),
|
||||
Swap({
|
||||
value: notifications,
|
||||
on: "🔔",
|
||||
off: "🔕",
|
||||
onclick: () => notifications(!notifications())
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({}, 'Auto Save'),
|
||||
Swap({
|
||||
value: autoSave,
|
||||
on: "✅",
|
||||
off: "⭕",
|
||||
onclick: () => autoSave(!autoSave())
|
||||
})
|
||||
])
|
||||
]),
|
||||
Div({ class: 'divider my-4' }),
|
||||
Div({ class: 'flex gap-2' }, [
|
||||
Button({
|
||||
class: 'btn btn-primary flex-1',
|
||||
onclick: () => {
|
||||
isOpen(false);
|
||||
Toast('Settings saved!', 'alert-success', 2000);
|
||||
}
|
||||
}, 'Save'),
|
||||
Button({
|
||||
class: 'btn btn-ghost flex-1',
|
||||
onclick: () => isOpen(false)
|
||||
}, 'Cancel')
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-lg font-bold' }, 'Dashboard'),
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle',
|
||||
onclick: () => isOpen(true)
|
||||
}, '⚙️')
|
||||
]),
|
||||
Div({ class: 'mt-4 grid grid-cols-2 gap-4' }, [
|
||||
Div({ class: 'stat bg-base-200 rounded-lg p-4' }, [
|
||||
Div({ class: 'stat-title' }, 'Users'),
|
||||
Div({ class: 'stat-value' }, '1,234')
|
||||
]),
|
||||
Div({ class: 'stat bg-base-200 rounded-lg p-4' }, [
|
||||
Div({ class: 'stat-title' }, 'Revenue'),
|
||||
Div({ class: 'stat-value' }, '$45K')
|
||||
])
|
||||
])
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(SettingsDrawer, settingsTarget);
|
||||
}
|
||||
|
||||
// 4. Cart Drawer
|
||||
const cartTarget = document.querySelector('#demo-cart');
|
||||
if (cartTarget && !cartTarget.hasChildNodes()) {
|
||||
const CartDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const cart = $([
|
||||
{ id: 1, name: 'Product 1', price: 29, quantity: 2 },
|
||||
{ id: 2, name: 'Product 2', price: 49, quantity: 1 }
|
||||
]);
|
||||
|
||||
const updateQuantity = (id, delta) => {
|
||||
cart(cart().map(item => {
|
||||
if (item.id === id) {
|
||||
const newQty = Math.max(0, item.quantity + delta);
|
||||
return newQty === 0 ? null : { ...item, quantity: newQty };
|
||||
}
|
||||
return item;
|
||||
}).filter(Boolean));
|
||||
};
|
||||
|
||||
const total = () => cart().reduce((sum, item) => sum + (item.price * item.quantity), 0);
|
||||
|
||||
return Drawer({
|
||||
id: 'cart-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'flex flex-col h-full' }, [
|
||||
Div({ class: 'p-4 border-b border-base-300' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-xl font-bold' }, `Cart (${cart().length} items)`),
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle btn-sm',
|
||||
onclick: () => isOpen(false)
|
||||
}, '✕')
|
||||
])
|
||||
]),
|
||||
Div({ class: 'flex-1 overflow-y-auto p-4' }, cart().length === 0
|
||||
? Div({ class: 'text-center text-gray-500 mt-8' }, 'Your cart is empty')
|
||||
: Div({ class: 'flex flex-col gap-3' }, cart().map(item =>
|
||||
Div({ class: 'flex gap-3 items-center p-2 bg-base-200 rounded-lg' }, [
|
||||
Div({ class: 'flex-1' }, [
|
||||
Div({ class: 'font-medium' }, item.name),
|
||||
Div({ class: 'text-sm' }, `$${item.price} each`)
|
||||
]),
|
||||
Div({ class: 'flex items-center gap-2' }, [
|
||||
Button({
|
||||
class: 'btn btn-xs btn-circle',
|
||||
onclick: () => updateQuantity(item.id, -1)
|
||||
}, '-'),
|
||||
Span({ class: 'w-8 text-center' }, item.quantity),
|
||||
Button({
|
||||
class: 'btn btn-xs btn-circle',
|
||||
onclick: () => updateQuantity(item.id, 1)
|
||||
}, '+')
|
||||
]),
|
||||
Span({ class: 'font-bold w-16 text-right' }, `$${item.price * item.quantity}`)
|
||||
])
|
||||
))
|
||||
),
|
||||
Div({ class: 'p-4 border-t border-base-300' }, [
|
||||
Div({ class: 'flex justify-between items-center mb-4' }, [
|
||||
Span({ class: 'font-bold' }, 'Total'),
|
||||
Span({ class: 'text-xl font-bold' }, () => `$${total()}`)
|
||||
]),
|
||||
Button({
|
||||
class: 'btn btn-primary w-full',
|
||||
onclick: () => {
|
||||
isOpen(false);
|
||||
Toast('Checkout initiated!', 'alert-success', 2000);
|
||||
},
|
||||
disabled: () => cart().length === 0
|
||||
}, 'Checkout')
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-lg font-bold' }, 'Store'),
|
||||
Button({
|
||||
class: 'btn btn-primary',
|
||||
onclick: () => isOpen(true)
|
||||
}, () => `🛒 Cart (${cart().length})`)
|
||||
]),
|
||||
Div({ class: 'mt-4 grid grid-cols-2 gap-4' }, [
|
||||
Button({
|
||||
class: 'btn btn-outline h-32 flex flex-col',
|
||||
onclick: () => {
|
||||
cart([...cart(), { id: Date.now(), name: 'New Product', price: 39, quantity: 1 }]);
|
||||
Toast('Added to cart!', 'alert-success', 1500);
|
||||
}
|
||||
}, ['📦', 'Add to Cart'])
|
||||
])
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(CartDrawer, cartTarget);
|
||||
}
|
||||
|
||||
// 5. Responsive Drawer
|
||||
const responsiveTarget = document.querySelector('#demo-responsive');
|
||||
if (responsiveTarget && !responsiveTarget.hasChildNodes()) {
|
||||
const ResponsiveDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const activePage = $('home');
|
||||
|
||||
const MenuItems = () => Div({ class: 'flex flex-col gap-1 p-4' }, [
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'home' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('home');
|
||||
if (window.innerWidth < 1024) isOpen(false);
|
||||
}
|
||||
}, '🏠 Home'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'analytics' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('analytics');
|
||||
if (window.innerWidth < 1024) isOpen(false);
|
||||
}
|
||||
}, '📊 Analytics'),
|
||||
Button({
|
||||
class: `btn btn-ghost justify-start ${activePage() === 'settings' ? 'btn-active' : ''}`,
|
||||
onclick: () => {
|
||||
activePage('settings');
|
||||
if (window.innerWidth < 1024) isOpen(false);
|
||||
}
|
||||
}, '⚙️ Settings')
|
||||
]);
|
||||
|
||||
return Drawer({
|
||||
id: 'responsive-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'w-64' }, [
|
||||
Div({ class: 'text-xl font-bold p-4 border-b border-base-300' }, 'Menu'),
|
||||
MenuItems()
|
||||
]),
|
||||
content: Div({ class: 'flex' }, [
|
||||
Div({ class: 'hidden lg:block w-64 border-r border-base-300' }, [MenuItems()]),
|
||||
Div({ class: 'flex-1 p-4' }, [
|
||||
Div({ class: 'flex justify-between items-center lg:hidden mb-4' }, [
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle',
|
||||
onclick: () => isOpen(true)
|
||||
}, '☰'),
|
||||
Span({ class: 'text-lg font-bold' }, 'MyApp')
|
||||
]),
|
||||
Div({ class: 'card bg-base-200' }, [
|
||||
Div({ class: 'card-body' }, [
|
||||
Div({ class: 'text-2xl font-bold' }, () => activePage().charAt(0).toUpperCase() + activePage().slice(1)),
|
||||
Div({}, 'Content area. On desktop, the menu is always visible on the left.')
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(ResponsiveDrawer, responsiveTarget);
|
||||
}
|
||||
|
||||
// 6. Form Drawer
|
||||
const formTarget = document.querySelector('#demo-form');
|
||||
if (formTarget && !formTarget.hasChildNodes()) {
|
||||
const FormDrawer = () => {
|
||||
const isOpen = $(false);
|
||||
const name = $('');
|
||||
const email = $('');
|
||||
const message = $('');
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (name() && email() && message()) {
|
||||
Toast('Message sent!', 'alert-success', 2000);
|
||||
isOpen(false);
|
||||
name('');
|
||||
email('');
|
||||
message('');
|
||||
} else {
|
||||
Toast('Please fill all fields', 'alert-warning', 2000);
|
||||
}
|
||||
};
|
||||
|
||||
return Drawer({
|
||||
id: 'form-drawer',
|
||||
open: isOpen,
|
||||
side: Div({ class: 'p-4 w-96' }, [
|
||||
Div({ class: 'flex justify-between items-center mb-4' }, [
|
||||
Span({ class: 'text-xl font-bold' }, 'Contact Us'),
|
||||
Button({
|
||||
class: 'btn btn-ghost btn-circle btn-sm',
|
||||
onclick: () => isOpen(false)
|
||||
}, '✕')
|
||||
]),
|
||||
Div({ class: 'flex flex-col gap-4' }, [
|
||||
Input({
|
||||
label: 'Name',
|
||||
value: name,
|
||||
placeholder: 'Your name',
|
||||
oninput: (e) => name(e.target.value)
|
||||
}),
|
||||
Input({
|
||||
label: 'Email',
|
||||
type: 'email',
|
||||
value: email,
|
||||
placeholder: 'your@email.com',
|
||||
oninput: (e) => email(e.target.value)
|
||||
}),
|
||||
Div({ class: 'form-control' }, [
|
||||
Span({ class: 'label-text mb-1' }, 'Message'),
|
||||
$html('textarea', {
|
||||
class: 'textarea textarea-bordered h-24',
|
||||
placeholder: 'Your message',
|
||||
value: message,
|
||||
oninput: (e) => message(e.target.value)
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex gap-2 mt-2' }, [
|
||||
Button({
|
||||
class: 'btn btn-primary flex-1',
|
||||
onclick: handleSubmit
|
||||
}, 'Send'),
|
||||
Button({
|
||||
class: 'btn btn-ghost flex-1',
|
||||
onclick: () => isOpen(false)
|
||||
}, 'Cancel')
|
||||
])
|
||||
])
|
||||
]),
|
||||
content: Div({ class: 'p-4 text-center' }, [
|
||||
Button({
|
||||
class: 'btn btn-primary',
|
||||
onclick: () => isOpen(true)
|
||||
}, 'Contact Us')
|
||||
])
|
||||
});
|
||||
};
|
||||
$mount(FormDrawer, formTarget);
|
||||
}
|
||||
};
|
||||
|
||||
initDrawerExamples();
|
||||
|
||||
if (window.$docsify) {
|
||||
window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => {
|
||||
hook.doneEach(initDrawerExamples);
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user