diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..32a11cd3 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,169 @@ +# EOWeb – Copilot Instructions + +EOWeb is a browser-based client for Endless Online (classic MMORPG, 0.0.28 protocol). It connects to game servers over WebSocket and renders the world using Pixi.js, with a Preact UI for menus/dialogs. + +## Commands + +```sh +pnpm dev # Vite dev server (port 3000) +pnpm build # tsc && vite build → dist/ +pnpm lint # biome check . +pnpm format # biome check --write . +``` + +There is no test suite. + +## Architecture + +The app has two rendering layers that serve different purposes: + +- **Preact UI** (`src/ui/`) — overlaid on the canvas at all times. For pre-game screens (main menu, login, character select, etc.) it renders full-screen containers. In the `InGame` state it renders the in-game overlay: HUD, chat, hotbar, dialogs, touch controls, etc. Conditionally rendered based on `GameState` enum. +- **Pixi.js** (`src/map.ts`, `src/atlas.ts`, `src/render/`) — handles all in-game rendering: map tiles, characters, NPCs, animations, effects. + +The central object is `Client` (`src/client/client.ts`). It owns all game state, every controller, the packet bus, the Pixi.js `Application`, and the `MapRenderer`. Nearly everything receives a `Client` reference. + +### Data flow + +``` +WebSocket → PacketBus → handlers/ → client state / emit events → UI / Pixi render +``` + +- **`src/bus.ts` (`PacketBus`)** — manages the WebSocket connection and dispatches incoming packets by `PacketFamily + PacketAction` to registered handler functions. +- **`src/handlers/`** — one file per packet family. Each exports a `registerXxxHandlers(client: Client)` function that calls `client.bus.registerPacketHandler(family, action, fn)`. All are registered at startup via `registerAllHandlers(client)`. +- **`src/controllers/`** — encapsulate client-side logic for sending packets and managing related state (e.g., `MovementController`, `InventoryController`). Each takes `Client` in its constructor. +- **`src/client/events.ts`** — typed `ClientEvents` map used by the mitt emitter on `Client`. Most handlers still call `client.emit(...)` and UI subscribes via `client.on(...)`, but newer controllers expose typed `subscribe*` methods (e.g. `subscribeConfirm`, `subscribePaperdollOpened`) as part of an ongoing refactor away from `ClientEvents`. + +### Persistence + +`src/db.ts` wraps IndexedDB (via `idb`) with three stores: +- `pubs` — serialized EIF/ENF/ECF/ESF pub files (keyed by string: `'eif'`, `'enf'`, etc.) +- `maps` — serialized EMF map files (keyed by map ID number) +- `edfs` — EDF dialog/string files (keyed by file ID); fetched from `/data/datNNN.edf` on cache miss + +### Game loop + +`src/main.tsx` sets up a Pixi.js ticker at 120 ms per tick: +```ts +client.tick(); // game logic +client.render(interp); // interpolated Pixi render +``` + +### Graphics + +`src/atlas.ts` (`Atlas`) builds a dynamic texture atlas for character/NPC sprites on demand. Graphics files are loaded from `public/gfx/gfxNNN.egf` (Custom PE Files). `src/gfx/gfx-loader.worker.ts` loads and parses these files in a Web Worker. + +## Key Conventions + +### Imports + +- **Always use `@/` path alias** — never `../` relative parent imports. This is enforced by Biome as an error. +- **Import from barrel files**, not deep paths. The following modules have barrels and must be imported from the top level: + - `@/utils`, `@/render`, `@/controllers`, `@/handlers`, `@/gfx`, `@/fonts` + - For in-game UI: `@/ui/in-game` (not `@/ui/in-game/chat/chat-manager`, etc.) + - For UI enums (`ChatTab`, `ChatIcon`, `DialogIcon`, `SlotType`, `ISlot`): import from `@/ui/enums` directly to avoid circular dependencies, not from `@/ui` + +### Style + +- Single quotes for JS/TS strings and JSX attributes (enforced by Biome). +- Biome (not ESLint/Prettier) is the sole linter/formatter. Run `pnpm lint` to check, `pnpm format` to auto-fix. + +### Packet handlers + +Register handlers in `src/handlers/.ts`: +```ts +export function registerWalkHandlers(client: Client) { + client.bus!.registerPacketHandler(PacketFamily.Walk, PacketAction.Player, + (reader) => handleWalkPlayer(client, reader)); +} +``` +Each handler function deserializes using the corresponding `eolib` packet class: `XxxServerPacket.deserialize(reader)`. + +### Controllers + +Controller classes store a private `client: Client` reference. They send packets by constructing `eolib` client packet objects and calling `this.client.bus!.send(packet)`. + +### Hair style + +`hairStyle` is 1-based. A value of `0` means no hair. Rendering uses `(hairStyle - 1) * 40 + hairColor * 4`. + +### Nullable returns + +- `getEmf(id)` returns `Promise` — always handle the null case. +- `client.getDialogStrings(id)` always returns a 2-element `string[]` (fallback `['', '']`). + +### UI Look and Feel + +The UI uses DaisyUI components with Tailwind CSS. Reference @.github/daisyui-llms.txt for component usage and styling conventions. + +Shared components (e.g., `Button`) are in `src/ui/components/`. Container components for each screen are in `src/ui/containers/`. + +### In game UI elements + +All in-game UI elements should be movable by the player (Toggle in settings, then drag to reposition) with default +positions based on screen size. + +A global UI Scale setting should allow the player to adjust the size of all UI elements (except the main game canvas) for better readability on different screen sizes. + +The following elements are planned/implemented: +- Hotbar (assignable item/skill slots) (**Implemented**: `HotBar` in `src/ui/in-game/hud/hot-bar.tsx`) +- HUD (character name/level/HP/TP/TNL display (numeric & bars)) (**Implemented**: `PlayerHud` in `src/ui/in-game/hud/player-hud.tsx`) +- Side menu (inventory, map, stats, skills, quests, settings, etc.) (**Implemented**: `NavSidebar` / `MobileNav` in `src/ui/in-game/hud/nav-sidebar.tsx`) + - Collapsed to hamburger menu for mobile screens +- Touch controls (virtual joystick + buttons, shown only on mobile) (**Implemented**: `TouchJoystick` / `TouchActionButtons` in `src/ui/in-game/hud/`) +- Chat (**Implemented**: `ChatDialog` / `ChatManagerProvider` in `src/ui/in-game/chat/`) + - All messages have a name (optional), icon (optional), and text. + - The client tracks timestamp for each message and displays as local time (e.g., `[12:34:56]`). + - Chat messages are saved in IndexedDB for chat history to view/search in the Chat Log window. + - WoW style (Color coded, optionally open in separate tabs) + - Local channel (nearby characters, and npcs) + - Global channel (all players, messages prefixed with `~` to send to global) + - Group channel (party messages, prefixed with `'` to send to group) + - Guild channel (guild messages, prefixed with `&` to send to guild) + - Admin channel (GMs only, prefixed with `+` to send to admin) + - Whisper channel(s) (private messages, prefixed with `!recipientName` to send a whisper) + - System messages (Combat log, item pickups, etc. system generated) +- Dialog windows (**Partially implemented**: `src/ui/in-game/dialogs/`) + - Flex positions by default (centered with gap), but allow dragging to reposition (and save position per dialog type). + - Support multiple open dialogs at once (e.g., Inventory + Character + Quests) with proper z-index stacking when clicked. + - Implemented dialogs: `InventoryDialog`, `SpellsDialog`, `CharacterDialog` (Paperdoll), `QuestsDialog`, `SettingsDialog`, `ChatLogDialog` + - Base dialog types: + - Scrolling List + - Layout: + - Title + - Scrollable content area (e.g., list of items, quests, skills, etc.) + - Action buttons (e.g., Cancel, OK, etc.) + - Push/Pop state for nested dialogs (e.g items for sale -> list of items) + - Dialogs using this layout: Shop, Skill master, Inn keeper, Lawyer (for marriage/divorce), Guild master + - Scrolling grid: + - Layout: + - Title + - Scrollable grid content area (e.g., inventory grid, skill grid, etc.) + - Action buttons (e.g., Cancel, OK, etc.) + - Push/Pop state for nested dialogs (e.g., inventory -> item details) + - Dialogs using this layout: Chest, Locker, Skill list + - Custom Dialog Types: + - Paperdoll (**Implemented** as `CharacterDialog`) + - Displays player information and equipment + - Layout: + - Character info (name, title, home, class, partner, guild name, guild rank name, admin badge) + - Equipment slots (hat, necklace, weapon, armor, shield, gloves, belt, boots, ring 1, ring 2, armlet 1, armlet 2, bracer 1, bracer 2, accessory) + - Displayed in a grid with empty slots for unequipped items + - Image is loaded from gfx-loader + - Hovering over an equipped item shows a tooltip with item details + - OK button to close the dialog + - More to come + +## Public assets + +Game data files must be placed in `public/` before running: +- `public/gfx/gfxNNN.egf` — Custom PE Files for graphics (extracted via gfx-loader) +- `public/sfx/sfxNNN.wav` — sound effects +- `public/maps/NNNNN.emf` — map files (_only_ used for the title screen, in-game maps are loaded via protocol over WebSocket and cached in IndexedDB) +- `public/data/datNNN.edf` — dialog/string data files + +# Refactoring notes + +- Currently a lot of game state is stored in `Client`. Some things have been extracted into controllers but there's still +a lot that need to be moved out. +- The `ClientEvents` / `client.emit` pattern is being phased out in favor of controller-specific `subscribe*` methods (e.g. `subscribeConfirm`, `subscribePaperdollOpened`) that UI hooks call directly. Handlers still predominantly use `client.emit`, but new code should prefer the subscribe pattern on the relevant controller. +- The `GameState` enum has been expanded with all necessary specific states (`CharacterSelect`, `ChangePassword`, `CreateCharacter`, `InGame`, etc.) — this refactor is complete. diff --git a/.github/daisyui-llms.txt b/.github/daisyui-llms.txt new file mode 100644 index 00000000..19e9a812 --- /dev/null +++ b/.github/daisyui-llms.txt @@ -0,0 +1,1874 @@ +--- +description: daisyUI 5 +alwaysApply: true +applyTo: "**" +downloadedFrom: https://daisyui.com/llms.txt +version: 5.5.x +--- + +# daisyUI 5 +daisyUI 5 is a CSS library for Tailwind CSS 4 +daisyUI 5 provides class names for common UI components + +- [daisyUI 5 docs](http://daisyui.com) +- [Guide: How to use this file in LLMs and code editors](https://daisyui.com/docs/editor/) +- [daisyUI 5 release notes](https://daisyui.com/docs/v5/) +- [daisyUI 4 to 5 upgrade guide](https://daisyui.com/docs/upgrade/) + +## daisyUI 5 install notes +[install guide](https://daisyui.com/docs/install/) +1. daisyUI 5 requires Tailwind CSS 4 +2. `tailwind.config.js` file is deprecated in Tailwind CSS v4. do not use `tailwind.config.js`. Tailwind CSS v4 only needs `@import "tailwindcss";` in the CSS file if it's a node dependency. +3. daisyUI 5 can be installed using `npm i -D daisyui@latest` and then adding `@plugin "daisyui";` to the CSS file +4. daisyUI is suggested to be installed as a dependency but if you really want to use it from CDN, you can use Tailwind CSS and daisyUI CDN files: +```html + + +``` +5. A CSS file with Tailwind CSS and daisyUI looks like this (if it's a node dependency) +```css +@import "tailwindcss"; +@plugin "daisyui"; +``` + +## daisyUI 5 usage rules +1. We can give styles to a HTML element by adding daisyUI class names to it. By adding a component class name, part class names (if there's any available for that component), and modifier class names (if there's any available for that component) +2. Components can be customized using Tailwind CSS utility classes if the customization is not possible using the existing daisyUI classes. For example `btn px-10` sets a custom horizontal padding to a `btn` +3. If customization of daisyUI styles using Tailwind CSS utility classes didn't work because of CSS specificity issues, you can use the `!` at the end of the Tailwind CSS utility class to override the existing styles. For example `btn bg-red-500!` sets a custom background color to a `btn` forcefully. This is a last resort solution and should be used sparingly +4. If a specific component or something similar to it doesn't exist in daisyUI, you can create your own component using Tailwind CSS utility +5. when using Tailwind CSS `flex` and `grid` for layout, it should be responsive using Tailwind CSS responsive utility prefixes. +6. Only allowed class names are existing daisyUI class names or Tailwind CSS utility classes. +7. Ideally, you won't need to write any custom CSS. Using daisyUI class names or Tailwind CSS utility classes is preferred. +8. suggested - if you need placeholder images, use https://picsum.photos/200/300 with the size you want +9. suggested - when designing , don't add a custom font unless it's necessary +10. don't add `bg-base-100 text-base-content` to body unless it's necessary +11. For design decisions, use Refactoring UI book best practices + +daisyUI 5 class names are one of the following categories. These type names are only for reference and are not used in the actual code +- `component`: the required component class +- `part`: a child part of a component +- `style`: sets a specific style to component or part +- `behavior`: changes the behavior of component or part +- `color`: sets a specific color to component or part +- `size`: sets a specific size to component or part +- `placement`: sets a specific placement to component or part +- `direction`: sets a specific direction to component or part +- `modifier`: modifies the component or part in a specific way +- `variant`: prefixes for utility classes that conditionally apply styles. syntax is `variant:utility-class` + +## Config +daisyUI 5 config docs: https://daisyui.com/docs/config/ +daisyUI without config: +```css +@plugin "daisyui"; +``` +daisyUI config with `light` theme only: +```css +@plugin "daisyui" { + themes: light --default; +} +``` +daisyUI with all the default configs: +```css +@plugin "daisyui" { + themes: light --default, dark --prefersdark; + root: ":root"; + include: ; + exclude: ; + prefix: ; + logs: true; +} +``` +An example config: +In below config, all the built-in themes are enabled while bumblebee is the default theme and synthwave is the prefersdark theme (default dark mode) +All the other themes are enabled and can be used by adding `data-theme="THEME_NAME"` to the `` element +root scrollbar gutter is excluded. `daisy-` prefix is used for all daisyUI classes and console.log is disabled +```css +@plugin "daisyui" { + themes: light, dark, cupcake, bumblebee --default, emerald, corporate, synthwave --prefersdark, retro, cyberpunk, valentine, halloween, garden, forest, aqua, lofi, pastel, fantasy, wireframe, black, luxury, dracula, cmyk, autumn, business, acid, lemonade, night, coffee, winter, dim, nord, sunset, caramellatte, abyss, silk; + root: ":root"; + include: ; + exclude: rootscrollgutter, checkbox; + prefix: daisy-; + logs: false; +} +``` +## daisyUI 5 colors + +### daisyUI color names +- `primary`: Primary brand color, The main color of your brand +- `primary-content`: Foreground content color to use on primary color +- `secondary`: Secondary brand color, The optional, secondary color of your brand +- `secondary-content`: Foreground content color to use on secondary color +- `accent`: Accent brand color, The optional, accent color of your brand +- `accent-content`: Foreground content color to use on accent color +- `neutral`: Neutral dark color, For not-saturated parts of UI +- `neutral-content`: Foreground content color to use on neutral color +- `base-100`:-100 Base surface color of page, used for blank backgrounds +- `base-200`:-200 Base color, darker shade, to create elevations +- `base-300`:-300 Base color, even more darker shade, to create elevations +- `base-content`: Foreground content color to use on base color +- `info`: Info color, For informative/helpful messages +- `info-content`: Foreground content color to use on info color +- `success`: Success color, For success/safe messages +- `success-content`: Foreground content color to use on success color +- `warning`: Warning color, For warning/caution messages +- `warning-content`: Foreground content color to use on warning color +- `error`: Error color, For error/danger/destructive messages +- `error-content`: Foreground content color to use on error color + +### daisyUI color rules +1. daisyUI adds semantic color names to Tailwind CSS colors +2. daisyUI color names can be used in utility classes, like other Tailwind CSS color names. for example, `bg-primary` will use the primary color for the background +3. daisyUI color names include variables as value so they can change based the theme +4. There's no need to use `dark:` for daisyUI color names +5. Ideally only daisyUI color names should be used for colors so the colors can change automatically based on the theme +6. If a Tailwind CSS color name (like `red-500`) is used, it will be same red color on all themes +7. If a daisyUI color name (like `primary`) is used, it will change color based on the theme +8. Using Tailwind CSS color names for text colors should be avoided because Tailwind CSS color `text-gray-800` on `bg-base-100` would be unreadable on a dark theme - because on dark theme, `bg-base-100` is a dark color +9. `*-content` colors should have a good contrast compared to their associated colors +10. suggestion - when designing a page use `base-*` colors for majority of the page. use `primary` color for important elements + +### daisyUI custom theme with custom colors +A CSS file with Tailwind CSS, daisyUI and a custom daisyUI theme looks like this: +```css +@import "tailwindcss"; +@plugin "daisyui"; +@plugin "daisyui/theme" { + name: "mytheme"; + default: true; /* set as default */ + prefersdark: false; /* set as default dark mode (prefers-color-scheme:dark) */ + color-scheme: light; /* color of browser-provided UI */ + + --color-base-100: oklch(98% 0.02 240); + --color-base-200: oklch(95% 0.03 240); + --color-base-300: oklch(92% 0.04 240); + --color-base-content: oklch(20% 0.05 240); + --color-primary: oklch(55% 0.3 240); + --color-primary-content: oklch(98% 0.01 240); + --color-secondary: oklch(70% 0.25 200); + --color-secondary-content: oklch(98% 0.01 200); + --color-accent: oklch(65% 0.25 160); + --color-accent-content: oklch(98% 0.01 160); + --color-neutral: oklch(50% 0.05 240); + --color-neutral-content: oklch(98% 0.01 240); + --color-info: oklch(70% 0.2 220); + --color-info-content: oklch(98% 0.01 220); + --color-success: oklch(65% 0.25 140); + --color-success-content: oklch(98% 0.01 140); + --color-warning: oklch(80% 0.25 80); + --color-warning-content: oklch(20% 0.05 80); + --color-error: oklch(65% 0.3 30); + --color-error-content: oklch(98% 0.01 30); + + --radius-selector: 1rem; /* border radius of selectors (checkbox, toggle, badge) */ + --radius-field: 0.25rem; /* border radius of fields (button, input, select, tab) */ + --radius-box: 0.5rem; /* border radius of boxes (card, modal, alert) */ + /* preferred values for --radius-* : 0rem, 0.25rem, 0.5rem, 1rem, 2rem */ + + --size-selector: 0.25rem; /* base size of selectors (checkbox, toggle, badge). Value must be 0.25rem unless we intentionally want bigger selectors. In so it can be 0.28125 or 0.3125. If we intentionally want smaller selectors, it can be 0.21875 or 0.1875 */ + --size-field: 0.25rem; /* base size of fields (button, input, select, tab). Value must be 0.25rem unless we intentionally want bigger fields. In so it can be 0.28125 or 0.3125. If we intentionally want smaller fields, it can be 0.21875 or 0.1875 */ + + --border: 1px; /* border size. Value must be 1px unless we intentionally want thicker borders. In so it can be 1.5px or 2px. If we intentionally want thinner borders, it can be 0.5px */ + + --depth: 1; /* only 0 or 1 – Adds a shadow and subtle 3D depth effect to components */ + --noise: 0; /* only 0 or 1 - Adds a subtle noise (grain) effect to components */ +} +``` +#### Rules +- All CSS variables above are required +- Colors can be OKLCH or hex or other formats +- If you're generating a custom theme, do not include the comments from the example above. Just provide the code. + +People can use https://daisyui.com/theme-generator/ visual tool to create their own theme. + +## daisyUI 5 components + +### accordion +Accordion is used for showing and hiding content but only one item can stay open at a time + +[accordion docs](https://daisyui.com/components/accordion/) + +#### Class names +- component: `collapse` +- part: `collapse-title`, `collapse-content` +- modifier: `collapse-arrow`, `collapse-plus`, `collapse-open`, `collapse-close` + +#### Syntax +```html +
{CONTENT}
+``` +where content is: +```html + +
{title}
+
{CONTENT}
+``` + +#### Rules +- {MODIFIER} is optional and can have one of the modifier class names +- Accordion uses radio inputs. All radio inputs with the same name work together and only one of them can be open at a time +- If you have more than one set of accordion items on a page, use different names for the radio inputs on each set +- Replace {name} with a unique name for the accordion group +- replace `{checked}` with `checked="checked"` if you want the accordion to be open by default + +### alert +Alert informs users about important events + +[alert docs](https://daisyui.com/components/alert/) + +#### Class names +- component: `alert` +- style: `alert-outline`, `alert-dash`, `alert-soft` +- color: `alert-info`, `alert-success`, `alert-warning`, `alert-error` +- direction: `alert-vertical`, `alert-horizontal` + +#### Syntax +```html + +``` + +#### Rules +- {MODIFIER} is optional and can have one of each style/color/direction class names +- Add `sm:alert-horizontal` for responsive layouts + +### avatar +Avatars are used to show a thumbnail + +[avatar docs](https://daisyui.com/components/avatar/) + +#### Class names +- component: `avatar`, `avatar-group` +- modifier: `avatar-online`, `avatar-offline`, `avatar-placeholder` + +#### Syntax +```html +
+
+ +
+
+``` + +#### Rules +- {MODIFIER} is optional and can have one of the modifier class names +- Use `avatar-group` for containing multiple avatars +- You can set custom sizes using `w-*` and `h-*` +- You can use mask classes such as `mask-squircle`, `mask-hexagon`, `mask-triangle` + +### badge +Badges are used to inform the user of the status of specific data + +[badge docs](https://daisyui.com/components/badge/) + +#### Class names +- component: `badge` +- style: `badge-outline`, `badge-dash`, `badge-soft`, `badge-ghost` +- color: `badge-neutral`, `badge-primary`, `badge-secondary`, `badge-accent`, `badge-info`, `badge-success`, `badge-warning`, `badge-error` +- size: `badge-xs`, `badge-sm`, `badge-md`, `badge-lg`, `badge-xl` + +#### Syntax +```html +Badge +``` + +#### Rules +- {MODIFIER} is optional and can have one of each style/color/size class names +- Can be used inside text or buttons +- To create an empty badge, just remove the text between the span tags + +### breadcrumbs +Breadcrumbs helps users to navigate + +[breadcrumbs docs](https://daisyui.com/components/breadcrumbs/) + +#### Class names +- component: `breadcrumbs` + +#### Syntax +```html + +``` + +#### Rules +- breadcrumbs only has one main class name +- Can contain icons inside the links +- If you set `max-width` or the list gets larger than the container it will scroll + +### button +Buttons allow the user to take actions + +[button docs](https://daisyui.com/components/button/) + +#### Class names +- component: `btn` +- color: `btn-neutral`, `btn-primary`, `btn-secondary`, `btn-accent`, `btn-info`, `btn-success`, `btn-warning`, `btn-error` +- style: `btn-outline`, `btn-dash`, `btn-soft`, `btn-ghost`, `btn-link` +- behavior: `btn-active`, `btn-disabled` +- size: `btn-xs`, `btn-sm`, `btn-md`, `btn-lg`, `btn-xl` +- modifier: `btn-wide`, `btn-block`, `btn-square`, `btn-circle` + +#### Syntax +```html + +``` +#### Rules +- {MODIFIER} is optional and can have one of each color/style/behavior/size/modifier class names +- btn can be used on any html tags such as ` +``` + +#### Rules +- {MODIFIER} is optional and can have one of the size class names +- To make a button active, add `dock-active` class to the button +- add `` is required for responsivness of the dock in iOS + +### drawer +Drawer is a grid layout that can show/hide a sidebar on the left or right side of the page + +[drawer docs](https://daisyui.com/components/drawer/) + +#### Class names +- component: `drawer` +- part: `drawer-toggle`, `drawer-content`, `drawer-side`, `drawer-overlay` +- placement: `drawer-end` +- modifier: `drawer-open` +- variant: `is-drawer-open:`, `is-drawer-close:` + +#### Syntax +```html +
+ +
{CONTENT}
+
{SIDEBAR}
+
+``` +where {CONTENT} can be navbar, site content, footer, etc +and {SIDEBAR} can be a menu like: +```html +
+``` +To open/close the drawer, use a label that points to the `drawer-toggle` input: +```html + +``` +Example: This sidebar is always visible on large screen, can be toggled on small screen: +```html +
+ +
+ + +
+
+ + +
+
+``` + +Example: This sidebar is always visible. When it's close we only see iocns, when it's open we see icons and text +```html +
+ +
+ +
+
+ +
+ + + +
+ +
+
+
+
+``` + +#### Rules +- {MODIFIER} is optional and can have one of the modifier/placement class names +- `id` is required for the `drawer-toggle` input. change `my-drawer` to a unique id according to your needs +- `lg:drawer-open` can be used to make sidebar visible on larger screens +- `drawer-toggle` is a hidden checkbox. Use label with "for" attribute to toggle state +- if you want to open the drawer when a button is clicked, use `` where `my-drawer` is the id of the `drawer-toggle` input +- when using drawer, every page content must be inside `drawer-content` element. for example navbar, footer, etc should not be outside of `drawer` + +### dropdown +Dropdown can open a menu or any other element when the button is clicked + +[dropdown docs](https://daisyui.com/components/dropdown/) + +#### Class names +- component: `dropdown` +- part: `dropdown-content` +- placement: `dropdown-start`, `dropdown-center`, `dropdown-end`, `dropdown-top`, `dropdown-bottom`, `dropdown-left`, `dropdown-right` +- modifier: `dropdown-hover`, `dropdown-open`, `dropdown-close` + +#### Syntax +Using details and summary +```html + +``` + +Using popover API +```html + + +``` + +Using CSS focus +```html + +``` + +#### Rules +- {MODIFIER} is optional and can have one of the modifier/placement class names +- replace `{id}` and `{anchor}` with a unique name +- For CSS focus dropdowns, use `tabindex="0"` and `role="button"` on the button +- The content can be any HTML element (not just `