diff --git a/.cspell-project-words.txt b/.cspell-project-words.txt
new file mode 100644
index 0000000..c75afa3
--- /dev/null
+++ b/.cspell-project-words.txt
@@ -0,0 +1,27 @@
+adminlte
+colorlib
+dropbutton
+dropbuttons
+tabledrag
+treeview
+navbar
+subnav
+fontsource
+popperjs
+Popper
+woff
+Frobieter
+grevil
+DROWL
+Bircher
+displace
+tertiary
+subtle
+breadcrumb
+breadcrumbs
+Nightwatch
+stylelint
+phpcs
+phpstan
+cspell
+eslint
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..1fb0684
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,28 @@
+################
+# GitLabCI template for Drupal projects.
+#
+# This uses the official GitLabCI template maintained by the Drupal Association,
+# which runs the standard contrib test/lint jobs (phpcs, phpstan, eslint,
+# stylelint, cspell, phpunit) against this theme.
+#
+# For information on customising jobs, variables and adding/skipping jobs, see:
+# https://project.pages.drupalcode.org/gitlab_templates/
+################
+
+include:
+ - project: $_GITLAB_TEMPLATES_REPO
+ ref: $_GITLAB_TEMPLATES_REF
+ file:
+ - '/includes/include.drupalci.main.yml'
+ - '/includes/include.drupalci.variables.yml'
+ - '/includes/include.drupalci.workflows.yml'
+
+variables:
+ # Skip Nightwatch/functional-JS jobs by default: this theme ships no custom
+ # test suite yet, and the lint/static-analysis jobs are the ones tracked in
+ # https://www.drupal.org/project/adminlte/issues/3607152
+ SKIP_ESLINT: '0'
+ SKIP_STYLELINT: '0'
+ SKIP_PHPSTAN: '0'
+ SKIP_PHPCS: '0'
+ SKIP_CSPELL: '0'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a1a850..e98dd6b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,69 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [Unreleased]
+### Added
+
+- **Primary/accent colour picker** in theme settings — recolours links, focus
+ rings, active states and `.btn-primary`
+ ([#3608660](https://www.drupal.org/project/adminlte/issues/3608660)).
+- **Drag-resizable sidebar** with a localStorage-persisted width and a
+ configurable default width setting
+ ([#3609296](https://www.drupal.org/project/adminlte/issues/3609296)).
+- **Bootstrap Icons pack** for Drupal's Icon API (`adminlte.icons.yml`) — optional,
+ activates when `ui_icons` (`ui_icons_font`) is enabled
+ ([#3609048](https://www.drupal.org/project/adminlte/issues/3609048)).
+- **Components demo** at `docs/components.html`
+ ([#3608677](https://www.drupal.org/project/adminlte/issues/3608677)).
+- **Bootstrap-grid layouts** for Layout Builder (`adminlte.layouts.yml`) — one,
+ two, content+sidebar, three and four column, under the *AdminLTE* category
+ ([#3609456](https://www.drupal.org/project/adminlte/issues/3609456)).
+- **UI Suite integration** — ship `small-box`, `info-box` and `callout` as Single
+ Directory Components; UI Patterns 2 surfaces them in Layout Builder, Views and
+ field formatters. Optional (works standalone on core SDC); `drupal/ui_patterns`
+ added as a Composer *suggest*
+ ([#3608703](https://www.drupal.org/project/adminlte/issues/3608703)).
+- Bundle **Source Sans 3** (the default AdminLTE/Bootstrap body font) locally —
+ weights 300/400/700, Latin + Latin-Extended, under the SIL OFL. The intended
+ default typography now renders without a CDN or a system-installed font
+ ([#3609458](https://www.drupal.org/project/adminlte/issues/3609458)).
+- Theme setting **Start with the sidebar collapsed** — first-load `sidebar-collapse`
+ ([#3608687](https://www.drupal.org/project/adminlte/issues/3608687)).
+- Theme setting **Compact mode** — denser shell via `compact-mode`
+ ([#3608663](https://www.drupal.org/project/adminlte/issues/3608663)).
+- Theme setting **Force RTL layout** — `dir="rtl"` + the bundled RTL stylesheet.
+ (RTL site languages already auto-load `adminlte.rtl.css`.)
+ ([#3608661](https://www.drupal.org/project/adminlte/issues/3608661)).
+- `.gitlab-ci.yml` using the Drupal Association contrib CI template, plus a
+ cspell project dictionary
+ ([#3607152](https://www.drupal.org/project/adminlte/issues/3607152)).
+- README: navigation-block guidance (frontend vs. admin theme), a CSS Editor
+ recommendation, and a first-party-by-Colorlib note
+ ([#3608681](https://www.drupal.org/project/adminlte/issues/3608681),
+ [#3608659](https://www.drupal.org/project/adminlte/issues/3608659),
+ [#3608672](https://www.drupal.org/project/adminlte/issues/3608672)).
+
+### Changed
+
+- **Base theme is now Bootstrap5** instead of the deprecated Stable9. This
+ supplies Drupal core-markup glue CSS (fields, forms, tables, pager, messages)
+ and adds a `drupal/bootstrap5` dependency; AdminLTE keeps its own bundled
+ Bootstrap build (Bootstrap5's CSS/JS is disabled)
+ ([#3609244](https://www.drupal.org/project/adminlte/issues/3609244),
+ [#3608934](https://www.drupal.org/project/adminlte/issues/3608934)).
+- **Dark sidebar is now off by default** — the sidebar follows the active
+ light/dark colour mode unless the setting is enabled
+ ([#3608682](https://www.drupal.org/project/adminlte/issues/3608682)).
+- Login / register / reset-password pages render as a centred, constrained card
+ instead of spanning the full content width
+ ([#3608688](https://www.drupal.org/project/adminlte/issues/3608688)).
+
+### Fixed
+
+- Lower the `.app-header` / `.app-sidebar` z-index below Drupal's admin toolbar
+ so the toolbar (and Admin Toolbar Search autocomplete) is no longer hidden
+ behind the theme chrome
+ ([#3608932](https://www.drupal.org/project/adminlte/issues/3608932)).
+
## [1.0.0-beta1] - 2026-06-29
First public release. Official **AdminLTE 4** admin theme for **Drupal 10.3+ / 11**
diff --git a/README.md b/README.md
index 6c08132..d5b4234 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,10 @@ Official **AdminLTE 4** admin theme for **Drupal** — Bootstrap 5.3, vanilla JS
(no jQuery), light & dark colour modes. Self-contained: all assets are bundled
locally, no CDN required. By [Colorlib](https://colorlib.com).
+> ✅ **Officially created and maintained by [Colorlib](https://colorlib.com)** —
+> the authors of [AdminLTE](https://github.com/ColorlibHQ/AdminLTE) itself. This
+> is the first-party Drupal port, not a third-party reskin.
+
Verified on **Drupal 11.3** (PHP 8.5): clean install, no errors/warnings in the
log, all admin screens render with the AdminLTE shell in both colour modes.
@@ -43,6 +47,11 @@ The same AdminLTE 4 dashboard, in the framework you know best — you're looking
- Drupal **10.3+** or **11**
- PHP 8.1+ (as required by your Drupal core version)
+- The [**Bootstrap5**](https://www.drupal.org/project/bootstrap5) base theme
+ (`drupal/bootstrap5`, `^4.0`). AdminLTE builds on it for Drupal's core-markup
+ "glue" CSS. Composer pulls it in automatically; for a manual install, download
+ and place it in `themes/contrib/bootstrap5` as well. AdminLTE still bundles its
+ own Bootstrap 5.3 build, so Bootstrap5's own CSS/JS is disabled.
## Installation
@@ -93,8 +102,38 @@ At `/admin/appearance/settings/adminlte`:
- **Default colour mode** — `auto` (follow OS), `light` or `dark`. Visitors can
override it with the navbar toggle; their choice is remembered in the browser.
-- **Dark sidebar** — render the sidebar dark regardless of page mode (applied via
- `data-bs-theme="dark"` on the sidebar).
+- **Dark sidebar** — render the sidebar dark regardless of the page colour mode
+ (applied via `data-bs-theme="dark"` on the sidebar). *Off by default* — the
+ sidebar follows the active light/dark mode unless you enable this.
+- **Start with the sidebar collapsed** — render the sidebar collapsed to icons on
+ first load (adds `sidebar-collapse sidebar-mini`). Visitors can still expand it.
+- **Compact mode** — tighten spacing across the shell (adds `compact-mode`) for
+ information-heavy admin screens.
+- **Force right-to-left (RTL) layout** — force `dir="rtl"` and the bundled RTL
+ stylesheet on every page. You usually don't need this: for RTL **site
+ languages** Drupal already loads `adminlte.rtl.css` automatically (via the
+ `.rtl.css` naming convention). Use the setting only to force RTL on an
+ LTR-language site.
+
+For customisation beyond these settings (colours, spacing, etc.), AdminLTE 4 is
+driven by [CSS variables](https://adminlte.io/themes/v4/docs/customization.html).
+To edit CSS without touching theme files or writing a subtheme, the
+[CSS Editor](https://www.drupal.org/project/css_editor) module lets you add
+custom CSS straight from the admin UI.
+
+## Navigation blocks: frontend vs. admin theme
+
+AdminLTE works both as a **frontend** theme (for applications, intranets and
+dashboards) and as an **administration** theme. Two navigation blocks are placed
+in the `sidebar` region on install, so you can pick whichever fits your use case:
+
+- **Main navigation** — your site's own menu. Use this when AdminLTE is the
+ **default (frontend) theme** for an app-style site. This is the primary use case.
+- **Administration** — Drupal's admin menu as a collapsible treeview with
+ per-section icons. Use this when AdminLTE is set as the **administration
+ theme** (`/admin/appearance` → *Administration theme*).
+
+Remove or rearrange either block at `/admin/structure/block` to suit your build.
## What's bundled
@@ -104,9 +143,52 @@ At `/admin/appearance/settings/adminlte`:
| `js/adminlte.js` | AdminLTE behaviours (sidebar, treeview) |
| `js/vendor/bootstrap.bundle.min.js` | Bootstrap 5.3 + Popper |
| `css/vendor/bootstrap-icons.min.css` + fonts | Bootstrap Icons 1.13 |
+| `css/vendor/source-sans-3.css` + fonts | Source Sans 3 (default body font, weights 300/400/700, [OFL](css/vendor/fonts/OFL.txt)) |
Everything is served from the theme — no external CDN calls.
+## Icons (Drupal Icon API)
+
+The theme ships a **Bootstrap Icons** pack for Drupal's [Icon API](https://www.drupal.org/docs/develop/drupal-apis/icon-api)
+(`adminlte.icons.yml`, all ~2,000 icons). It's an **optional** integration: install
+the [UI Icons](https://www.drupal.org/project/ui_icons) module and enable its
+`ui_icons_font` submodule (the Icon API is in core from 11.1; `ui_icons` backports
+it to 10.3–11.0), and the pack appears in every icon picker — menu-link icons,
+CKEditor, fields, etc. — using the already-bundled font. Nothing extra to download,
+and the theme works fine without it.
+
+## Component reference
+
+Open [`docs/components.html`](docs/components.html) in a browser (straight from
+the theme folder — no Drupal needed) for a self-contained showcase of the
+AdminLTE 4 / Bootstrap 5.3 components this theme provides: buttons, cards,
+tables, forms, tabs, pagination, alerts, badges and icons, in both colour modes.
+
+## Site building: layouts & components
+
+**Bootstrap layouts** — the theme ships five Bootstrap-grid layouts for
+**Layout Builder** (and the *Layout* of display modes), grouped under the
+**AdminLTE** category: one column, two columns (½ + ½), content + sidebar
+(⅔ + ⅓), three columns and four columns. They emit `.row`/`.col-*` markup, so
+Layout Builder regions align to the same grid as the rest of the theme — no
+extra module required.
+
+**Components (SDC / UI Suite)** — three signature AdminLTE widgets ship as
+[Single Directory Components](https://www.drupal.org/docs/develop/theming-drupal/using-single-directory-components):
+`small-box`, `info-box` and `callout`. Use them in any Twig template:
+
+```twig
+{{ include('adminlte:small-box', {
+ value: '150', label: 'New orders', icon: 'bag',
+ color: 'primary', url: '/admin/content'
+}) }}
+```
+
+They work standalone on core SDC. Install
+[UI Patterns 2](https://www.drupal.org/project/ui_patterns) (`drupal/ui_patterns`)
+to surface them — with auto-generated config forms — in **Layout Builder, Views
+and field formatters**, integrating the theme with the **UI Suite** ecosystem.
+
## Tested
Verified against a clean **Drupal 11.3.13** install (standard profile, PHP 8.5):
diff --git a/adminlte.icons.yml b/adminlte.icons.yml
new file mode 100644
index 0000000..d61eea3
--- /dev/null
+++ b/adminlte.icons.yml
@@ -0,0 +1,38 @@
+# Bootstrap Icons pack for the Drupal Icon API (core 11.1+, or the ui_icons
+# contrib backport on 10.3–11.0). Uses the "font" extractor from the
+# ui_icons_font submodule, so this pack activates only when that module is
+# enabled — it is an optional integration, not a hard dependency.
+# See https://www.drupal.org/project/adminlte/issues/3609048
+bootstrap_icons:
+ enabled: true
+ label: 'Bootstrap Icons'
+ description: 'Bootstrap Icons 1.13, bundled with the AdminLTE theme and rendered as font icons.'
+ links:
+ - https://icons.getbootstrap.com
+ version: 1.13.1
+ license:
+ name: MIT
+ url: 'https://github.com/twbs/icons/blob/main/LICENSE'
+ gpl-compatible: true
+ extractor: font
+ config:
+ sources:
+ - css/vendor/bootstrap-icons.json
+ settings:
+ size:
+ title: 'Size (px)'
+ type: integer
+ default: 16
+ class:
+ title: 'Additional CSS class'
+ type: string
+ # The class must be exact, so do NOT run icon_id through clean_class here.
+ template: >-
+
+ # Loads the bundled Bootstrap Icons webfont CSS so the glyphs render.
+ library: 'adminlte/bootstrap_icons'
+ preview: >-
+
diff --git a/adminlte.info.yml b/adminlte.info.yml
index 1538ec3..46e06d1 100644
--- a/adminlte.info.yml
+++ b/adminlte.info.yml
@@ -3,7 +3,11 @@ type: theme
description: 'Official AdminLTE 4 admin theme for Drupal — Bootstrap 5.3, vanilla JS (no jQuery), light & dark modes. By Colorlib.'
package: AdminLTE
core_version_requirement: ^10.3 || ^11
-base theme: stable9
+# Bootstrap5 is a maintained base theme that supplies Drupal "glue" CSS for core
+# markup (field--label-inline, forms, tables, pager, messages …) that Stable9
+# (now deprecated) does not. We inherit that glue but keep AdminLTE's own bundled
+# Bootstrap build. See #3609244 (replaces Stable9) and #3608934 (base CSS).
+base theme: bootstrap5
screenshot: screenshot.png
logo: logo.svg
@@ -11,6 +15,20 @@ logo: logo.svg
libraries:
- adminlte/global-styling
+# Keep Bootstrap5's core-markup glue (bootstrap5/base + bootstrap5/messages, both
+# in the CSS "component" group) but drop its own compiled Bootstrap CSS and JS —
+# AdminLTE already bundles Bootstrap 5.3 (css/adminlte.css) and the Bootstrap JS
+# bundle. Our theme-group CSS loads after the inherited component-group CSS, so
+# the AdminLTE look wins where the two overlap.
+libraries-override:
+ bootstrap5/global-styling: false
+ bootstrap5/bootstrap5-js-latest: false
+
+# Style CKEditor 5 content to match the theme rather than inheriting Bootstrap5's
+# css/ck5style.css.
+ckeditor5-stylesheets:
+ - css/adminlte.css
+
regions:
page_top: 'Page top'
page_bottom: 'Page bottom'
diff --git a/adminlte.layouts.yml b/adminlte.layouts.yml
new file mode 100644
index 0000000..4a481b8
--- /dev/null
+++ b/adminlte.layouts.yml
@@ -0,0 +1,82 @@
+# Bootstrap-grid layouts for Layout Builder / Layout Discovery. Provided directly
+# by the theme (no contrib module needed); they output Bootstrap 5 .row/.col
+# markup so Layout Builder regions align to the grid AdminLTE ships.
+# See https://www.drupal.org/project/adminlte/issues/3609456
+adminlte_one_column:
+ label: 'AdminLTE: One column'
+ category: 'AdminLTE'
+ path: templates/layout/layouts
+ template: adminlte-one-column
+ library: adminlte/layouts
+ default_region: content
+ icon_map:
+ - [content]
+ regions:
+ content:
+ label: Content
+
+adminlte_two_column:
+ label: 'AdminLTE: Two columns (½ + ½)'
+ category: 'AdminLTE'
+ path: templates/layout/layouts
+ template: adminlte-two-column
+ library: adminlte/layouts
+ default_region: first
+ icon_map:
+ - [first, second]
+ regions:
+ first:
+ label: First
+ second:
+ label: Second
+
+adminlte_two_column_sidebar:
+ label: 'AdminLTE: Content + sidebar (⅔ + ⅓)'
+ category: 'AdminLTE'
+ path: templates/layout/layouts
+ template: adminlte-two-column-sidebar
+ library: adminlte/layouts
+ default_region: main
+ icon_map:
+ - [main, sidebar]
+ regions:
+ main:
+ label: Main
+ sidebar:
+ label: Sidebar
+
+adminlte_three_column:
+ label: 'AdminLTE: Three columns (⅓ + ⅓ + ⅓)'
+ category: 'AdminLTE'
+ path: templates/layout/layouts
+ template: adminlte-three-column
+ library: adminlte/layouts
+ default_region: first
+ icon_map:
+ - [first, second, third]
+ regions:
+ first:
+ label: First
+ second:
+ label: Second
+ third:
+ label: Third
+
+adminlte_four_column:
+ label: 'AdminLTE: Four columns'
+ category: 'AdminLTE'
+ path: templates/layout/layouts
+ template: adminlte-four-column
+ library: adminlte/layouts
+ default_region: first
+ icon_map:
+ - [first, second, third, fourth]
+ regions:
+ first:
+ label: First
+ second:
+ label: Second
+ third:
+ label: Third
+ fourth:
+ label: Fourth
diff --git a/adminlte.libraries.yml b/adminlte.libraries.yml
index e7b3ca9..e081dcb 100644
--- a/adminlte.libraries.yml
+++ b/adminlte.libraries.yml
@@ -3,6 +3,8 @@ global-styling:
css:
# Bootstrap 5.3 is bundled inside adminlte.css, so no separate Bootstrap CSS.
theme:
+ # Source Sans 3 (the default AdminLTE/Bootstrap body font), bundled locally.
+ css/vendor/source-sans-3.css: {}
css/vendor/bootstrap-icons.min.css: { minified: true }
css/adminlte.css: { minified: false }
css/adminlte-drupal.css: {}
@@ -15,3 +17,31 @@ global-styling:
- core/drupal
- core/drupalSettings
- core/once
+
+# Right-to-left overrides. Drupal loads adminlte.rtl.css automatically for RTL
+# site languages via the .rtl.css naming convention; this library is only
+# attached when the "Force RTL" theme setting is on, to flip the layout on
+# LTR-language sites too. Depends on global-styling so it cascades after it.
+rtl:
+ version: 4.0.2
+ css:
+ theme:
+ css/adminlte.rtl.css: {}
+ dependencies:
+ - adminlte/global-styling
+
+# Loaded on demand by the Bootstrap Icons pack in adminlte.icons.yml when an icon
+# is rendered via the Drupal Icon API. (The webfont CSS is already part of
+# global-styling for normal page rendering.)
+bootstrap_icons:
+ version: 1.13.1
+ css:
+ component:
+ css/vendor/bootstrap-icons.min.css: { minified: true }
+
+# Spacing/helpers for the theme-provided Bootstrap layouts (adminlte.layouts.yml).
+layouts:
+ version: 4.0.2
+ css:
+ layout:
+ css/layouts.css: {}
diff --git a/adminlte.theme b/adminlte.theme
index 115501c..c3dd69a 100644
--- a/adminlte.theme
+++ b/adminlte.theme
@@ -14,20 +14,129 @@ use Drupal\Core\Url;
* Returns the theme's layout settings with sane defaults.
*
* @return array
- * Keyed by: default_color_mode, sidebar_dark.
+ * Keyed by: default_color_mode, sidebar_dark, sidebar_collapsed,
+ * compact_mode, force_rtl.
*/
function _adminlte_layout_settings(): array {
return [
'default_color_mode' => theme_get_setting('default_color_mode', 'adminlte') ?? 'auto',
- 'sidebar_dark' => (bool) (theme_get_setting('sidebar_dark', 'adminlte') ?? TRUE),
+ // The sidebar follows the active colour mode by default; a dark override is
+ // opt-in (see https://www.drupal.org/project/adminlte/issues/3608682).
+ 'sidebar_dark' => (bool) (theme_get_setting('sidebar_dark', 'adminlte') ?? FALSE),
+ 'sidebar_collapsed' => (bool) (theme_get_setting('sidebar_collapsed', 'adminlte') ?? FALSE),
+ 'compact_mode' => (bool) (theme_get_setting('compact_mode', 'adminlte') ?? FALSE),
+ 'force_rtl' => (bool) (theme_get_setting('force_rtl', 'adminlte') ?? FALSE),
+ 'primary_color' => theme_get_setting('primary_color', 'adminlte') ?: NULL,
+ 'sidebar_width' => theme_get_setting('sidebar_width', 'adminlte') ?: NULL,
];
}
+/**
+ * Builds a CSS override block that recolours the primary accent.
+ *
+ * Overrides the Bootstrap primary CSS variables (utilities, links, focus rings)
+ * plus the `.btn-primary` component variables, since Bootstrap bakes the literal
+ * default colour into compiled components rather than reading `--bs-primary`.
+ *
+ * @param string $hex
+ * A colour as `#rrggbb` (already normalised by the core 'color' element).
+ *
+ * @return string|null
+ * The CSS, or NULL when the colour is missing or malformed.
+ */
+function _adminlte_primary_color_css(string $hex): ?string {
+ if (!preg_match('/^#[0-9a-fA-F]{6}$/', $hex)) {
+ return NULL;
+ }
+ $rgb = static function (float $factor) use ($hex): string {
+ $r = (int) round(hexdec(substr($hex, 1, 2)) * $factor);
+ $g = (int) round(hexdec(substr($hex, 3, 2)) * $factor);
+ $b = (int) round(hexdec(substr($hex, 5, 2)) * $factor);
+ return "$r, $g, $b";
+ };
+ $shade = static function (float $factor) use ($hex): string {
+ return sprintf(
+ '#%02x%02x%02x',
+ (int) round(hexdec(substr($hex, 1, 2)) * $factor),
+ (int) round(hexdec(substr($hex, 3, 2)) * $factor),
+ (int) round(hexdec(substr($hex, 5, 2)) * $factor)
+ );
+ };
+
+ $base_rgb = $rgb(1.0);
+ $hover = $shade(0.85);
+ $active = $shade(0.75);
+
+ return <<setAttribute('dir', 'rtl');
+ }
+ $variables['#attached']['library'][] = 'adminlte/rtl';
+ }
+
+ // Tag the authentication pages (log in, register, reset password) so their
+ // forms can render as a centred, constrained card instead of spanning the
+ // full content width. See
+ // https://www.drupal.org/project/adminlte/issues/3608688
+ $auth_routes = ['user.login', 'user.register', 'user.pass'];
+ if (in_array(\Drupal::routeMatch()->getRouteName(), $auth_routes, TRUE)) {
+ $variables['attributes']['class'][] = 'adminlte-auth-page';
+ }
+
+ // Custom primary/accent colour: inject a small