Просмотр исходного кода

docs(plugins): add Overview page, document programmatic API for all 7 plugins

Adds a new Plugins Overview page (javascript/plugins-overview.html)
with an at-a-glance reference table mapping every plugin to its data
API, programmatic methods, and dedicated reference page. Includes
event-name reference, config-via-data-attribute examples, and the
full list of CSS classes the plugins manage on body / app-wrapper /
card / etc.

Each individual plugin page gains a "Programmatic API" section
documenting the real public methods (verified against the TypeScript
source in src/ts/, not invented):

- PushMenu: toggle/expand/collapse/isCollapsed/isExplicitlyOpen/
  isMiniMode/isMobileSize/saveSidebarState/loadSidebarState/
  clearSidebarState/updateStateByResponsiveLogic
- Treeview: open/close/toggle, plus the previously-undocumented
  data-accordion and data-animation-speed attributes
- CardWidget: collapse/expand/toggle/maximize/minimize/
  toggleMaximize/remove, plus the four trigger-selector config keys
- DirectChat: toggle
- FullScreen: toggleFullScreen/inFullScreen/outFullscreen, plus
  notes on the .d-none toggle pattern that #6021 fixed
- Layout: holdTransition(time)

Method signatures, return types, and event fired-on-call mapping
verified against src/ts/{push-menu,treeview,card-widget,direct-chat,
fullscreen,layout}.ts.
Aigars Silkalns 10 часов назад
Родитель
Сommit
389d017c42

+ 41 - 1
src/html/components/javascript/card-widget.mdx

@@ -49,7 +49,47 @@ The plugin dispatches the following events on the trigger element:
 | `collapsed-card` | Applied to the card when collapsed. |
 | `maximized-card` | Applied to the card when maximized. |
 
+##### Configuration
+
+The plugin reads no `data-*` configuration attributes. To customize behaviour, instantiate it programmatically and pass a config:
+
+| Option | Default | Description |
+|---|---|---|
+| `animationSpeed` | `500` | Slide animation duration in milliseconds. |
+| `collapseTrigger` | `[data-lte-toggle="card-collapse"]` | CSS selector for collapse buttons. |
+| `removeTrigger` | `[data-lte-toggle="card-remove"]` | CSS selector for remove buttons. |
+| `maximizeTrigger` | `[data-lte-toggle="card-maximize"]` | CSS selector for maximize buttons. |
+
+##### Programmatic API
+
+```js
+import { CardWidget } from "admin-lte"
+
+const card = document.querySelector("#chart-card")
+const widget = new CardWidget(card, { animationSpeed: 250 })
+
+widget.maximize()     // expand to fullscreen
+widget.collapse()     // hide body and footer
+widget.expand()       // restore from collapsed
+widget.remove()       // animate out and remove from DOM
+widget.toggle()       // expand / collapse based on current state
+widget.toggleMaximize()  // maximize / minimize based on current state
+```
+
+###### Methods
+
+| Method | Returns | Description |
+|---|---|---|
+| `collapse()` | `void` | Slides up body and footer, adds `collapsed-card`. Fires `collapsed.lte.card-widget`. |
+| `expand()` | `void` | Slides down body and footer, removes `collapsed-card`. Fires `expanded.lte.card-widget`. |
+| `toggle()` | `void` | Calls `collapse()` or `expand()` based on the `collapsed-card` class. |
+| `maximize()` | `void` | Sets the card to fixed fullscreen positioning, adds `maximized-card`. Fires `maximized.lte.card-widget`. |
+| `minimize()` | `void` | Restores original size, removes `maximized-card`. Fires `minimized.lte.card-widget`. |
+| `toggleMaximize()` | `void` | Calls `maximize()` or `minimize()` based on the `maximized-card` class. |
+| `remove()` | `void` | Animates the card out and removes it from the DOM. Fires `remove.lte.card-widget`. |
+
 ##### Notes
 
 - Nested cards are handled correctly: collapsing a parent card does not affect child cards.
-- The animation speed defaults to 500ms.
+- Maximizing a card also adds `maximized-card` to `<html>` so global styles can react.
+- A card that's collapsed when you maximize it remembers that — the `was-collapsed` class tracks this state.

+ 19 - 0
src/html/components/javascript/direct-chat.mdx

@@ -41,3 +41,22 @@ Add `data-lte-toggle="chat-pane"` to a button inside a `.direct-chat` container
 | Class | Description |
 |-------|-------------|
 | `direct-chat-contacts-open` | Applied to the `.direct-chat` container when the contacts pane is visible. |
+
+##### Programmatic API
+
+```js
+import { DirectChat } from "admin-lte"
+
+const chat = document.querySelector(".direct-chat")
+const dc = new DirectChat(chat)
+
+dc.toggle()  // show or hide the contacts pane
+```
+
+###### Methods
+
+| Method | Returns | Description |
+|---|---|---|
+| `toggle()` | `void` | Toggles the `direct-chat-contacts-open` class on the `.direct-chat` container. Fires `expanded.lte.direct-chat` or `collapsed.lte.direct-chat`. |
+
+The constructor takes no config object — pass only the `.direct-chat` element.

+ 26 - 2
src/html/components/javascript/fullscreen.mdx

@@ -22,7 +22,31 @@ Add `data-lte-toggle="fullscreen"` to a button element. Use `data-lte-icon="maxi
 | `maximized.lte.fullscreen` | Fired when entering fullscreen mode. |
 | `minimized.lte.fullscreen` | Fired when exiting fullscreen mode. |
 
+##### Programmatic API
+
+```js
+import { FullScreen } from "admin-lte"
+
+const btn = document.querySelector('[data-lte-toggle="fullscreen"]')
+const fs = new FullScreen(btn)
+
+fs.toggleFullScreen()  // enter or exit based on current state
+fs.inFullScreen()      // request fullscreen
+fs.outFullscreen()     // exit fullscreen
+```
+
+###### Methods
+
+| Method | Returns | Description |
+|---|---|---|
+| `toggleFullScreen()` | `void` | Calls `inFullScreen()` if not in fullscreen, otherwise `outFullscreen()`. Checks `document.fullscreenEnabled` first. |
+| `inFullScreen()` | `void` | Calls `document.documentElement.requestFullscreen()`, toggles `.d-none` on the maximize/minimize icons. Fires `maximized.lte.fullscreen`. |
+| `outFullscreen()` | `void` | Calls `document.exitFullscreen()`, toggles `.d-none` on the maximize/minimize icons. Fires `minimized.lte.fullscreen`. |
+
+The constructor takes no config — pass only the trigger element.
+
 ##### Notes
 
-- Requires browser support for the Fullscreen API (`document.fullscreenEnabled`).
-- The maximize icon is hidden when in fullscreen mode, and the minimize icon is shown (and vice versa).
+- Requires browser support for the [Fullscreen API](https://developer.mozilla.org/docs/Web/API/Fullscreen_API). Check `document.fullscreenEnabled` before invoking.
+- The maximize icon is hidden via the `d-none` Bootstrap utility class (not inline `display`) so it doesn't override the icon library's natural display value — this works correctly with FontAwesome, Lucide, Tabler Icons, etc.
+- Fullscreen on `document.documentElement` (i.e. `<html>`) means the entire page goes fullscreen. To fullscreen just a card, use the [CardWidget `maximize()` method](card-widget.html#programmatic-api) instead.

+ 23 - 2
src/html/components/javascript/layout.mdx

@@ -29,7 +29,28 @@ body.app-loaded .app-sidebar {
 }
 ```
 
+##### Programmatic API
+
+The Layout plugin self-initializes on `DOMContentLoaded` — there's nothing to wire up manually. The only public method is exposed for advanced cases where you want to suppress transitions around your own DOM mutations:
+
+```js
+import { Layout } from "admin-lte"
+
+const layout = new Layout(document.body)
+layout.holdTransition(200)   // disable transitions for 200ms
+
+// ... do something that would otherwise animate awkwardly
+document.body.classList.toggle("sidebar-mini")
+```
+
+###### Methods
+
+| Method | Returns | Description |
+|---|---|---|
+| `holdTransition(time?)` | `void` | Adds `hold-transition` to `<body>`, removes it after `time` milliseconds (default `100`). Use to suppress CSS transitions during programmatic layout changes. |
+
 ##### Notes
 
-- The `hold-transition` class is automatically removed after 200ms (on resize) or 100ms (default).
-- No data attributes or manual initialization required. The plugin initializes automatically.
+- The `hold-transition` class is automatically removed after the timeout. You don't need to clean up.
+- No data attributes — the plugin reads no config and initialises with the body element on page load.
+- If you need to detect when the initial page-load animations are done, watch for the `app-loaded` class on `<body>` or listen for the standard `load` event.

+ 149 - 0
src/html/components/javascript/plugins-overview.mdx

@@ -0,0 +1,149 @@
+AdminLTE ships seven JavaScript plugins as a single bundle (`adminlte.js`). Each one is exported from the package root, can be triggered via `data-lte-*` attributes for declarative use, and exposes a programmatic API for code-driven control.
+
+##### At a glance
+
+| Plugin | Data API | Programmatic | Documentation |
+|---|---|---|---|
+| **PushMenu** | `data-lte-toggle="sidebar"` | `.toggle()` / `.expand()` / `.collapse()` | [Reference](pushmenu.html) |
+| **Treeview** | `data-lte-toggle="treeview"` on parent menu | `.toggle()` / `.open()` / `.close()` | [Reference](treeview.html) |
+| **CardWidget** | `data-lte-toggle="card-collapse"`, `card-remove`, `card-maximize` | `.toggle()` / `.collapse()` / `.expand()` / `.remove()` / `.maximize()` / `.minimize()` / `.toggleMaximize()` | [Reference](card-widget.html) |
+| **DirectChat** | `data-lte-toggle="chat-pane"` | `.toggle()` | [Reference](direct-chat.html) |
+| **FullScreen** | `data-lte-toggle="fullscreen"` | `.toggleFullScreen()` / `.inFullScreen()` / `.outFullscreen()` | [Reference](fullscreen.html) |
+| **Layout** | (auto-applied to `<body>`) | `.holdTransition(time)` | [Reference](layout.html) |
+| **AccessibilityManager** | (helper function: `initAccessibility()`) | `.announce()` / `.focusElement()` / `.trapFocus()` / `.addLandmarks()` | [Reference](accessibility.html) |
+
+##### Two ways to use them
+
+###### 1. Data API (declarative)
+
+For most pages, the data API is enough — no JavaScript code required. Drop the right `data-lte-*` attribute on the trigger element and the bundle wires it up on page load:
+
+```html
+<!-- Sidebar toggle -->
+<button data-lte-toggle="sidebar">☰</button>
+
+<!-- Card collapse / remove / maximize -->
+<div class="card">
+  <div class="card-header">
+    <h3 class="card-title">Title</h3>
+    <div class="card-tools">
+      <button class="btn btn-tool" data-lte-toggle="card-collapse">
+        <i data-lte-icon="expand" class="bi bi-dash-lg"></i>
+        <i data-lte-icon="collapse" class="bi bi-plus-lg"></i>
+      </button>
+    </div>
+  </div>
+  <div class="card-body">…</div>
+</div>
+```
+
+The bundle attaches all data-API listeners on `DOMContentLoaded`. Dynamically-injected elements still work for the [PushMenu](pushmenu.html), [CardWidget](card-widget.html), and [Treeview](treeview.html) plugins, which use event delegation.
+
+###### 2. Programmatic (imperative)
+
+When you need to control a plugin from your own code — eg. open the sidebar after a successful login, or expand a card on a route change — instantiate the class directly:
+
+```js
+// ESM (bundler import)
+import { PushMenu, CardWidget, Treeview } from "admin-lte"
+
+// Sidebar
+new PushMenu(document.body, {}).expand()
+
+// Card maximize
+const card = document.querySelector("#chart-card")
+new CardWidget(card, {}).maximize()
+```
+
+Or use the globals (UMD bundle, no build step):
+
+```html
+<script>
+  // The bundle assigns to window.adminlte
+  new adminlte.PushMenu(document.body, {}).expand()
+</script>
+```
+
+##### Listening to plugin events
+
+Every plugin fires a `CustomEvent` or `Event` on the element it operates on. Listen for these to coordinate with your own code:
+
+```js
+document.addEventListener("expanded.lte.card-widget", (e) => {
+  console.log("Card expanded:", e.target)
+})
+
+document.addEventListener("open.lte.push-menu", () => {
+  // user opened the sidebar — eg. analytics call
+})
+```
+
+###### Event name reference
+
+| Plugin | Event | Fired when |
+|---|---|---|
+| PushMenu | `open.lte.push-menu` | Sidebar expanded |
+| PushMenu | `collapse.lte.push-menu` | Sidebar collapsed |
+| Treeview | `expanded.lte.treeview` | Submenu opened |
+| Treeview | `collapsed.lte.treeview` | Submenu closed |
+| Treeview | `load.lte.treeview` | Pre-opened submenu detected on page load |
+| CardWidget | `expanded.lte.card-widget` | Card expanded |
+| CardWidget | `collapsed.lte.card-widget` | Card collapsed |
+| CardWidget | `remove.lte.card-widget` | Card removed |
+| CardWidget | `maximized.lte.card-widget` | Card maximized |
+| CardWidget | `minimized.lte.card-widget` | Card minimized |
+| DirectChat | `expanded.lte.direct-chat` | Contacts pane opened |
+| DirectChat | `collapsed.lte.direct-chat` | Contacts pane closed |
+| FullScreen | `maximized.lte.fullscreen` | Entered fullscreen |
+| FullScreen | `minimized.lte.fullscreen` | Exited fullscreen |
+
+All events bubble. Attach listeners to `document` or `document.body` for global hooks, or to a specific card / sidebar element for scoped listeners.
+
+##### Configuring via data attributes
+
+Some plugins read config from `data-*` attributes on their target element:
+
+```html
+<!-- Treeview — non-accordion (multiple submenus can be open at once) -->
+<ul class="nav sidebar-menu" data-lte-toggle="treeview" data-accordion="false">…</ul>
+
+<!-- Treeview — custom animation speed -->
+<ul class="nav sidebar-menu" data-lte-toggle="treeview" data-animation-speed="500">…</ul>
+
+<!-- Sidebar — opt into localStorage persistence (default: off) -->
+<aside class="app-sidebar" data-enable-persistence="true">…</aside>
+
+<!-- Sidebar — override the mobile breakpoint -->
+<aside class="app-sidebar" data-sidebar-breakpoint="768">…</aside>
+```
+
+Each plugin's reference page documents which attributes it supports.
+
+##### CSS classes the plugins manage
+
+The plugins toggle a small set of CSS classes that you can also style or react to:
+
+| Class | Set by | Where | Meaning |
+|---|---|---|---|
+| `sidebar-collapse` | PushMenu | `<body>` | Sidebar collapsed (desktop mini state, or mobile-closed) |
+| `sidebar-open` | PushMenu | `<body>` | Mobile sidebar explicitly opened by user |
+| `sidebar-mini` | PushMenu | `<body>` | Mini-sidebar mode active |
+| `menu-open` | Treeview | `.nav-item` | Submenu is currently expanded |
+| `collapsed-card` | CardWidget | `.card` | Card body/footer are collapsed |
+| `maximized-card` | CardWidget | `<html>` and `.card` | Card is in fullscreen mode |
+| `direct-chat-contacts-open` | DirectChat | `.direct-chat` | Contacts pane visible |
+| `hold-transition` | Layout | `<body>` | Transitions disabled briefly (during resize, etc.) |
+| `app-loaded` | Layout | `<body>` | Initial page-load animation finished |
+| `reduce-motion` | AccessibilityManager | `<body>` | OS `prefers-reduced-motion` detected |
+
+##### Production vs source
+
+The plugins live in [`src/ts/`](https://github.com/ColorlibHQ/master/src/ts) as TypeScript modules. The published `dist/js/adminlte.js` is a Rollup bundle of all seven, exporting them under a single `adminlte` namespace (UMD) or named imports (ESM).
+
+If you only need one or two plugins and care about bundle size, importing individual modules from `node_modules/admin-lte/src/ts/` will tree-shake — but you'll need TypeScript in your toolchain.
+
+##### Where to next
+
+- Detailed reference for each plugin (links in the table above)
+- [Layout Blueprint](../layout-blueprint.html) — the structural classes the plugins operate on
+- [Accessibility](accessibility.html) — keyboard navigation, focus trapping, ARIA helpers

+ 44 - 0
src/html/components/javascript/pushmenu.mdx

@@ -49,6 +49,50 @@ Configure the sidebar via data attributes on the `.app-sidebar` element:
 | `open.lte.push-menu` | Fired when the sidebar is expanded. |
 | `collapse.lte.push-menu` | Fired when the sidebar is collapsed. |
 
+Both events bubble. Listen on `document` for a global hook:
+
+```js
+document.addEventListener("open.lte.push-menu", () => {
+  console.log("Sidebar opened")
+})
+```
+
+##### Programmatic API
+
+Import the class and instantiate it on any element (typically the sidebar toggle button or `document.body`):
+
+```js
+import { PushMenu } from "admin-lte"
+
+const sidebar = new PushMenu(document.querySelector('[data-lte-toggle="sidebar"]'), {
+  sidebarBreakpoint: 992,
+  enablePersistence: false
+})
+```
+
+###### Methods
+
+| Method | Returns | Description |
+|---|---|---|
+| `toggle()` | `void` | Expands or collapses the sidebar based on current state. Persists state if `enablePersistence` is `true`. |
+| `expand()` | `void` | Expands the sidebar. Fires `open.lte.push-menu`. |
+| `collapse()` | `void` | Collapses the sidebar. Fires `collapse.lte.push-menu`. |
+| `isCollapsed()` | `boolean` | `true` if `<body>` has `sidebar-collapse` class. |
+| `isExplicitlyOpen()` | `boolean` | `true` if `<body>` has `sidebar-open` (mobile, user opened it). |
+| `isMiniMode()` | `boolean` | `true` if `<body>` has `sidebar-mini`. |
+| `isMobileSize()` | `boolean` | `true` if `window.innerWidth ≤ sidebarBreakpoint`. |
+| `saveSidebarState(state)` | `void` | Manually save state to localStorage (`"sidebar-open"` or `"sidebar-collapse"`). |
+| `loadSidebarState()` | `void` | Read state from localStorage and apply it. |
+| `clearSidebarState()` | `void` | Remove saved state from localStorage. |
+| `updateStateByResponsiveLogic()` | `void` | Recompute correct state based on viewport size (collapse on mobile, expand on desktop unless mini). Called automatically on resize. |
+
+###### Storage key
+
+When `enablePersistence` is enabled, the plugin reads/writes `localStorage.getItem("lte.sidebar.state")`. The stored value is one of:
+
+- `"sidebar-open"` — user wants the sidebar expanded
+- `"sidebar-collapse"` — user wants it collapsed
+
 ##### Example
 
 <a href="#" data-lte-toggle="sidebar">Toggle Sidebar</a>

+ 103 - 18
src/html/components/javascript/treeview.mdx

@@ -1,38 +1,123 @@
-The Treeview plugin converts a nested list into a tree view where sub menus can be expanded.
+The Treeview plugin converts a nested list into a collapsible tree where submenus expand and contract on click. It's what powers the sidebar navigation in the demo dashboards.
 
 ##### Usage
 
-This plugin can be used as the data api.
+###### Data API
 
-**Data API**
-
-Add `data-lte-toggle="treeview"` to any ul or ol element to activate the plugin.
+Add `data-lte-toggle="treeview"` to the parent `<ul>` or `<ol>`. Inside, mark items that have children with `.nav-item` and put the submenu in a nested `<ul class="nav-treeview">`:
 
 ```html
-<ul data-lte-toggle="treeview">
-  <li><a href="#">One Level</a></li>
-  <li class="nav-item menu-open">
-    <a class="nav-link" href="#">Multilevel</a>
-    <ul class="nav-treeview">
-      <li><a href="#">Level 2</a></li>
+<ul class="nav sidebar-menu flex-column" data-lte-toggle="treeview" role="menu">
+  <li class="nav-item">
+    <a class="nav-link" href="#">
+      <i class="nav-icon bi bi-speedometer"></i>
+      <p>Dashboard</p>
+    </a>
+  </li>
+  <li class="nav-item">
+    <a href="#" class="nav-link">
+      <i class="nav-icon bi bi-folder"></i>
+      <p>
+        Reports
+        <i class="nav-arrow bi bi-chevron-right"></i>
+      </p>
+    </a>
+    <ul class="nav nav-treeview">
+      <li class="nav-item">
+        <a href="#" class="nav-link"><i class="nav-icon bi bi-circle"></i><p>Sales</p></a>
+      </li>
+      <li class="nav-item">
+        <a href="#" class="nav-link"><i class="nav-icon bi bi-circle"></i><p>Traffic</p></a>
+      </li>
     </ul>
   </li>
 </ul>
 ```
 
+To start with a submenu pre-expanded, add `menu-open` to its `.nav-item`.
+
+##### Configuration
+
+Configure via `data-*` attributes on the parent `<ul>`:
+
+| Attribute | Default | Description |
+|---|---|---|
+| `data-accordion` | `true` | Close other open submenus when one opens. Set `false` for non-accordion behaviour (multiple submenus open at once). |
+| `data-animation-speed` | `300` | Slide animation duration in milliseconds. Set `0` to disable animation. |
+
+```html
+<!-- Non-accordion mode: multiple submenus can stay open -->
+<ul class="nav sidebar-menu" data-lte-toggle="treeview" data-accordion="false">
+  …
+</ul>
+
+<!-- Faster animation -->
+<ul class="nav sidebar-menu" data-lte-toggle="treeview" data-animation-speed="150">
+  …
+</ul>
+```
+
+##### CSS Classes
+
+| Class | Applied to | Description |
+|---|---|---|
+| `menu-open` | `.nav-item` (the parent of a submenu) | The submenu is currently expanded. |
+| `nav-treeview` | `<ul>` (nested) | Marks a submenu so the plugin recognises it. |
+| `nav-arrow` | `<i>` inside `.nav-link` | The chevron icon that rotates when the submenu opens. |
+
+##### Events
+
+| Event | Description |
+|---|---|
+| `expanded.lte.treeview` | Fired on the `.nav-item` when its submenu opens. |
+| `collapsed.lte.treeview` | Fired on the `.nav-item` when its submenu closes. |
+| `load.lte.treeview` | Fired once per page load for any submenu that's already expanded via the `menu-open` class. |
+
+```js
+document.addEventListener("expanded.lte.treeview", (e) => {
+  console.log("Opened submenu inside:", e.target)
+})
+```
+
+##### Programmatic API
+
+```js
+import { Treeview } from "admin-lte"
+
+const item = document.querySelector(".sidebar-menu .nav-item")
+const tv = new Treeview(item, { accordion: true, animationSpeed: 300 })
+
+tv.open()    // expand this item's submenu
+tv.close()   // collapse it
+tv.toggle()  // toggle
+```
+
+###### Methods
+
+| Method | Returns | Description |
+|---|---|---|
+| `open()` | `void` | Expands the submenu. If `accordion` is `true`, closes sibling submenus first. Fires `expanded.lte.treeview`. |
+| `close()` | `void` | Collapses the submenu. Fires `collapsed.lte.treeview`. |
+| `toggle()` | `void` | Calls `open()` or `close()` based on current state. |
+
 ##### Example
 
-<ul data-lte-toggle="treeview">
-  <li>
-    <a href="#">One Level</a>
+<ul class="nav sidebar-menu flex-column" data-lte-toggle="treeview" role="menu" style="background: var(--bs-tertiary-bg); padding: .5rem; border-radius: var(--bs-border-radius);">
+  <li class="nav-item">
+    <a class="nav-link" href="#">
+      <i class="nav-icon bi bi-circle"></i><p>One level</p>
+    </a>
   </li>
   <li class="nav-item menu-open">
     <a class="nav-link" href="#">
-      Multilevel
+      <i class="nav-icon bi bi-folder"></i>
+      <p>Multilevel <i class="nav-arrow bi bi-chevron-right"></i></p>
     </a>
-    <ul class="nav-treeview">
-      <li>
-        <a href="#">Level 2</a>
+    <ul class="nav nav-treeview">
+      <li class="nav-item">
+        <a href="#" class="nav-link">
+          <i class="nav-icon bi bi-circle"></i><p>Level 2</p>
+        </a>
       </li>
     </ul>
   </li>

+ 61 - 0
src/html/pages/docs/javascript/plugins-overview.astro

@@ -0,0 +1,61 @@
+---
+import Head from "@components/_head.astro"
+import Footer from "@components/dashboard/_footer.astro"
+import Topbar from "@components/dashboard/_topbar.astro"
+import PluginsOverview from "@components/javascript/plugins-overview.mdx"
+import Sidenav from "@components/dashboard/_sidenav.astro"
+import Scripts from "@components/_scripts.astro"
+
+const title = "JavaScript Plugins Overview | AdminLTE 4"
+const path = "../../../../dist"
+const mainPage = "javascript"
+const page = "plugins-overview";
+---
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <Head title={title} path={path} />
+  </head>
+  <body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
+    <div class="app-wrapper">
+      <Topbar path={path} />
+      <Sidenav path={path} mainPage={mainPage} page={page} />
+      <main class="app-main">
+        <div class="app-content-header">
+          <div class="container-fluid">
+            <div class="row">
+              <div class="col-sm-6">
+                <h3 class="mb-0">JavaScript Plugins Overview</h3>
+              </div>
+              <div class="col-sm-6">
+                <ol class="breadcrumb float-sm-end">
+                  <li class="breadcrumb-item"><a href="#">Docs</a></li>
+                  <li class="breadcrumb-item"><a href="#">JavaScript</a></li>
+                  <li class="breadcrumb-item active" aria-current="page">
+                    Overview
+                  </li>
+                </ol>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="app-content">
+          <div class="container-fluid">
+            <div class="row">
+              <div class="col-12">
+                <div class="card">
+                  <div class="card-body">
+                    <PluginsOverview />
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </main>
+      <Footer />
+    </div>
+    <Scripts path={path} />
+  </body>
+</html>