Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added dist/assets/img/ai-hero-avatar.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -245,22 +245,22 @@ <h3 class="dropdown-item-title">
<li class="nav-item dropdown user-menu">
<a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown">
<img
src="./assets/img/user2-160x160.jpg"
src="./assets/img/ai-hero-avatar.jpg"
class="user-image rounded-circle shadow"
alt="User Image"
/>
<span class="d-none d-md-inline">Alexander Pierce</span>
<span class="d-none d-md-inline">AI HERO 2</span>
</a>
<ul class="dropdown-menu dropdown-menu-lg dropdown-menu-end">
<!--begin::User Image-->
<li class="user-header text-bg-primary">
<img
src="./assets/img/user2-160x160.jpg"
src="./assets/img/ai-hero-avatar.jpg"
class="rounded-circle shadow"
alt="User Image"
/>
<p>
Alexander Pierce - Web Developer
AI HERO 2 - Web Developer
<small>Member since Nov. 2023</small>
</p>
</li>
Expand Down Expand Up @@ -971,7 +971,7 @@ <h3 class="card-title">Direct Chat</h3>
<!-- Message. Default to the start -->
<div class="direct-chat-msg">
<div class="direct-chat-infos clearfix">
<span class="direct-chat-name float-start"> Alexander Pierce </span>
<span class="direct-chat-name float-start"> AI HERO 2 </span>
<span class="direct-chat-timestamp float-end"> 23 Jan 2:00 pm </span>
</div>
<!-- /.direct-chat-infos -->
Expand Down Expand Up @@ -1009,7 +1009,7 @@ <h3 class="card-title">Direct Chat</h3>
<!-- Message. Default to the start -->
<div class="direct-chat-msg">
<div class="direct-chat-infos clearfix">
<span class="direct-chat-name float-start"> Alexander Pierce </span>
<span class="direct-chat-name float-start"> AI HERO 2 </span>
<span class="direct-chat-timestamp float-end"> 23 Jan 5:37 pm </span>
</div>
<!-- /.direct-chat-infos -->
Expand Down
Binary file added src/assets/img/ai-hero-avatar.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions src/html/components/dashboard/_topbar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -170,22 +170,22 @@ const deploymentPath = depth === 0 ? './' : '../'.repeat(depth);
<li class="nav-item dropdown user-menu">
<a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown">
<img
src={deploymentPath + "assets/img/user2-160x160.jpg"}
src={deploymentPath + "assets/img/ai-hero-avatar.jpeg"}
class="user-image rounded-circle shadow"
alt="User Image"
/>
<span class="d-none d-md-inline">Alexander Pierce</span>
<span class="d-none d-md-inline">AI HERO</span>
</a>
<ul class="dropdown-menu dropdown-menu-lg dropdown-menu-end">
<!--begin::User Image-->
<li class="user-header text-bg-primary">
<img
src={deploymentPath + "assets/img/user2-160x160.jpg"}
src={deploymentPath + "assets/img/ai-hero-avatar.jpeg"}
class="rounded-circle shadow"
alt="User Image"
/>
<p>
Alexander Pierce - Web Developer
AI HERO - Web Developer
<small>Member since Nov. 2023</small>
</p>
</li>
Expand Down
8 changes: 4 additions & 4 deletions src/html/components/docs/components/main-header.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,23 +147,23 @@
<li class="nav-item dropdown user-menu">
<a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown">
<img
src="../../../dist/assets/img/user2-160x160.jpg"
src="../../../dist/assets/img/ai-hero-avatar.jpeg"
class="user-image rounded-circle shadow"
alt="User Image"
/>
<span class="d-none d-md-inline">Alexander Pierce</span>
<span class="d-none d-md-inline">AI HERO</span>
</a>
<ul class="dropdown-menu dropdown-menu-lg dropdown-menu-end">
<!-- User image -->
<li class="user-header text-bg-primary">
<img
src="../../../dist/assets/img/user2-160x160.jpg"
src="../../../dist/assets/img/ai-hero-avatar.jpeg"
class="rounded-circle shadow"
alt="User Image"
/>

<p>
Alexander Pierce - Web Developer
AI HERO - Web Developer
<small>Member since Nov. 2023</small>
</p>
</li>
Expand Down
8 changes: 4 additions & 4 deletions src/html/pages/docs/components/main-header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -255,25 +255,25 @@ const deploymentPath = depth === 0 ? './' : '../'.repeat(depth);
data-bs-toggle="dropdown"
>
<img
src={deploymentPath + "assets/img/user2-160x160.jpg"}
src={deploymentPath + "assets/img/ai-hero-avatar.jpeg"}
class="user-image rounded-circle shadow"
alt="User Image"
/>
<span class="d-none d-md-inline">Alexander Pierce</span>
<span class="d-none d-md-inline">AI HERO</span>
</a>
<ul
class="dropdown-menu dropdown-menu-lg dropdown-menu-end"
>
<!-- User image -->
<li class="user-header text-bg-primary">
<img
src={deploymentPath + "assets/img/user2-160x160.jpg"}
src={deploymentPath + "assets/img/ai-hero-avatar.jpeg"}
class="rounded-circle shadow"
alt="User Image"
/>

<p>
Alexander Pierce - Web Developer
AI HERO - Web Developer
<small>Member since Nov. 2023</small>
</p>
</li>
Expand Down
4 changes: 2 additions & 2 deletions src/html/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ const deploymentPath = depth === 0 ? './' : '../'.repeat(depth);
<div class="direct-chat-msg">
<div class="direct-chat-infos clearfix">
<span class="direct-chat-name float-start">
Alexander Pierce
AI HERO
</span>
<span class="direct-chat-timestamp float-end">
23 Jan 2:00 pm
Expand Down Expand Up @@ -311,7 +311,7 @@ const deploymentPath = depth === 0 ? './' : '../'.repeat(depth);
<div class="direct-chat-msg">
<div class="direct-chat-infos clearfix">
<span class="direct-chat-name float-start">
Alexander Pierce
AI HERO
</span>
<span class="direct-chat-timestamp float-end">
23 Jan 5:37 pm
Expand Down
6 changes: 3 additions & 3 deletions src/html/pages/index2.astro
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ const deploymentPath = depth === 0 ? './' : '../'.repeat(depth);
<div class="direct-chat-msg">
<div class="direct-chat-infos clearfix">
<span class="direct-chat-name float-start">
Alexander Pierce
AI HERO
</span>
<span class="direct-chat-timestamp float-end">
23 Jan 2:00 pm
Expand Down Expand Up @@ -412,7 +412,7 @@ const deploymentPath = depth === 0 ? './' : '../'.repeat(depth);
<div class="direct-chat-msg">
<div class="direct-chat-infos clearfix">
<span class="direct-chat-name float-start">
Alexander Pierce
AI HERO
</span>
<span class="direct-chat-timestamp float-end">
23 Jan 5:37 pm
Expand Down Expand Up @@ -668,7 +668,7 @@ const deploymentPath = depth === 0 ? './' : '../'.repeat(depth);
class="btn fw-bold fs-7 text-secondary text-truncate w-100 p-0"
href="#"
>
Alexander Pierce
AI HERO
</a>
<div class="fs-8">Today</div>
</div>
Expand Down
Binary file added src/html/public/assets/img/ai-hero-avatar.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/ts/adminlte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Treeview from './treeview.js'
import DirectChat from './direct-chat.js'
import FullScreen from './fullscreen.js'
import PushMenu from './push-menu.js'
import ThemeSwitch from './theme-switch.js'
import { initAccessibility } from './accessibility.js'

/**
Expand Down Expand Up @@ -50,5 +51,6 @@ export {
DirectChat,
FullScreen,
PushMenu,
ThemeSwitch,
initAccessibility
}
183 changes: 183 additions & 0 deletions src/ts/theme-switch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/**
* --------------------------------------------
* @file AdminLTE theme-switch.ts
* @description Dark/light theme toggle for AdminLTE.
* Persists user preference in localStorage and
* respects the OS-level prefers-color-scheme setting.
* @license MIT
* --------------------------------------------
*/

import {
onDOMContentLoaded
} from './util/index'

/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/

const DATA_KEY = 'lte.theme-switch'
const EVENT_KEY = `.${DATA_KEY}`

const EVENT_THEME_CHANGE = `change${EVENT_KEY}`

const THEME_LIGHT = 'light'
const THEME_DARK = 'dark'

const STORAGE_KEY_THEME = 'lte.theme'
const SELECTOR_THEME_TOGGLE = '[data-lte-toggle="theme"]'

type Theme = typeof THEME_LIGHT | typeof THEME_DARK

type Config = {
defaultTheme: Theme;
enablePersistence: boolean;
respectSystemPreference: boolean;
}

const Defaults: Config = {
defaultTheme: THEME_LIGHT,
enablePersistence: true,
respectSystemPreference: true
}

/**
* Class Definition
* ====================================================
*/

class ThemeSwitch {
_element: HTMLElement
_config: Config
_currentTheme: Theme

constructor(element: HTMLElement, config?: Partial<Config>) {
this._element = element
this._config = { ...Defaults, ...config }
this._currentTheme = this._resolveInitialTheme()
}

get theme(): Theme {
return this._currentTheme
}

/**
* Determine initial theme from: localStorage > system preference > default
*/
private _resolveInitialTheme(): Theme {
if (this._config.enablePersistence) {
try {
const stored = localStorage.getItem(STORAGE_KEY_THEME)
if (stored === THEME_DARK || stored === THEME_LIGHT) {
return stored
}
} catch {
// localStorage unavailable
}
}

if (this._config.respectSystemPreference) {
const prefersDark = globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches
if (prefersDark) {
return THEME_DARK
}
}

return this._config.defaultTheme
}

apply(): void {
document.documentElement.setAttribute('data-bs-theme', this._currentTheme)
this._updateToggles()
this._persist()
}

toggle(): void {
this.setTheme(this._currentTheme === THEME_DARK ? THEME_LIGHT : THEME_DARK)
}

setTheme(theme: Theme): void {
this._currentTheme = theme
this.apply()

const event = new CustomEvent(EVENT_THEME_CHANGE, { detail: { theme } })
this._element.dispatchEvent(event)
}

private _persist(): void {
if (!this._config.enablePersistence) {
return
}

try {
localStorage.setItem(STORAGE_KEY_THEME, this._currentTheme)
} catch {
// localStorage unavailable
}
}

private _updateToggles(): void {
const toggles = document.querySelectorAll<HTMLElement>(SELECTOR_THEME_TOGGLE)
const isDark = this._currentTheme === THEME_DARK

toggles.forEach(toggle => {
// Update aria attribute for accessibility
toggle.setAttribute('aria-pressed', String(isDark))

// Update checkbox/input toggles
if (toggle instanceof HTMLInputElement && toggle.type === 'checkbox') {
toggle.checked = isDark
}
})
}

/**
* Listen for OS theme changes and react accordingly
*/
watchSystemPreference(): void {
if (!this._config.respectSystemPreference) {
return
}

globalThis.matchMedia?.('(prefers-color-scheme: dark)').addEventListener('change', event => {
// Only auto-switch if user hasn't manually chosen a theme
if (!this._config.enablePersistence) {
this.setTheme(event.matches ? THEME_DARK : THEME_LIGHT)
return
}

try {
const stored = localStorage.getItem(STORAGE_KEY_THEME)
if (!stored) {
this.setTheme(event.matches ? THEME_DARK : THEME_LIGHT)
}
} catch {
this.setTheme(event.matches ? THEME_DARK : THEME_LIGHT)
}
})
}
}

/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/

onDOMContentLoaded(() => {
const themeSwitch = new ThemeSwitch(document.documentElement)
themeSwitch.apply()
themeSwitch.watchSystemPreference()

const toggles = document.querySelectorAll(SELECTOR_THEME_TOGGLE)
toggles.forEach(toggle => {
toggle.addEventListener('click', event => {
event.preventDefault()
themeSwitch.toggle()
})
})
})

export default ThemeSwitch