# Theme Module — Complete Documentation

## Overview

The Theme Module is a CSS customization layer that allows admin users to change the look and feel of both the backend panel and the login page **without editing any template files**. It works by defining CSS templates with placeholder variables (`{{param}}`) that are populated through an admin form (Theme Settings) and compiled into a static CSS file.

---

## Architecture

```
┌──────────────────────────────────────────────────────────────┐
│                      Database                                │
│  ┌─────────────────────────┐  ┌──────────────────────────┐  │
│  │     theme_rules          │  │    theme_settings         │  │
│  │  ┌───────────────────┐   │  │  ┌────────────────────┐  │  │
│  │  │ rule_id (PK)      │   │  │  │ setting_id (PK)    │  │  │
│  │  │ rule_name         │   │  │  │ setting_rule_id(FK)│  │  │
│  │  │ rule_description  │   │  │  │ setting_param_name │  │  │
│  │  │ rule_content (CSS)│   │  │  │ setting_param_type │  │  │
│  │  │ rule_params (JSON)│   │  │  │ setting_param_value│  │  │
│  │  │ rule_status (bool)│   │  │  │ setting_param_def  │  │  │
│  │  │ rule_sorting      │   │  │  └────────────────────┘  │  │
│  │  └───────────────────┘   │  └──────────────────────────┘  │
│  └─────────────────────────┘                                  │
└──────────────────────────────────────────────────────────────┘
          │                                      │
          │  ThemeService::generateCss()         │
          ▼                                      ▼
┌──────────────────────────────────────────────────────────────┐
│          storage/app/public/css/theme-module.css              │
│  (compiled CSS with all {{param}} placeholders replaced)      │
└──────────────────────────────────────────────────────────────┘
          │
          ▼
┌────────────────────────────────────────────┐
│  backend/layouts/app.blade.php             │
│  <link href="theme-module.css">            │
└────────────────────────────────────────────┘
```

### Database Tables

#### `theme_rules`
Stores CSS **templates** with `{{param_name}}` placeholders.

| Column | Type | Description |
|--------|------|-------------|
| `rule_id` | bigint (PK) | Auto-increment |
| `rule_name` | varchar(250) | Display name for the rule |
| `rule_description` | varchar(500) | Description of what the rule controls |
| `rule_content` | longtext | CSS template with `{{param_name}}` placeholders |
| `rule_params` | text | JSON array of parameter definitions |
| `rule_status` | boolean | Active/inactive toggle |
| `rule_sorting` | int | Sort order in Theme Settings page |

#### `theme_settings`
Stores user-configured **values** for each parameter of each rule.

| Column | Type | Description |
|--------|------|-------------|
| `setting_id` | bigint (PK) | Auto-increment |
| `setting_rule_id` | bigint (FK) | References `theme_rules.rule_id` |
| `setting_param_name` | varchar(250) | Parameter name matching the `{{param_name}}` placeholder |
| `setting_param_type` | varchar(250) | `text`, `colorpicker`, or `unit` |
| `setting_param_value` | varchar(500) | User-set value |
| `setting_param_default` | varchar(500) | Default fallback value |

---

## How It Works (Step by Step)

### Step 1: Define a Theme Rule

Go to **Theme Rules** → **Create New** and fill in:

1. **Rule Name** — e.g. "Button Styling"
2. **CSS Template** — Write CSS with `{{placeholder}}` for parts you want to make editable:
   ```css
   .btn-custom {
     background: {{background-color}};
     color: {{color}};
     padding: {{padding}};
   }
   ```
3. **Parameters** — Define each `{{placeholder}}`:
   - `background-color` → type `colorpicker`, default `#c24d4a`
   - `color` → type `colorpicker`, default `#ffffff`
   - `padding` → type `text`, default `6px 12px`

When saved, the system:
- Stores the CSS template in `theme_rules.rule_content`
- Stores the parameter schema in `theme_rules.rule_params`
- Creates one `theme_settings` row per parameter with default values

### Step 2: Configure Values

Go to **Theme Settings** → find the rule card → fill in the values → **Save**.

Each parameter type renders a different input:
| Type | Input |
|------|-------|
| `text` | Text field |
| `colorpicker` | Color picker |
| `unit` | Number field + unit selector (px, rem, %, vh, vw) |

### Step 3: CSS Compilation (Automatic)

Every time a rule or setting is saved, `ThemeService::generateCss()` runs automatically. It:

1. Fetches all **active** rules (`rule_status = true`)
2. Fetches all setting values via `ThemeSetting::settingArray()`
3. For each rule, replaces `{{param}}` placeholders with actual values
4. Concatenates all rules' CSS into one file
5. Writes to `storage/app/public/css/theme-module.css`

### Step 4: Frontend Loading

The backend layout (`backend/layouts/app.blade.php`) loads the generated CSS:

```blade
@if(Storage::disk('public')->exists('css/theme-module.css'))
    <link rel="stylesheet" href="{{ Storage::url('css/theme-module.css') }}?v={{ File::lastModified(...) }}">
@endif
```

To load it on the login page as well, add the same code to `auth-base.blade.php`.

---

## Parameter Types

### `text`
Free-text input. Use for strings like shadow values, font weights, display properties.

```
Default: "inset 0 1px 1px #fff"
```

### `colorpicker`
Hex color picker. Values stored as `#rrggbb` or `#rgb`.

```
Default: "#c24d4a"
```

### `unit`
Numeric value with a CSS unit selector. The value is stored as JSON:
```
{"value": "12", "unit": "px"}
```

Default format in form: `12px` (number immediately followed by unit). During parameter definition, the unit is selected from a dropdown (px, rem, %, vh, vw).

---

## Approaches for Applying CSS Rules

### 1. CSS Variables (`:root { --custom-var: ...; }`)
Best for when your existing CSS already uses `var(--custom-var)`.

**Rule CSS:**
```css
:root { --btn-bg: {{background-color}}; }
.btn-custom { background: var(--btn-bg); }
```

**Pros:** Works with existing Tailwind/component CSS if they reference the CSS variable.  
**Cons:** Requires your HTML to use the matching class.

### 2. Class-based Selector (`.btn-custom`)
Target elements that have a specific class.

**Rule CSS:**
```css
.btn-custom { background: {{background-color}}; color: {{color}}; }
```

**Pros:** Precise targeting.  
**Cons:** Must manually add `btn-custom` class to every HTML element.

### 3. Universal Selector (`button[type="submit"]`)
Target elements by tag, attribute, or position — no HTML changes needed.

**Rule CSS:**
```css
button[type="submit"] { background: {{background-color}}; color: {{color}}; }
```

**Pros:** Applies globally without touching views.  
**Cons:** May affect elements you didn't intend.

---

## Pre-seeded Rules (21 rules)

### Admin Panel
| Rule | CSS Variables | Purpose |
|------|--------------|---------|
| Page Body Background Color | `--page-body-bg` | Body background |
| Breadcrumb | `--breadcrumb-bg`, etc. | Breadcrumb area styling |
| Dashboard Box | `--dashboard-box-shadow`, etc. | Dashboard box/panel styling |
| GridView | `--gridview-padding` | Grid view container padding |
| Table Header | `--table-header-bg`, etc. | Table header section |

### Buttons
| Rule | CSS Classes | Purpose |
|------|-------------|---------|
| Button Styling | `.btn-custom`, `.btn-default` | Primary & default buttons |
| Button styling success | `.btn-success-custom` | Success/green buttons |

### Sidebar & Menu
| Rule | CSS Classes/Variables | Purpose |
|------|----------------------|---------|
| Sidebar background | `.sidebar` | Sidebar background color |
| Sidebar Brand Image | `.sidebar-brand-img` | Logo border, radius, shadow |
| Avatar Image | `.sidebar-avatar img` | Avatar shadow |
| Language Flag | `.lang-flag img` | Flag icon width |
| Nav Header | `.nav-header` | Logo area background |
| Menu Background | `.main-menu` | Menu container background |
| Side Bar First Level Default | `.sidebar-menu li.level-1 > a` | Level 1 menu items |
| Side Bar Second Level Default | `.sidebar-menu li.level-2 > a` | Level 2 submenu items |
| Side Bar Active Menu Border | `.sidebar-menu li.active` | Active menu left border |
| Side bar Minimal Header Background | `.sidebar-mini .nav-header` | Mini sidebar header |
| Menu Footer | `.menu-footer`, `.menu-footer-description` | Footer text & description |

### Forms
| Rule | CSS Classes | Purpose |
|------|-------------|---------|
| Form Input Element | `.form-control`, `.file-input-preview`, `.file-input-drop-zone` | Input fields & file upload |

### Login
| Rule | CSS Classes/Variables | Purpose |
|------|----------------------|---------|
| Login Background | `.login-page` | Background gradient overlay |
| Login Welcome Page | Pseudo-elements | Title, description, copyright text |

---

## Routes

| Method | URL | Name | Purpose |
|--------|-----|------|---------|
| GET | `/admin/theme/theme-setting` | `theme-setting.index` | Theme Settings page |
| POST | `/admin/theme/theme-setting` | `theme-setting.save` | Save settings |
| GET | `/admin/theme/theme-rule` | `theme-rule.index` | List all rules |
| GET | `/admin/theme/theme-rule/create` | `theme-rule.create` | Create rule form |
| POST | `/admin/theme/theme-rule` | `theme-rule.store` | Store new rule |
| GET | `/admin/theme/theme-rule/{id}` | `theme-rule.show` | View rule details |
| GET | `/admin/theme/theme-rule/{id}/edit` | `theme-rule.edit` | Edit rule form |
| PUT | `/admin/theme/theme-rule/{id}` | `theme-rule.update` | Update rule |
| POST | `/admin/theme/theme-rule/delete` | `theme-rule.destroy` | Delete rule |

All routes require admin authentication and specific permissions (`theme-setting.view`, `theme-rule.create`, etc.).

---

## Key Classes & Methods

### `ThemeRule` Model
- `$rule->rule_params` — Accessor that auto-decodes JSON to array
- `$rule->settings()` — HasMany relation to ThemeSetting
- `$rule->createdBy()` / `$rule->updatedBy()` — BelongsTo BackendUser

### `ThemeSetting` Model
- `ThemeSetting::settingArray()` — Static method that returns a 2D array:
  ```
  [ rule_id => [ param_name => value, ... ], ... ]
  ```
  For `unit` type, returns `['type'=>'unit', 'value'=>..., 'unit'=>...]`

### `ThemeService::generateCss()`
- Queries all active ThemeRules
- Gets all settings via `ThemeSetting::settingArray()`
- Replaces `{{param}}` placeholders using `str_replace`
- For `unit` types, concatenates `value + unit` (e.g., `12px`)
- Writes result to `storage/app/public/css/theme-module.css`

### `ThemeSettingController@save`
- Handles file uploads (login_logo, login_background, sidebar_logo, favicon, dashboard_banner)
- Handles sidebar color fields
- Handles dynamic theme params via form keys containing `-id-{rule_id}`
- Calls `ThemeService::generateCss()` after saving

---

## Flow for Adding a New Theme Rule

1. **Inspect** the element in browser to identify its CSS selector/class
2. **Create Theme Rule**:
   - Name: e.g. "Card Border"
   - CSS Template: `.card { border-color: {{border-color}}; border-width: {{border-width}}; }`
   - Parameters: `border-color` (colorpicker, `#ddd`), `border-width` (unit, `1`)
3. **Save** → system creates rule + settings with defaults + regenerates CSS
4. Go to **Theme Settings** → adjust values → Save
5. If the rule targets a class not yet used in views, add that class to the HTML elements

---

## Key Files

| File | Purpose |
|------|---------|
| `app/Models/Backend/ThemeRule.php` | ThemeRule model |
| `app/Models/Backend/ThemeSetting.php` | ThemeSetting model + `settingArray()` helper |
| `app/Services/ThemeService.php` | CSS compilation engine |
| `app/Http/Controllers/Backend/ThemeRuleController.php` | CRUD for rules |
| `app/Http/Controllers/Backend/ThemeSettingController.php` | Save settings + file uploads |
| `database/seeders/ThemeRuleSeeder.php` | Seeds 21 default rules |
| `resources/views/backend/module/theme/` | All theme views |
| `storage/app/public/css/theme-module.css` | Compiled CSS output |
| `resources/views/backend/layouts/app.blade.php` | Loads theme-module.css |
| `resources/views/auth-base.blade.php` | Login page layout (inline styles) |
| `resources/views/backend/auth/login.blade.php` | Login page content (welcome text) |
