| @ -0,0 +1,151 @@ | |||||
| # Adminator Documentation | |||||
| This directory contains the complete documentation for Adminator Bootstrap 5 Admin Template. | |||||
| ## ๐ Documentation Structure | |||||
| ``` | |||||
| docs/ | |||||
| โโโ index.md # Homepage | |||||
| โโโ _config.yml # GitHub Pages configuration | |||||
| โโโ getting-started/ # Installation and setup guides | |||||
| โ โโโ installation.md | |||||
| โ โโโ project-structure.md | |||||
| โ โโโ development.md | |||||
| โ โโโ build-deployment.md | |||||
| โโโ components/ # Component documentation | |||||
| โ โโโ charts.md | |||||
| โ โโโ forms.md | |||||
| โ โโโ tables.md | |||||
| โ โโโ navigation.md | |||||
| โ โโโ modals.md | |||||
| โโโ customization/ # Theme and styling guides | |||||
| โ โโโ theme-system.md | |||||
| โ โโโ css-variables.md | |||||
| โ โโโ custom-themes.md | |||||
| โ โโโ component-theming.md | |||||
| โโโ api/ # API reference | |||||
| โ โโโ theme-api.md | |||||
| โ โโโ component-apis.md | |||||
| โ โโโ utilities.md | |||||
| โ โโโ events.md | |||||
| โโโ examples/ # Practical examples | |||||
| โ โโโ basic-setup.md | |||||
| โ โโโ custom-components.md | |||||
| โ โโโ theme-integration.md | |||||
| โ โโโ advanced-patterns.md | |||||
| โโโ deployment/ # Production deployment | |||||
| โ โโโ production-build.md | |||||
| โ โโโ static-hosting.md | |||||
| โ โโโ cdn-integration.md | |||||
| โ โโโ performance.md | |||||
| โโโ contributing/ # Contribution guidelines | |||||
| โโโ development-setup.md | |||||
| โโโ code-standards.md | |||||
| โโโ pull-requests.md | |||||
| โโโ issues.md | |||||
| ``` | |||||
| ## ๐ Hosting Strategy | |||||
| ### **GitHub Pages Setup** | |||||
| 1. **Main Branch Integration**: Documentation lives in the `docs/` folder of the main branch | |||||
| 2. **Automatic Deployment**: GitHub Pages automatically builds and deploys on every commit | |||||
| 3. **Custom Domain Support**: Can be configured with custom domains | |||||
| 4. **Jekyll Integration**: Uses Jekyll static site generator with the Minima theme | |||||
| ### **Benefits of This Approach** | |||||
| โ **Version Control**: Docs stay in sync with code releases | |||||
| โ **Free Hosting**: GitHub Pages provides free, reliable hosting | |||||
| โ **Easy Discovery**: Users find docs directly in the repository | |||||
| โ **SEO Friendly**: Searchable and indexable documentation | |||||
| โ **Collaboration**: Easy for contributors to update docs | |||||
| โ **Professional URLs**: Clean URLs like `username.github.io/repo/` | |||||
| ## ๐ Documentation Sections | |||||
| ### **๐ Getting Started** | |||||
| Complete setup and installation guides for new users. | |||||
| ### **๐จ Components** | |||||
| Detailed documentation for all UI components and their usage. | |||||
| ### **๐ Dark Mode & Theming** | |||||
| Comprehensive guide to the theme system and customization options. | |||||
| ### **๐ง API Reference** | |||||
| Complete API documentation for all JavaScript utilities and components. | |||||
| ### **๐ก Examples** | |||||
| Practical, copy-paste examples for common use cases. | |||||
| ### **๐ Deployment** | |||||
| Production deployment guides and performance optimization tips. | |||||
| ### **๐ค Contributing** | |||||
| Guidelines for contributing to the project. | |||||
| ## ๐ง Local Development | |||||
| To view the documentation locally: | |||||
| ```bash | |||||
| # Install Jekyll (if not already installed) | |||||
| gem install bundler jekyll | |||||
| # Navigate to docs directory | |||||
| cd docs | |||||
| # Install dependencies | |||||
| bundle install | |||||
| # Serve locally | |||||
| bundle exec jekyll serve | |||||
| # Visit http://localhost:4000 | |||||
| ``` | |||||
| ## ๐ Writing Documentation | |||||
| ### **Markdown Guidelines** | |||||
| - Use clear, descriptive headings | |||||
| - Include code examples for all features | |||||
| - Add cross-references between related sections | |||||
| - Use emoji for visual appeal (sparingly) | |||||
| - Include "Next Steps" sections to guide readers | |||||
| ### **Code Examples** | |||||
| ```markdown | |||||
| \```javascript | |||||
| // Always include working code examples | |||||
| const example = Theme.current(); | |||||
| console.log(example); | |||||
| \``` | |||||
| ``` | |||||
| ### **File Naming** | |||||
| - Use lowercase with hyphens: `theme-system.md` | |||||
| - Be descriptive but concise | |||||
| - Group related files in subdirectories | |||||
| ## ๐ Quick Links | |||||
| - **[Live Documentation](https://puikinsh.github.io/Adminator-admin-dashboard/)** (Coming Soon) | |||||
| - **[GitHub Repository](https://github.com/puikinsh/Adminator-admin-dashboard)** | |||||
| - **[Live Demo](https://colorlib.com/polygon/adminator/index.html)** | |||||
| ## ๐ Support | |||||
| For documentation issues: | |||||
| - Open an issue with the `documentation` label | |||||
| - Suggest improvements via pull requests | |||||
| - Join discussions for larger documentation changes | |||||
| --- | |||||
| **Happy documenting!** ๐ | |||||
| @ -0,0 +1,85 @@ | |||||
| # GitHub Pages Configuration for Adminator Documentation | |||||
| # Site settings | |||||
| title: "Adminator Documentation" | |||||
| description: "Complete guide for the Adminator Bootstrap 5 Admin Dashboard Template with Dark Mode" | |||||
| url: "https://puikinsh.github.io" | |||||
| baseurl: "/Adminator-admin-dashboard" | |||||
| # Build settings | |||||
| markdown: kramdown | |||||
| highlighter: rouge | |||||
| theme: minima | |||||
| # Plugin settings | |||||
| plugins: | |||||
| - jekyll-feed | |||||
| - jekyll-sitemap | |||||
| - jekyll-seo-tag | |||||
| # Navigation | |||||
| navigation: | |||||
| - title: "Getting Started" | |||||
| url: "/getting-started/" | |||||
| - title: "Components" | |||||
| url: "/components/" | |||||
| - title: "Dark Mode & Theming" | |||||
| url: "/customization/" | |||||
| - title: "API Reference" | |||||
| url: "/api/" | |||||
| - title: "Examples" | |||||
| url: "/examples/" | |||||
| - title: "Deployment" | |||||
| url: "/deployment/" | |||||
| # SEO | |||||
| author: "Colorlib" | |||||
| twitter: | |||||
| username: colorlib | |||||
| social: | |||||
| name: "Colorlib" | |||||
| links: | |||||
| - https://github.com/puikinsh/Adminator-admin-dashboard | |||||
| - https://colorlib.com | |||||
| # Exclude from processing | |||||
| exclude: | |||||
| - Gemfile | |||||
| - Gemfile.lock | |||||
| - node_modules | |||||
| - vendor/bundle/ | |||||
| - vendor/cache/ | |||||
| - vendor/gems/ | |||||
| - vendor/ruby/ | |||||
| # Include | |||||
| include: | |||||
| - _pages | |||||
| # Collections | |||||
| collections: | |||||
| pages: | |||||
| output: true | |||||
| permalink: /:name/ | |||||
| # Defaults | |||||
| defaults: | |||||
| - scope: | |||||
| path: "" | |||||
| type: "pages" | |||||
| values: | |||||
| layout: "page" | |||||
| - scope: | |||||
| path: "" | |||||
| values: | |||||
| layout: "default" | |||||
| # Code highlighting | |||||
| kramdown: | |||||
| syntax_highlighter: rouge | |||||
| syntax_highlighter_opts: | |||||
| css_class: 'highlight' | |||||
| span: | |||||
| line_numbers: false | |||||
| block: | |||||
| line_numbers: true | |||||
| @ -0,0 +1,489 @@ | |||||
| # Theme API Reference | |||||
| Complete API documentation for the Adminator Theme utility system. | |||||
| ## Overview | |||||
| The Theme API provides programmatic control over Adminator's dark mode and theming system. It includes methods for theme management, color retrieval, and event handling. | |||||
| ## Theme Object | |||||
| The global `Theme` object is available throughout the application: | |||||
| ```javascript | |||||
| // Available globally | |||||
| window.Theme | |||||
| // or simply | |||||
| Theme | |||||
| ``` | |||||
| ## Core Methods | |||||
| ### `Theme.apply(theme)` | |||||
| Applies a specific theme to the application. | |||||
| **Parameters:** | |||||
| - `theme` (string): The theme to apply (`'light'` or `'dark'`) | |||||
| **Returns:** `void` | |||||
| **Example:** | |||||
| ```javascript | |||||
| // Apply dark theme | |||||
| Theme.apply('dark'); | |||||
| // Apply light theme | |||||
| Theme.apply('light'); | |||||
| ``` | |||||
| **Side Effects:** | |||||
| - Sets `data-theme` attribute on `document.documentElement` | |||||
| - Updates Chart.js global defaults (if Chart.js is loaded) | |||||
| - Saves theme preference to localStorage | |||||
| - Dispatches `adminator:themeChanged` event | |||||
| --- | |||||
| ### `Theme.toggle()` | |||||
| Toggles between light and dark themes. | |||||
| **Parameters:** None | |||||
| **Returns:** `void` | |||||
| **Example:** | |||||
| ```javascript | |||||
| // Switch from current theme to opposite | |||||
| Theme.toggle(); | |||||
| // If current theme is 'light', switches to 'dark' | |||||
| // If current theme is 'dark', switches to 'light' | |||||
| ``` | |||||
| --- | |||||
| ### `Theme.current()` | |||||
| Gets the currently active theme. | |||||
| **Parameters:** None | |||||
| **Returns:** `string` - The current theme (`'light'` or `'dark'`) | |||||
| **Example:** | |||||
| ```javascript | |||||
| const currentTheme = Theme.current(); | |||||
| console.log(currentTheme); // 'light' or 'dark' | |||||
| // Use in conditional logic | |||||
| if (Theme.current() === 'dark') { | |||||
| // Dark theme specific logic | |||||
| } | |||||
| ``` | |||||
| --- | |||||
| ### `Theme.init()` | |||||
| Initializes the theme system. Called automatically on page load. | |||||
| **Parameters:** None | |||||
| **Returns:** `void` | |||||
| **Example:** | |||||
| ```javascript | |||||
| // Manual initialization (usually not needed) | |||||
| Theme.init(); | |||||
| ``` | |||||
| **Behavior:** | |||||
| - Checks for stored theme preference in localStorage | |||||
| - If no stored preference, detects OS color scheme preference | |||||
| - Applies the determined theme | |||||
| - Sets up Chart.js defaults if available | |||||
| --- | |||||
| ### `Theme.getCSSVar(varName)` | |||||
| Retrieves the computed value of a CSS custom property. | |||||
| **Parameters:** | |||||
| - `varName` (string): The CSS variable name (including `--` prefix) | |||||
| **Returns:** `string` - The computed CSS variable value | |||||
| **Example:** | |||||
| ```javascript | |||||
| // Get primary color | |||||
| const primaryColor = Theme.getCSSVar('--c-primary'); | |||||
| console.log(primaryColor); // '#4b7cf3' | |||||
| // Get background color | |||||
| const bgColor = Theme.getCSSVar('--c-bkg-body'); | |||||
| console.log(bgColor); // '#f8f9fa' or '#181a1f' | |||||
| ``` | |||||
| ## Specialized Color Methods | |||||
| ### `Theme.getChartColors()` | |||||
| Gets color values optimized for Chart.js components. | |||||
| **Parameters:** None | |||||
| **Returns:** `object` - Chart color configuration | |||||
| **Return Object:** | |||||
| ```javascript | |||||
| { | |||||
| textColor: string, // Primary text color | |||||
| mutedColor: string, // Secondary text color | |||||
| borderColor: string, // Border colors | |||||
| gridColor: string, // Grid line colors | |||||
| tooltipBg: string // Tooltip background | |||||
| } | |||||
| ``` | |||||
| **Example:** | |||||
| ```javascript | |||||
| const chartColors = Theme.getChartColors(); | |||||
| const chart = new Chart(ctx, { | |||||
| options: { | |||||
| plugins: { | |||||
| legend: { | |||||
| labels: { | |||||
| color: chartColors.textColor | |||||
| } | |||||
| } | |||||
| }, | |||||
| scales: { | |||||
| y: { | |||||
| ticks: { color: chartColors.mutedColor }, | |||||
| grid: { color: chartColors.gridColor } | |||||
| } | |||||
| } | |||||
| } | |||||
| }); | |||||
| ``` | |||||
| --- | |||||
| ### `Theme.getVectorMapColors()` | |||||
| Gets color palette for vector map components. | |||||
| **Parameters:** None | |||||
| **Returns:** `object` - Vector map color configuration | |||||
| **Return Object:** | |||||
| ```javascript | |||||
| { | |||||
| backgroundColor: string, // Map background | |||||
| borderColor: string, // Map borders | |||||
| regionColor: string, // Default region color | |||||
| markerFill: string, // Marker fill color | |||||
| markerStroke: string, // Marker stroke color | |||||
| hoverColor: string, // Hover state color | |||||
| selectedColor: string, // Selected state color | |||||
| scaleStart: string, // Color scale start | |||||
| scaleEnd: string, // Color scale end | |||||
| scaleLight: string, // Light scale color | |||||
| scaleDark: string // Dark scale color | |||||
| } | |||||
| ``` | |||||
| **Example:** | |||||
| ```javascript | |||||
| const mapColors = Theme.getVectorMapColors(); | |||||
| $('#world-map').vectorMap({ | |||||
| backgroundColor: mapColors.backgroundColor, | |||||
| regionStyle: { | |||||
| initial: { | |||||
| fill: mapColors.regionColor, | |||||
| stroke: mapColors.borderColor | |||||
| }, | |||||
| hover: { | |||||
| fill: mapColors.hoverColor | |||||
| } | |||||
| } | |||||
| }); | |||||
| ``` | |||||
| --- | |||||
| ### `Theme.getSparklineColors()` | |||||
| Gets color palette for Sparkline chart components. | |||||
| **Parameters:** None | |||||
| **Returns:** `object` - Sparkline color configuration | |||||
| **Return Object:** | |||||
| ```javascript | |||||
| { | |||||
| success: string, // Success state color | |||||
| purple: string, // Purple variant | |||||
| info: string, // Info state color | |||||
| danger: string, // Danger state color | |||||
| light: string // Light variant | |||||
| } | |||||
| ``` | |||||
| **Example:** | |||||
| ```javascript | |||||
| const sparklineColors = Theme.getSparklineColors(); | |||||
| $('.sparkline-success').sparkline(data, { | |||||
| lineColor: sparklineColors.success, | |||||
| fillColor: false | |||||
| }); | |||||
| ``` | |||||
| ## Event System | |||||
| ### Theme Change Event | |||||
| The theme system dispatches custom events when themes change. | |||||
| **Event Name:** `adminator:themeChanged` | |||||
| **Event Detail:** | |||||
| ```javascript | |||||
| { | |||||
| theme: string // The new theme ('light' or 'dark') | |||||
| } | |||||
| ``` | |||||
| **Example:** | |||||
| ```javascript | |||||
| // Listen for theme changes | |||||
| window.addEventListener('adminator:themeChanged', (event) => { | |||||
| const newTheme = event.detail.theme; | |||||
| console.log('Theme changed to:', newTheme); | |||||
| // Update custom components | |||||
| updateCustomComponent(newTheme); | |||||
| }); | |||||
| // Alternative using jQuery | |||||
| $(window).on('adminator:themeChanged', function(event) { | |||||
| const newTheme = event.originalEvent.detail.theme; | |||||
| // Handle theme change | |||||
| }); | |||||
| ``` | |||||
| ## Storage Management | |||||
| ### Local Storage Key | |||||
| The theme preference is stored using the key: `'adminator-theme'` | |||||
| **Example:** | |||||
| ```javascript | |||||
| // Manually check stored theme | |||||
| const storedTheme = localStorage.getItem('adminator-theme'); | |||||
| console.log(storedTheme); // 'light', 'dark', or null | |||||
| // Manually set theme preference | |||||
| localStorage.setItem('adminator-theme', 'dark'); | |||||
| ``` | |||||
| ### Fallback Handling | |||||
| The Theme API gracefully handles storage unavailability: | |||||
| ```javascript | |||||
| // Internal implementation example | |||||
| try { | |||||
| localStorage.setItem('adminator-theme', theme); | |||||
| } catch (_) { | |||||
| // Storage not available - theme won't persist | |||||
| // But theme will still work for current session | |||||
| } | |||||
| ``` | |||||
| ## Integration Examples | |||||
| ### React Integration | |||||
| ```javascript | |||||
| import { useEffect, useState } from 'react'; | |||||
| function useTheme() { | |||||
| const [theme, setTheme] = useState(Theme.current()); | |||||
| useEffect(() => { | |||||
| const handleThemeChange = (event) => { | |||||
| setTheme(event.detail.theme); | |||||
| }; | |||||
| window.addEventListener('adminator:themeChanged', handleThemeChange); | |||||
| return () => { | |||||
| window.removeEventListener('adminator:themeChanged', handleThemeChange); | |||||
| }; | |||||
| }, []); | |||||
| return { | |||||
| theme, | |||||
| toggle: Theme.toggle, | |||||
| setTheme: Theme.apply | |||||
| }; | |||||
| } | |||||
| ``` | |||||
| ### Vue.js Integration | |||||
| ```javascript | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| currentTheme: Theme.current() | |||||
| } | |||||
| }, | |||||
| mounted() { | |||||
| window.addEventListener('adminator:themeChanged', this.handleThemeChange); | |||||
| }, | |||||
| beforeDestroy() { | |||||
| window.removeEventListener('adminator:themeChanged', this.handleThemeChange); | |||||
| }, | |||||
| methods: { | |||||
| handleThemeChange(event) { | |||||
| this.currentTheme = event.detail.theme; | |||||
| }, | |||||
| toggleTheme() { | |||||
| Theme.toggle(); | |||||
| } | |||||
| } | |||||
| } | |||||
| ``` | |||||
| ### Custom Component Integration | |||||
| ```javascript | |||||
| class CustomWidget { | |||||
| constructor(element) { | |||||
| this.element = element; | |||||
| this.currentTheme = Theme.current(); | |||||
| this.init(); | |||||
| this.bindEvents(); | |||||
| } | |||||
| init() { | |||||
| this.updateTheme(this.currentTheme); | |||||
| } | |||||
| bindEvents() { | |||||
| window.addEventListener('adminator:themeChanged', (event) => { | |||||
| this.currentTheme = event.detail.theme; | |||||
| this.updateTheme(this.currentTheme); | |||||
| }); | |||||
| } | |||||
| updateTheme(theme) { | |||||
| // Update widget based on theme | |||||
| if (theme === 'dark') { | |||||
| this.element.classList.add('widget-dark'); | |||||
| this.element.style.backgroundColor = Theme.getCSSVar('--c-bkg-card'); | |||||
| } else { | |||||
| this.element.classList.remove('widget-dark'); | |||||
| this.element.style.backgroundColor = Theme.getCSSVar('--c-bkg-card'); | |||||
| } | |||||
| } | |||||
| } | |||||
| ``` | |||||
| ## Error Handling | |||||
| ### Browser Compatibility | |||||
| ```javascript | |||||
| // Check for CSS custom property support | |||||
| function supportsCSSVariables() { | |||||
| return window.CSS && CSS.supports('color', 'var(--fake-var)'); | |||||
| } | |||||
| if (!supportsCSSVariables()) { | |||||
| console.warn('CSS variables not supported - theme switching limited'); | |||||
| } | |||||
| ``` | |||||
| ### LocalStorage Availability | |||||
| ```javascript | |||||
| // Check for localStorage support | |||||
| function supportsLocalStorage() { | |||||
| try { | |||||
| return 'localStorage' in window && window['localStorage'] !== null; | |||||
| } catch (e) { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| if (!supportsLocalStorage()) { | |||||
| console.warn('localStorage not available - theme preference won\'t persist'); | |||||
| } | |||||
| ``` | |||||
| ## Performance Considerations | |||||
| ### Debounced Theme Changes | |||||
| For applications with many theme-aware components: | |||||
| ```javascript | |||||
| let themeChangeTimeout; | |||||
| window.addEventListener('adminator:themeChanged', (event) => { | |||||
| clearTimeout(themeChangeTimeout); | |||||
| themeChangeTimeout = setTimeout(() => { | |||||
| // Expensive theme update operations | |||||
| updateManyComponents(event.detail.theme); | |||||
| }, 100); | |||||
| }); | |||||
| ``` | |||||
| ### Efficient CSS Variable Reading | |||||
| Cache CSS variable values when possible: | |||||
| ```javascript | |||||
| class ThemeCache { | |||||
| constructor() { | |||||
| this.cache = new Map(); | |||||
| this.cacheTheme = null; | |||||
| } | |||||
| getCSSVar(varName) { | |||||
| const currentTheme = Theme.current(); | |||||
| if (this.cacheTheme !== currentTheme) { | |||||
| this.cache.clear(); | |||||
| this.cacheTheme = currentTheme; | |||||
| } | |||||
| if (!this.cache.has(varName)) { | |||||
| const value = Theme.getCSSVar(varName); | |||||
| this.cache.set(varName, value); | |||||
| } | |||||
| return this.cache.get(varName); | |||||
| } | |||||
| } | |||||
| ``` | |||||
| --- | |||||
| **Next:** Explore [Component APIs](component-apis.md) or check out [Theme Integration Examples](../examples/theme-integration.md). | |||||
| @ -0,0 +1,356 @@ | |||||
| # Theme System Overview | |||||
| Adminator v2.6.0 introduces a comprehensive dark mode system with intelligent theme switching and component integration. | |||||
| ## ๐ Features | |||||
| ### Core Capabilities | |||||
| - **๐ Smart Toggle**: Bootstrap-based switch with sun/moon icons | |||||
| - **๐ OS Detection**: Automatically detects and applies system preference | |||||
| - **๐พ Persistent Storage**: Remembers theme choice across browser sessions | |||||
| - **โก Instant Switching**: Real-time theme updates without page reload | |||||
| - **๐ฏ Component Integration**: All elements are theme-aware | |||||
| ### Visual Enhancements | |||||
| - **๐จ Semantic Colors**: Consistent color variables across components | |||||
| - **๐ Chart Integration**: Dynamic color schemes for Chart.js | |||||
| - **๐๏ธ Calendar Support**: Dark-mode aware FullCalendar | |||||
| - **๐บ๏ธ Map Theming**: Custom color palettes for vector and Google maps | |||||
| ## ๐ Quick Start | |||||
| ### Basic Usage | |||||
| The theme system is automatically initialized when the page loads: | |||||
| ```javascript | |||||
| // The theme toggle is automatically injected into the header | |||||
| // Users can click the Light/Dark switch to change themes | |||||
| ``` | |||||
| ### Programmatic Control | |||||
| ```javascript | |||||
| // Get current theme | |||||
| const currentTheme = Theme.current(); // 'light' or 'dark' | |||||
| // Switch themes | |||||
| Theme.toggle(); | |||||
| // Set specific theme | |||||
| Theme.apply('dark'); | |||||
| Theme.apply('light'); | |||||
| // Listen for theme changes | |||||
| window.addEventListener('adminator:themeChanged', (event) => { | |||||
| console.log('Theme changed to:', event.detail.theme); | |||||
| // Your custom logic here | |||||
| }); | |||||
| ``` | |||||
| ## ๐จ CSS Variables | |||||
| ### Core Theme Variables | |||||
| ```css | |||||
| :root { | |||||
| /* Backgrounds */ | |||||
| --c-bkg-body: #f8f9fa; /* Main page background */ | |||||
| --c-bkg-card: #ffffff; /* Card and panel backgrounds */ | |||||
| --c-bkg-sidebar: #ffffff; /* Sidebar background */ | |||||
| /* Text Colors */ | |||||
| --c-text-base: #212529; /* Primary text color */ | |||||
| --c-text-muted: #6c757d; /* Secondary text color */ | |||||
| /* UI Elements */ | |||||
| --c-border: #e2e5e8; /* Border colors */ | |||||
| --c-primary: #4b7cf3; /* Primary brand color */ | |||||
| --c-success: #2ecc71; /* Success state color */ | |||||
| --c-danger: #e74c3c; /* Error state color */ | |||||
| } | |||||
| /* Dark theme overrides */ | |||||
| [data-theme="dark"] { | |||||
| --c-bkg-body: #181a1f; | |||||
| --c-bkg-card: #20232a; | |||||
| --c-bkg-sidebar: #20232a; | |||||
| --c-text-base: #e8eaed; | |||||
| --c-text-muted: #9ca3af; | |||||
| --c-border: #2b2f36; | |||||
| /* ... additional dark theme variables */ | |||||
| } | |||||
| ``` | |||||
| ### Component-Specific Variables | |||||
| ```css | |||||
| :root { | |||||
| /* Vector Maps */ | |||||
| --vmap-bg-color: #ffffff; | |||||
| --vmap-region-color: #e4ecef; | |||||
| --vmap-hover-color: #ffffff; | |||||
| /* Charts */ | |||||
| --sparkline-success: #4caf50; | |||||
| --sparkline-info: #03a9f3; | |||||
| --sparkline-danger: #f96262; | |||||
| /* Maps */ | |||||
| --gmap-landscape-hue: #FFBB00; | |||||
| --gmap-water-hue: #0078FF; | |||||
| } | |||||
| ``` | |||||
| ## ๐ง Implementation Details | |||||
| ### Theme Toggle Component | |||||
| The theme toggle is automatically injected into the navigation: | |||||
| ```html | |||||
| <!-- Automatically generated theme toggle --> | |||||
| <li class="theme-toggle d-flex ai-c"> | |||||
| <div class="form-check form-switch d-flex ai-c"> | |||||
| <label class="form-check-label me-2 text-nowrap c-grey-700" for="theme-toggle"> | |||||
| <i class="ti-sun"></i> Light | |||||
| </label> | |||||
| <input class="form-check-input" type="checkbox" id="theme-toggle"> | |||||
| <label class="form-check-label ms-2 text-nowrap c-grey-700" for="theme-toggle"> | |||||
| Dark <i class="ti-moon"></i> | |||||
| </label> | |||||
| </div> | |||||
| </li> | |||||
| ``` | |||||
| ### Theme Detection Logic | |||||
| ```javascript | |||||
| // Automatic OS preference detection | |||||
| if (!localStorage.getItem('adminator-theme')) { | |||||
| const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; | |||||
| Theme.apply(prefersDark ? 'dark' : 'light'); | |||||
| } else { | |||||
| Theme.apply(Theme.current()); | |||||
| } | |||||
| ``` | |||||
| ## ๐ฏ Component Integration | |||||
| ### Chart.js Integration | |||||
| Charts automatically update colors when themes change: | |||||
| ```javascript | |||||
| // Chart colors are automatically updated | |||||
| const chartColors = Theme.getChartColors(); | |||||
| // Returns: { textColor, mutedColor, borderColor, gridColor, tooltipBg } | |||||
| // Custom chart configuration | |||||
| const chart = new Chart(ctx, { | |||||
| data: data, | |||||
| options: { | |||||
| plugins: { | |||||
| legend: { | |||||
| labels: { | |||||
| color: chartColors.textColor | |||||
| } | |||||
| } | |||||
| }, | |||||
| scales: { | |||||
| y: { | |||||
| ticks: { | |||||
| color: chartColors.mutedColor | |||||
| }, | |||||
| grid: { | |||||
| color: chartColors.gridColor | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| }); | |||||
| ``` | |||||
| ### FullCalendar Integration | |||||
| Calendar styling updates automatically: | |||||
| ```css | |||||
| /* Automatic dark mode calendar styling */ | |||||
| .fc { | |||||
| background: var(--c-bkg-card); | |||||
| color: var(--c-text-base); | |||||
| } | |||||
| .fc-event { | |||||
| border-color: var(--c-border) !important; | |||||
| } | |||||
| .fc-daygrid-day { | |||||
| border-color: var(--c-border) !important; | |||||
| } | |||||
| ``` | |||||
| ### Vector Maps Integration | |||||
| Maps use theme-aware color palettes: | |||||
| ```javascript | |||||
| // Get vector map colors for current theme | |||||
| const mapColors = Theme.getVectorMapColors(); | |||||
| /* Returns: | |||||
| { | |||||
| backgroundColor: '#ffffff' | '#20232a', | |||||
| regionColor: '#e4ecef' | '#2b2f36', | |||||
| hoverColor: '#ffffff' | '#181a1f', | |||||
| // ... other map-specific colors | |||||
| } | |||||
| */ | |||||
| ``` | |||||
| ## ๐จ Custom Styling | |||||
| ### Using CSS Variables | |||||
| Style your components with theme-aware variables: | |||||
| ```css | |||||
| .my-custom-component { | |||||
| background: var(--c-bkg-card); | |||||
| color: var(--c-text-base); | |||||
| border: 1px solid var(--c-border); | |||||
| border-radius: 8px; | |||||
| padding: 1rem; | |||||
| } | |||||
| .my-custom-button { | |||||
| background: var(--c-primary); | |||||
| color: white; | |||||
| border: none; | |||||
| padding: 0.5rem 1rem; | |||||
| border-radius: 4px; | |||||
| } | |||||
| .my-custom-button:hover { | |||||
| background: var(--c-primary); | |||||
| opacity: 0.9; | |||||
| } | |||||
| ``` | |||||
| ### Creating Theme-Aware Components | |||||
| ```javascript | |||||
| class MyCustomComponent { | |||||
| constructor(element) { | |||||
| this.element = element; | |||||
| this.init(); | |||||
| // Listen for theme changes | |||||
| window.addEventListener('adminator:themeChanged', (event) => { | |||||
| this.updateTheme(event.detail.theme); | |||||
| }); | |||||
| } | |||||
| updateTheme(theme) { | |||||
| // Update component based on theme | |||||
| if (theme === 'dark') { | |||||
| this.element.classList.add('dark-mode'); | |||||
| } else { | |||||
| this.element.classList.remove('dark-mode'); | |||||
| } | |||||
| } | |||||
| } | |||||
| ``` | |||||
| ## ๐ Advanced Usage | |||||
| ### Custom Theme Colors | |||||
| Override default theme colors: | |||||
| ```css | |||||
| :root { | |||||
| /* Custom brand colors */ | |||||
| --c-primary: #your-brand-color; | |||||
| --c-success: #your-success-color; | |||||
| } | |||||
| [data-theme="dark"] { | |||||
| /* Custom dark theme colors */ | |||||
| --c-primary: #your-dark-brand-color; | |||||
| --c-success: #your-dark-success-color; | |||||
| } | |||||
| ``` | |||||
| ### Theme-Specific Images | |||||
| Use different images for light/dark themes: | |||||
| ```css | |||||
| .logo { | |||||
| background-image: url('logo-light.png'); | |||||
| } | |||||
| [data-theme="dark"] .logo { | |||||
| background-image: url('logo-dark.png'); | |||||
| } | |||||
| ``` | |||||
| ### Dynamic Theme Updates | |||||
| Create dynamic theme switching animations: | |||||
| ```css | |||||
| /* Smooth theme transitions */ | |||||
| * { | |||||
| transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease; | |||||
| } | |||||
| /* Disable transitions during theme switch */ | |||||
| .theme-transitioning * { | |||||
| transition: none !important; | |||||
| } | |||||
| ``` | |||||
| ## ๐ Troubleshooting | |||||
| ### Common Issues | |||||
| #### Theme Not Persisting | |||||
| ```javascript | |||||
| // Check localStorage availability | |||||
| if (typeof(Storage) !== "undefined") { | |||||
| // localStorage is available | |||||
| } else { | |||||
| // No web storage support | |||||
| console.warn('localStorage not available - theme won\'t persist'); | |||||
| } | |||||
| ``` | |||||
| #### Components Not Updating | |||||
| ```javascript | |||||
| // Ensure components listen for theme changes | |||||
| window.addEventListener('adminator:themeChanged', (event) => { | |||||
| // Force component update | |||||
| myComponent.refresh(); | |||||
| }); | |||||
| ``` | |||||
| #### CSS Variables Not Working | |||||
| ```css | |||||
| /* Fallback for older browsers */ | |||||
| .my-component { | |||||
| background: #ffffff; /* Fallback */ | |||||
| background: var(--c-bkg-card); /* Modern */ | |||||
| } | |||||
| ``` | |||||
| ## ๐ Related Documentation | |||||
| - **[CSS Variables Reference](css-variables.md)** - Complete variable list | |||||
| - **[Custom Theme Creation](custom-themes.md)** - Create your own themes | |||||
| - **[Component Theming](component-theming.md)** - Theme individual components | |||||
| --- | |||||
| **Ready to customize?** Start with the [CSS Variables Reference](css-variables.md) or explore [Custom Theme Creation](custom-themes.md)! | |||||
| @ -0,0 +1,664 @@ | |||||
| # Theme Integration Examples | |||||
| Practical examples for integrating custom components with Adminator's theme system. | |||||
| ## Basic Theme-Aware Component | |||||
| ### Simple CSS Integration | |||||
| Create components that automatically adapt to theme changes: | |||||
| ```html | |||||
| <!-- HTML --> | |||||
| <div class="custom-widget"> | |||||
| <h3 class="widget-title">My Custom Widget</h3> | |||||
| <div class="widget-content"> | |||||
| <p>This widget adapts to the current theme.</p> | |||||
| <button class="widget-button">Action</button> | |||||
| </div> | |||||
| </div> | |||||
| ``` | |||||
| ```css | |||||
| /* CSS using theme variables */ | |||||
| .custom-widget { | |||||
| background: var(--c-bkg-card); | |||||
| color: var(--c-text-base); | |||||
| border: 1px solid var(--c-border); | |||||
| border-radius: 8px; | |||||
| padding: 1.5rem; | |||||
| margin-bottom: 1rem; | |||||
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |||||
| } | |||||
| .widget-title { | |||||
| color: var(--c-text-base); | |||||
| margin-bottom: 1rem; | |||||
| font-size: 1.25rem; | |||||
| font-weight: 600; | |||||
| } | |||||
| .widget-content { | |||||
| color: var(--c-text-muted); | |||||
| line-height: 1.6; | |||||
| } | |||||
| .widget-button { | |||||
| background: var(--c-primary); | |||||
| color: white; | |||||
| border: none; | |||||
| padding: 0.5rem 1rem; | |||||
| border-radius: 4px; | |||||
| cursor: pointer; | |||||
| transition: opacity 0.2s ease; | |||||
| } | |||||
| .widget-button:hover { | |||||
| opacity: 0.9; | |||||
| } | |||||
| /* Dark theme specific adjustments */ | |||||
| [data-theme="dark"] .custom-widget { | |||||
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); | |||||
| } | |||||
| ``` | |||||
| ## JavaScript Integration | |||||
| ### Theme-Aware Class Component | |||||
| ```javascript | |||||
| class ThemeAwareWidget { | |||||
| constructor(element, options = {}) { | |||||
| this.element = element; | |||||
| this.options = { | |||||
| autoUpdate: true, | |||||
| customColors: {}, | |||||
| ...options | |||||
| }; | |||||
| this.currentTheme = Theme.current(); | |||||
| this.init(); | |||||
| } | |||||
| init() { | |||||
| this.render(); | |||||
| this.bindEvents(); | |||||
| this.updateTheme(this.currentTheme); | |||||
| } | |||||
| render() { | |||||
| this.element.innerHTML = ` | |||||
| <div class="theme-widget"> | |||||
| <div class="widget-header"> | |||||
| <h4>Theme-Aware Widget</h4> | |||||
| <span class="theme-indicator">${this.currentTheme}</span> | |||||
| </div> | |||||
| <div class="widget-body"> | |||||
| <div class="color-preview"> | |||||
| <div class="color-sample" data-color="primary"></div> | |||||
| <div class="color-sample" data-color="success"></div> | |||||
| <div class="color-sample" data-color="danger"></div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| `; | |||||
| } | |||||
| bindEvents() { | |||||
| if (this.options.autoUpdate) { | |||||
| window.addEventListener('adminator:themeChanged', (event) => { | |||||
| this.currentTheme = event.detail.theme; | |||||
| this.updateTheme(this.currentTheme); | |||||
| }); | |||||
| } | |||||
| } | |||||
| updateTheme(theme) { | |||||
| const widget = this.element.querySelector('.theme-widget'); | |||||
| // Update theme indicator | |||||
| const indicator = widget.querySelector('.theme-indicator'); | |||||
| indicator.textContent = theme; | |||||
| indicator.className = `theme-indicator theme-${theme}`; | |||||
| // Update color samples | |||||
| const samples = widget.querySelectorAll('.color-sample'); | |||||
| samples.forEach(sample => { | |||||
| const colorType = sample.dataset.color; | |||||
| const cssVar = `--c-${colorType}`; | |||||
| const color = Theme.getCSSVar(cssVar); | |||||
| sample.style.backgroundColor = color; | |||||
| }); | |||||
| // Apply custom colors if provided | |||||
| if (this.options.customColors[theme]) { | |||||
| Object.entries(this.options.customColors[theme]).forEach(([property, value]) => { | |||||
| widget.style.setProperty(property, value); | |||||
| }); | |||||
| } | |||||
| // Trigger custom update callback | |||||
| if (this.options.onThemeChange) { | |||||
| this.options.onThemeChange(theme, this); | |||||
| } | |||||
| } | |||||
| // Public methods | |||||
| setTheme(theme) { | |||||
| Theme.apply(theme); | |||||
| } | |||||
| getCurrentColors() { | |||||
| return { | |||||
| primary: Theme.getCSSVar('--c-primary'), | |||||
| success: Theme.getCSSVar('--c-success'), | |||||
| danger: Theme.getCSSVar('--c-danger'), | |||||
| background: Theme.getCSSVar('--c-bkg-card'), | |||||
| text: Theme.getCSSVar('--c-text-base') | |||||
| }; | |||||
| } | |||||
| destroy() { | |||||
| // Cleanup event listeners | |||||
| window.removeEventListener('adminator:themeChanged', this.updateTheme); | |||||
| } | |||||
| } | |||||
| // Usage | |||||
| const widget = new ThemeAwareWidget(document.getElementById('my-widget'), { | |||||
| customColors: { | |||||
| dark: { | |||||
| '--custom-accent': '#ff6b6b' | |||||
| }, | |||||
| light: { | |||||
| '--custom-accent': '#4dabf7' | |||||
| } | |||||
| }, | |||||
| onThemeChange: (theme, instance) => { | |||||
| console.log(`Widget theme changed to: ${theme}`); | |||||
| } | |||||
| }); | |||||
| ``` | |||||
| ## Chart Integration | |||||
| ### Theme-Aware Chart.js | |||||
| ```javascript | |||||
| class ThemeChart { | |||||
| constructor(canvas, data, options = {}) { | |||||
| this.canvas = canvas; | |||||
| this.data = data; | |||||
| this.options = options; | |||||
| this.chart = null; | |||||
| this.init(); | |||||
| } | |||||
| init() { | |||||
| this.createChart(); | |||||
| this.bindThemeEvents(); | |||||
| } | |||||
| createChart() { | |||||
| const colors = Theme.getChartColors(); | |||||
| const config = { | |||||
| type: this.options.type || 'line', | |||||
| data: this.processData(this.data, colors), | |||||
| options: { | |||||
| responsive: true, | |||||
| plugins: { | |||||
| legend: { | |||||
| labels: { | |||||
| color: colors.textColor, | |||||
| usePointStyle: true | |||||
| } | |||||
| }, | |||||
| tooltip: { | |||||
| backgroundColor: colors.tooltipBg, | |||||
| titleColor: colors.textColor, | |||||
| bodyColor: colors.textColor, | |||||
| borderColor: colors.borderColor, | |||||
| borderWidth: 1 | |||||
| } | |||||
| }, | |||||
| scales: { | |||||
| x: { | |||||
| ticks: { | |||||
| color: colors.mutedColor | |||||
| }, | |||||
| grid: { | |||||
| color: colors.gridColor | |||||
| } | |||||
| }, | |||||
| y: { | |||||
| ticks: { | |||||
| color: colors.mutedColor | |||||
| }, | |||||
| grid: { | |||||
| color: colors.gridColor | |||||
| } | |||||
| } | |||||
| }, | |||||
| ...this.options.chartOptions | |||||
| } | |||||
| }; | |||||
| this.chart = new Chart(this.canvas, config); | |||||
| } | |||||
| processData(data, colors) { | |||||
| return { | |||||
| ...data, | |||||
| datasets: data.datasets.map((dataset, index) => ({ | |||||
| ...dataset, | |||||
| borderColor: dataset.borderColor || this.getDatasetColor(index, colors), | |||||
| backgroundColor: dataset.backgroundColor || this.getDatasetColor(index, colors, 0.2) | |||||
| })) | |||||
| }; | |||||
| } | |||||
| getDatasetColor(index, colors, alpha = 1) { | |||||
| const colorKeys = ['primary', 'success', 'danger', 'info', 'warning']; | |||||
| const colorKey = colorKeys[index % colorKeys.length]; | |||||
| const color = Theme.getCSSVar(`--c-${colorKey}`); | |||||
| if (alpha < 1) { | |||||
| // Convert hex to rgba | |||||
| const r = parseInt(color.slice(1, 3), 16); | |||||
| const g = parseInt(color.slice(3, 5), 16); | |||||
| const b = parseInt(color.slice(5, 7), 16); | |||||
| return `rgba(${r}, ${g}, ${b}, ${alpha})`; | |||||
| } | |||||
| return color; | |||||
| } | |||||
| bindThemeEvents() { | |||||
| window.addEventListener('adminator:themeChanged', () => { | |||||
| this.updateChart(); | |||||
| }); | |||||
| } | |||||
| updateChart() { | |||||
| if (!this.chart) return; | |||||
| const colors = Theme.getChartColors(); | |||||
| // Update chart options | |||||
| this.chart.options.plugins.legend.labels.color = colors.textColor; | |||||
| this.chart.options.plugins.tooltip.backgroundColor = colors.tooltipBg; | |||||
| this.chart.options.plugins.tooltip.titleColor = colors.textColor; | |||||
| this.chart.options.plugins.tooltip.bodyColor = colors.textColor; | |||||
| this.chart.options.plugins.tooltip.borderColor = colors.borderColor; | |||||
| // Update scales | |||||
| this.chart.options.scales.x.ticks.color = colors.mutedColor; | |||||
| this.chart.options.scales.x.grid.color = colors.gridColor; | |||||
| this.chart.options.scales.y.ticks.color = colors.mutedColor; | |||||
| this.chart.options.scales.y.grid.color = colors.gridColor; | |||||
| // Update dataset colors | |||||
| this.chart.data.datasets.forEach((dataset, index) => { | |||||
| dataset.borderColor = this.getDatasetColor(index, colors); | |||||
| dataset.backgroundColor = this.getDatasetColor(index, colors, 0.2); | |||||
| }); | |||||
| this.chart.update(); | |||||
| } | |||||
| destroy() { | |||||
| if (this.chart) { | |||||
| this.chart.destroy(); | |||||
| } | |||||
| } | |||||
| } | |||||
| // Usage | |||||
| const chartData = { | |||||
| labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], | |||||
| datasets: [{ | |||||
| label: 'Sales', | |||||
| data: [12, 19, 3, 5, 2, 3] | |||||
| }, { | |||||
| label: 'Revenue', | |||||
| data: [2, 3, 20, 5, 1, 4] | |||||
| }] | |||||
| }; | |||||
| const themeChart = new ThemeChart( | |||||
| document.getElementById('myChart'), | |||||
| chartData, | |||||
| { | |||||
| type: 'line', | |||||
| chartOptions: { | |||||
| tension: 0.4 | |||||
| } | |||||
| } | |||||
| ); | |||||
| ``` | |||||
| ## Custom Modal Integration | |||||
| ### Theme-Aware Modal | |||||
| ```javascript | |||||
| class ThemeModal { | |||||
| constructor(options = {}) { | |||||
| this.options = { | |||||
| title: 'Modal Title', | |||||
| content: '', | |||||
| size: 'md', // sm, md, lg, xl | |||||
| backdrop: true, | |||||
| keyboard: true, | |||||
| ...options | |||||
| }; | |||||
| this.modal = null; | |||||
| this.element = null; | |||||
| this.currentTheme = Theme.current(); | |||||
| this.init(); | |||||
| } | |||||
| init() { | |||||
| this.createElement(); | |||||
| this.bindEvents(); | |||||
| this.updateTheme(this.currentTheme); | |||||
| } | |||||
| createElement() { | |||||
| const modalId = `modal-${Date.now()}`; | |||||
| const modalHTML = ` | |||||
| <div class="modal fade theme-modal" id="${modalId}" tabindex="-1"> | |||||
| <div class="modal-dialog modal-${this.options.size}"> | |||||
| <div class="modal-content"> | |||||
| <div class="modal-header"> | |||||
| <h5 class="modal-title">${this.options.title}</h5> | |||||
| <button type="button" class="btn-close" data-bs-dismiss="modal"></button> | |||||
| </div> | |||||
| <div class="modal-body"> | |||||
| ${this.options.content} | |||||
| </div> | |||||
| <div class="modal-footer"> | |||||
| <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> | |||||
| <button type="button" class="btn btn-primary modal-action">Save</button> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| `; | |||||
| document.body.insertAdjacentHTML('beforeend', modalHTML); | |||||
| this.element = document.getElementById(modalId); | |||||
| // Initialize Bootstrap modal | |||||
| this.modal = new bootstrap.Modal(this.element, { | |||||
| backdrop: this.options.backdrop, | |||||
| keyboard: this.options.keyboard | |||||
| }); | |||||
| } | |||||
| bindEvents() { | |||||
| // Theme change event | |||||
| window.addEventListener('adminator:themeChanged', (event) => { | |||||
| this.currentTheme = event.detail.theme; | |||||
| this.updateTheme(this.currentTheme); | |||||
| }); | |||||
| // Action button click | |||||
| const actionButton = this.element.querySelector('.modal-action'); | |||||
| actionButton.addEventListener('click', () => { | |||||
| if (this.options.onAction) { | |||||
| this.options.onAction(this); | |||||
| } | |||||
| }); | |||||
| // Cleanup on hide | |||||
| this.element.addEventListener('hidden.bs.modal', () => { | |||||
| if (this.options.autoDestroy !== false) { | |||||
| this.destroy(); | |||||
| } | |||||
| }); | |||||
| } | |||||
| updateTheme(theme) { | |||||
| const content = this.element.querySelector('.modal-content'); | |||||
| // Apply theme-specific styles | |||||
| content.style.backgroundColor = Theme.getCSSVar('--c-bkg-card'); | |||||
| content.style.color = Theme.getCSSVar('--c-text-base'); | |||||
| content.style.border = `1px solid ${Theme.getCSSVar('--c-border')}`; | |||||
| // Update header | |||||
| const header = this.element.querySelector('.modal-header'); | |||||
| header.style.borderBottom = `1px solid ${Theme.getCSSVar('--c-border')}`; | |||||
| // Update footer | |||||
| const footer = this.element.querySelector('.modal-footer'); | |||||
| footer.style.borderTop = `1px solid ${Theme.getCSSVar('--c-border')}`; | |||||
| // Update close button for dark theme | |||||
| const closeButton = this.element.querySelector('.btn-close'); | |||||
| if (theme === 'dark') { | |||||
| closeButton.classList.add('btn-close-white'); | |||||
| } else { | |||||
| closeButton.classList.remove('btn-close-white'); | |||||
| } | |||||
| } | |||||
| show() { | |||||
| this.modal.show(); | |||||
| } | |||||
| hide() { | |||||
| this.modal.hide(); | |||||
| } | |||||
| destroy() { | |||||
| if (this.modal) { | |||||
| this.modal.dispose(); | |||||
| } | |||||
| if (this.element) { | |||||
| this.element.remove(); | |||||
| } | |||||
| } | |||||
| } | |||||
| // Usage | |||||
| const modal = new ThemeModal({ | |||||
| title: 'Theme-Aware Modal', | |||||
| content: '<p>This modal adapts to the current theme automatically.</p>', | |||||
| size: 'lg', | |||||
| onAction: (modalInstance) => { | |||||
| console.log('Action button clicked!'); | |||||
| modalInstance.hide(); | |||||
| } | |||||
| }); | |||||
| modal.show(); | |||||
| ``` | |||||
| ## React Hook Integration | |||||
| ### useTheme Hook | |||||
| ```javascript | |||||
| import { useState, useEffect } from 'react'; | |||||
| // Custom hook for theme management | |||||
| export function useTheme() { | |||||
| const [theme, setTheme] = useState(() => { | |||||
| // Initialize with current theme | |||||
| return window.Theme ? window.Theme.current() : 'light'; | |||||
| }); | |||||
| const [isLoading, setIsLoading] = useState(!window.Theme); | |||||
| useEffect(() => { | |||||
| // Wait for Theme object to be available | |||||
| if (!window.Theme) { | |||||
| const checkTheme = () => { | |||||
| if (window.Theme) { | |||||
| setTheme(window.Theme.current()); | |||||
| setIsLoading(false); | |||||
| } else { | |||||
| setTimeout(checkTheme, 100); | |||||
| } | |||||
| }; | |||||
| checkTheme(); | |||||
| return; | |||||
| } | |||||
| const handleThemeChange = (event) => { | |||||
| setTheme(event.detail.theme); | |||||
| }; | |||||
| window.addEventListener('adminator:themeChanged', handleThemeChange); | |||||
| return () => { | |||||
| window.removeEventListener('adminator:themeChanged', handleThemeChange); | |||||
| }; | |||||
| }, []); | |||||
| const toggleTheme = () => { | |||||
| if (window.Theme) { | |||||
| window.Theme.toggle(); | |||||
| } | |||||
| }; | |||||
| const setSpecificTheme = (newTheme) => { | |||||
| if (window.Theme) { | |||||
| window.Theme.apply(newTheme); | |||||
| } | |||||
| }; | |||||
| const getThemeColors = () => { | |||||
| if (!window.Theme) return {}; | |||||
| return { | |||||
| primary: window.Theme.getCSSVar('--c-primary'), | |||||
| success: window.Theme.getCSSVar('--c-success'), | |||||
| danger: window.Theme.getCSSVar('--c-danger'), | |||||
| background: window.Theme.getCSSVar('--c-bkg-card'), | |||||
| text: window.Theme.getCSSVar('--c-text-base'), | |||||
| muted: window.Theme.getCSSVar('--c-text-muted'), | |||||
| border: window.Theme.getCSSVar('--c-border') | |||||
| }; | |||||
| }; | |||||
| return { | |||||
| theme, | |||||
| isLoading, | |||||
| isDark: theme === 'dark', | |||||
| isLight: theme === 'light', | |||||
| toggle: toggleTheme, | |||||
| setTheme: setSpecificTheme, | |||||
| colors: getThemeColors() | |||||
| }; | |||||
| } | |||||
| // React component using the hook | |||||
| export function ThemeAwareCard({ children, title }) { | |||||
| const { theme, colors, isDark } = useTheme(); | |||||
| const cardStyle = { | |||||
| backgroundColor: colors.background, | |||||
| color: colors.text, | |||||
| border: `1px solid ${colors.border}`, | |||||
| borderRadius: '8px', | |||||
| padding: '1.5rem', | |||||
| boxShadow: isDark | |||||
| ? '0 2px 4px rgba(0, 0, 0, 0.3)' | |||||
| : '0 2px 4px rgba(0, 0, 0, 0.1)' | |||||
| }; | |||||
| const titleStyle = { | |||||
| color: colors.text, | |||||
| marginBottom: '1rem', | |||||
| fontSize: '1.25rem', | |||||
| fontWeight: '600' | |||||
| }; | |||||
| return ( | |||||
| <div style={cardStyle} className={`theme-card theme-${theme}`}> | |||||
| {title && <h3 style={titleStyle}>{title}</h3>} | |||||
| <div style={{ color: colors.muted }}> | |||||
| {children} | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| // Theme toggle button component | |||||
| export function ThemeToggle() { | |||||
| const { theme, toggle, isLoading } = useTheme(); | |||||
| if (isLoading) { | |||||
| return <div>Loading theme...</div>; | |||||
| } | |||||
| return ( | |||||
| <button | |||||
| onClick={toggle} | |||||
| className={`btn btn-outline-${theme === 'dark' ? 'light' : 'dark'}`} | |||||
| > | |||||
| {theme === 'dark' ? 'โ๏ธ Light' : '๐ Dark'} | |||||
| </button> | |||||
| ); | |||||
| } | |||||
| ``` | |||||
| ## Performance Optimization | |||||
| ### Throttled Theme Updates | |||||
| For components with expensive rendering: | |||||
| ```javascript | |||||
| class PerformantThemeComponent { | |||||
| constructor(element) { | |||||
| this.element = element; | |||||
| this.updateTheme = this.throttle(this._updateTheme.bind(this), 100); | |||||
| window.addEventListener('adminator:themeChanged', this.updateTheme); | |||||
| } | |||||
| throttle(func, limit) { | |||||
| let inThrottle; | |||||
| return function() { | |||||
| const args = arguments; | |||||
| const context = this; | |||||
| if (!inThrottle) { | |||||
| func.apply(context, args); | |||||
| inThrottle = true; | |||||
| setTimeout(() => inThrottle = false, limit); | |||||
| } | |||||
| } | |||||
| } | |||||
| _updateTheme(event) { | |||||
| // Expensive theme update operations | |||||
| this.recalculateLayout(); | |||||
| this.updateComplexVisuals(); | |||||
| } | |||||
| recalculateLayout() { | |||||
| // Complex layout calculations | |||||
| } | |||||
| updateComplexVisuals() { | |||||
| // Expensive visual updates | |||||
| } | |||||
| } | |||||
| ``` | |||||
| --- | |||||
| **Next Steps:** | |||||
| - Check out [Component APIs](../api/component-apis.md) for more integration options | |||||
| - Explore [Advanced Patterns](advanced-patterns.md) for complex scenarios | |||||
| - Review [Performance Optimization](../deployment/performance.md) for production tips | |||||
| @ -0,0 +1,180 @@ | |||||
| # Installation Guide | |||||
| This guide will help you get Adminator up and running on your local machine. | |||||
| ## Prerequisites | |||||
| Before installing Adminator, ensure you have the following installed: | |||||
| ### Required Software | |||||
| - **Node.js** (v18.12.0 or higher) | |||||
| - Download from [nodejs.org](https://nodejs.org/) | |||||
| - Verify installation: `node --version` | |||||
| - **npm** (comes with Node.js) or **Yarn** | |||||
| - Verify npm: `npm --version` | |||||
| - **Git** for version control | |||||
| - Download from [git-scm.com](https://git-scm.com/) | |||||
| ### System Requirements | |||||
| - **Operating System**: Windows 10+, macOS 10.14+, or Linux | |||||
| - **RAM**: Minimum 4GB (8GB recommended for development) | |||||
| - **Storage**: 500MB free space for dependencies | |||||
| ## Installation Methods | |||||
| ### Method 1: Clone from GitHub (Recommended) | |||||
| ```bash | |||||
| # Clone the repository | |||||
| git clone https://github.com/puikinsh/Adminator-admin-dashboard.git | |||||
| # Navigate to the project directory | |||||
| cd Adminator-admin-dashboard | |||||
| # Install dependencies | |||||
| npm install | |||||
| # Start development server | |||||
| npm start | |||||
| ``` | |||||
| ### Method 2: Download ZIP | |||||
| 1. Visit the [GitHub repository](https://github.com/puikinsh/Adminator-admin-dashboard) | |||||
| 2. Click **"Code"** โ **"Download ZIP"** | |||||
| 3. Extract the downloaded file | |||||
| 4. Open terminal in the extracted folder | |||||
| 5. Run `npm install` and `npm start` | |||||
| ### Method 3: Use with Existing Project | |||||
| ```bash | |||||
| # Add Adminator to your project | |||||
| npm install --save adminator | |||||
| # Or download specific release | |||||
| wget https://github.com/puikinsh/Adminator-admin-dashboard/archive/v2.6.0.zip | |||||
| ``` | |||||
| ## Verification | |||||
| After installation, verify everything works: | |||||
| ### 1. Development Server | |||||
| ```bash | |||||
| npm start | |||||
| ``` | |||||
| **Expected Output:** | |||||
| ``` | |||||
| > adminator@2.6.0 start | |||||
| > webpack server | |||||
| โ Project is running at: http://localhost:4000/ | |||||
| โ webpack compiled successfully | |||||
| ``` | |||||
| ### 2. Build Process | |||||
| ```bash | |||||
| npm run build | |||||
| ``` | |||||
| **Expected Output:** | |||||
| ``` | |||||
| > adminator@2.6.0 build | |||||
| > npm run clean && cross-env webpack | |||||
| โ webpack compiled successfully in [time]ms | |||||
| ``` | |||||
| ### 3. Access the Application | |||||
| Open your browser and navigate to: | |||||
| - **Local**: `http://localhost:4000` | |||||
| - **Network**: `http://[your-ip]:4000` | |||||
| You should see the Adminator dashboard with: | |||||
| - โ Clean interface loading properly | |||||
| - โ Dark/Light mode toggle in the header | |||||
| - โ All components rendering correctly | |||||
| - โ No console errors | |||||
| ## Troubleshooting | |||||
| ### Common Issues | |||||
| #### Port Already in Use | |||||
| ```bash | |||||
| # Error: EADDRINUSE: address already in use :::4000 | |||||
| # Solution: Kill the process using port 4000 | |||||
| sudo lsof -ti:4000 | xargs kill -9 | |||||
| # Or use a different port | |||||
| PORT=3000 npm start | |||||
| ``` | |||||
| #### Node Version Issues | |||||
| ```bash | |||||
| # Check your Node.js version | |||||
| node --version | |||||
| # If version is below 18.12.0, update Node.js | |||||
| # Use nvm (recommended): | |||||
| nvm install 18 | |||||
| nvm use 18 | |||||
| ``` | |||||
| #### Permission Errors | |||||
| ```bash | |||||
| # On macOS/Linux, you might need sudo for global packages | |||||
| sudo npm install -g npm@latest | |||||
| # Better solution: Fix npm permissions | |||||
| npm config set prefix ~/.npm-global | |||||
| export PATH=~/.npm-global/bin:$PATH | |||||
| ``` | |||||
| #### Missing Dependencies | |||||
| ```bash | |||||
| # Clear npm cache and reinstall | |||||
| npm cache clean --force | |||||
| rm -rf node_modules package-lock.json | |||||
| npm install | |||||
| ``` | |||||
| #### Build Errors | |||||
| ```bash | |||||
| # Check for conflicting global packages | |||||
| npm list -g --depth=0 | |||||
| # Update npm and dependencies | |||||
| npm update | |||||
| npm audit fix | |||||
| ``` | |||||
| ### Getting Help | |||||
| If you encounter issues: | |||||
| 1. **Check the [GitHub Issues](https://github.com/puikinsh/Adminator-admin-dashboard/issues)** | |||||
| 2. **Search existing solutions** | |||||
| 3. **Create a new issue** with: | |||||
| - Operating system and version | |||||
| - Node.js and npm versions | |||||
| - Complete error message | |||||
| - Steps to reproduce | |||||
| ## Next Steps | |||||
| After successful installation: | |||||
| 1. **[Explore Project Structure](project-structure.md)** - Understand the codebase | |||||
| 2. **[Development Workflow](development.md)** - Learn the development process | |||||
| 3. **[Customize Themes](../customization/theme-system.md)** - Set up dark mode and theming | |||||
| 4. **[Build for Production](build-deployment.md)** - Deploy your application | |||||
| --- | |||||
| **Installation Complete!** ๐ You're ready to start building with Adminator. | |||||
| @ -0,0 +1,126 @@ | |||||
| --- | |||||
| title: Adminator Documentation | |||||
| description: Complete guide for the Adminator Bootstrap 5 Admin Dashboard Template | |||||
| --- | |||||
| # Adminator Documentation | |||||
| Welcome to the comprehensive documentation for **Adminator**, a modern Bootstrap 5 admin dashboard template with dark mode support. | |||||
| ## ๐ Overview | |||||
| Adminator is a responsive, feature-rich admin template built with: | |||||
| - **Bootstrap 5.3.6** - Latest CSS framework | |||||
| - **Dark Mode System** - Complete theme switching with OS detection | |||||
| - **Modern Components** - Charts, calendars, maps, and interactive elements | |||||
| - **Performance Optimized** - Webpack build system with modern tooling | |||||
| ## ๐ Quick Start | |||||
| ```bash | |||||
| # Clone the repository | |||||
| git clone https://github.com/puikinsh/Adminator-admin-dashboard.git | |||||
| # Install dependencies | |||||
| npm install | |||||
| # Start development server | |||||
| npm start | |||||
| ``` | |||||
| Visit `http://localhost:4000` to see Adminator in action. | |||||
| ## ๐ Documentation Sections | |||||
| ### ๐ [Getting Started](getting-started/) | |||||
| - [Installation Guide](getting-started/installation.md) | |||||
| - [Project Structure](getting-started/project-structure.md) | |||||
| - [Development Workflow](getting-started/development.md) | |||||
| - [Build & Deployment](getting-started/build-deployment.md) | |||||
| ### ๐จ [Components](components/) | |||||
| - [Charts & Data Visualization](components/charts.md) | |||||
| - [Forms & Input Elements](components/forms.md) | |||||
| - [Tables & Data Display](components/tables.md) | |||||
| - [Navigation & Layout](components/navigation.md) | |||||
| - [Modals & Overlays](components/modals.md) | |||||
| ### ๐ [Dark Mode & Theming](customization/) | |||||
| - [Theme System Overview](customization/theme-system.md) | |||||
| - [CSS Variables Reference](customization/css-variables.md) | |||||
| - [Custom Theme Creation](customization/custom-themes.md) | |||||
| - [Component Theming](customization/component-theming.md) | |||||
| ### ๐ง [API Reference](api/) | |||||
| - [Theme API](api/theme-api.md) | |||||
| - [Component APIs](api/component-apis.md) | |||||
| - [Utility Functions](api/utilities.md) | |||||
| - [Event System](api/events.md) | |||||
| ### ๐ก [Examples](examples/) | |||||
| - [Basic Setup](examples/basic-setup.md) | |||||
| - [Custom Components](examples/custom-components.md) | |||||
| - [Theme Integration](examples/theme-integration.md) | |||||
| - [Advanced Patterns](examples/advanced-patterns.md) | |||||
| ### ๐ [Deployment](deployment/) | |||||
| - [Production Build](deployment/production-build.md) | |||||
| - [Static Hosting](deployment/static-hosting.md) | |||||
| - [CDN Integration](deployment/cdn-integration.md) | |||||
| - [Performance Optimization](deployment/performance.md) | |||||
| ### ๐ค [Contributing](contributing/) | |||||
| - [Development Setup](contributing/development-setup.md) | |||||
| - [Code Standards](contributing/code-standards.md) | |||||
| - [Pull Request Process](contributing/pull-requests.md) | |||||
| - [Issue Templates](contributing/issues.md) | |||||
| ## โจ Key Features | |||||
| ### ๐ Dark Mode System | |||||
| - **Smart Toggle**: Bootstrap-based switch with visual indicators | |||||
| - **OS Detection**: Automatically respects user's system preference | |||||
| - **Persistent Storage**: Remembers theme choice across sessions | |||||
| - **Component Integration**: All elements are theme-aware | |||||
| ### ๐ Rich Components | |||||
| - **Chart.js Integration**: Line, bar, pie, and radar charts | |||||
| - **FullCalendar**: Interactive calendar with event management | |||||
| - **DataTables**: Advanced table features with search and pagination | |||||
| - **Vector Maps**: Interactive world and regional maps | |||||
| - **Google Maps**: Custom styled maps with markers | |||||
| ### ๐ ๏ธ Developer Experience | |||||
| - **Modern Tooling**: Webpack 5, ESLint 9.x, Sass, PostCSS | |||||
| - **Hot Reload**: Instant development feedback | |||||
| - **Code Quality**: Automated linting and formatting | |||||
| - **Performance**: Optimized builds with code splitting | |||||
| ## ๐ Quick Links | |||||
| - **[Live Demo](https://colorlib.com/polygon/adminator/index.html)** - See Adminator in action | |||||
| - **[GitHub Repository](https://github.com/puikinsh/Adminator-admin-dashboard)** - Source code and issues | |||||
| - **[Changelog](https://github.com/puikinsh/Adminator-admin-dashboard/blob/master/CHANGELOG.md)** - Version history | |||||
| - **[License](https://github.com/puikinsh/Adminator-admin-dashboard/blob/master/LICENSE)** - MIT License | |||||
| ## ๐ What's New in v2.6.0 | |||||
| The latest release introduces a comprehensive dark mode system: | |||||
| - **๐ Complete Dark Theme** with automatic OS detection | |||||
| - **๐จ Theme-Aware Components** for charts, calendars, and maps | |||||
| - **โก Instant Switching** without page reload | |||||
| - **๐ฏ CSS Variables Architecture** for consistent theming | |||||
| - **๐ฑ Responsive Design** across all screen sizes | |||||
| [View Full Changelog โ](https://github.com/puikinsh/Adminator-admin-dashboard/blob/master/CHANGELOG.md) | |||||
| ## ๐ฌ Support | |||||
| - **Issues**: [GitHub Issues](https://github.com/puikinsh/Adminator-admin-dashboard/issues) | |||||
| - **Discussions**: [GitHub Discussions](https://github.com/puikinsh/Adminator-admin-dashboard/discussions) | |||||
| - **Documentation**: You're here! ๐ | |||||
| --- | |||||
| **Happy coding with Adminator!** ๐ | |||||