Skip to main content
Tripfy Africa uses a single theme called Adventra. All views, styles, and JavaScript are organized under this theme. The admin controls the brand colors through Basic Control, and every save regenerates a CSS file that updates the entire frontend immediately.

Theme directory structure

All Blade templates live under resources/views/themes/adventra/:
resources/views/themes/adventra/
├── layouts/
│   ├── app.blade.php          # Main public-facing layout
│   └── user.blade.php         # Authenticated user dashboard
├── partials/
│   ├── header.blade.php       # Navigation header with theme toggle
│   ├── footer.blade.php       # Footer
│   ├── pwa.blade.php          # PWA install popup
│   ├── cookie.blade.php       # Cookie consent
│   ├── preloader.blade.php    # Page preloader
│   └── fixed_area.blade.php   # Floating UI elements
├── frontend/
│   ├── package/               # Package listing and detail pages
│   ├── checkout/              # Booking and payment flow
│   ├── destinations/          # Destination detail pages
│   └── blogs/                 # Blog listing and detail
├── auth/                      # Login, register, password reset
├── user/                      # User dashboard pages
└── sections/                  # Reusable page sections
The admin panel templates live separately under resources/views/admin/.

Dynamic color generation

When you save colors in Admin → Settings → Basic Control, the BasicControlController writes a file called public/assets/themes/adventra/css/dynamic-colors.css. This file contains only CSS custom properties — no component styles — so a single save instantly re-themes every page. The generated file looks like this:
/* Auto-generated by Tripfy Africa Admin — DO NOT edit manually */
/* Regenerated every time Basic Control colors are saved        */

/* Light (default) */
:root,
html[data-theme="light"],
html[data-hs-appearance="default"] {
  --tf-primary:              #2596be;
  --tf-primary-dark:         #0576be;
  --tf-primary-light:        rgba(37,150,190,0.12);
  --tf-primary-mid:          rgba(37,150,190,0.25);
  --tf-secondary:            #02d0e3;
  --tf-accent:               #02d0e3;
  --bs-primary:              #2596be;
  --bs-primary-rgb:          37,150,190;
  --bs-link-color:           #2596be;
  --bs-link-hover-color:     #0576be;
}

/* Dark (explicit user choice only) */
html[data-theme="dark"],
html[data-hs-appearance="dark"] {
  --tf-primary:              #2596be;
  --tf-primary-dark:         #0576be;
  --tf-primary-light:        rgba(37,150,190,0.18);
  --tf-primary-mid:          rgba(37,150,190,0.30);
  --tf-secondary:            #02d0e3;
  --tf-accent:               #02d0e3;
  --bs-primary:              #02d0e3;
  --bs-primary-rgb:          2,208,227;
}
The controller derives darker and lighter variants automatically from the single hex value you provide:
// app/Http/Controllers/Admin/BasicControlController.php
protected function generateDynamicCss(BasicControl $control): void
{
    $primary   = $control->primary_color   ?? '#2696be';
    $secondary = $control->secondary_color ?? '#02d0e3';

    $primaryDark  = $this->adjustColor($primary, -20);
    $primaryLight = $this->hexToRgba($primary, 0.12);
    $primaryMid   = $this->hexToRgba($primary, 0.25);

    // ... builds CSS string ...

    $path = public_path('assets/themes/adventra/css/dynamic-colors.css');
    file_put_contents($path, $css);
}
If dynamic-colors.css is missing after first deployment, run this once from tinker to generate it:
php artisan tinker
>>> app(\App\Http\Controllers\Admin\BasicControlController::class)->generateDynamicCssPublic();
Alternatively, visit Admin → Settings → Basic Control and click Save — this triggers the same method automatically.

The tripfy.css file

public/assets/themes/adventra/css/tripfy.css is the main stylesheet for the Adventra theme. It provides the full light and dark theme system, component styles, and layout rules. It is loaded by app.blade.php alongside dynamic-colors.css. Two other stylesheets complement it:
FilePurpose
dynamic-colors.cssCSS custom properties generated from admin colors
tripfy.cssFull component and layout styles using those properties
admin/css/tripfy-admin.cssAdmin panel branding overrides

Main layout (app.blade.php)

The public layout loads styles, sets the data-theme attribute, and prevents a flash of unstyled content:
<!-- resources/views/themes/adventra/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"
      data-theme="{{ auth()->check() ? auth()->user()->theme_mode : 'light' }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ $pageTitle ?? basicControl('site_title') }}</title>

    <!-- Admin-generated brand colors -->
    <link rel="stylesheet" href="{{ asset('assets/themes/adventra/css/dynamic-colors.css') }}">
    <!-- Full theme and component styles -->
    <link rel="stylesheet" href="{{ asset('assets/themes/adventra/css/tripfy.css') }}">

    <!-- Apply stored theme before first paint to prevent flash -->
    <script>
        (function() {
            var t = localStorage.getItem('tf_theme') || 'light';
            document.documentElement.setAttribute('data-theme', t);
        })();
    </script>
</head>
<body>
    @include('themes.adventra.partials.header')
    <main class="main-content">
        @yield('content')
    </main>
    @include('themes.adventra.partials.footer')
    @include('themes.adventra.partials.pwa')
    <script src="{{ asset('assets/themes/adventra/js/tripfy.js') }}"></script>
    @stack('scripts')
</body>
</html>

Light/dark mode toggle

The data-theme attribute on <html> controls the active color scheme. It is set server-side from auth()->user()->theme_mode for logged-in users and from localStorage for guests. The tripfy.js script runs before the DOM is ready and immediately calls applyMode() so the correct theme is in place before the first paint:
// public/assets/themes/adventra/js/tripfy.js
const THEME_KEY = 'tf_theme';

function getMode() {
  var stored = localStorage.getItem(THEME_KEY);
  return (stored === 'dark') ? 'dark' : 'light';
}

function applyMode(mode) {
  var isDark = (mode === 'dark');
  document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
  if (document.body) document.body.classList.toggle('dark', isDark);
  localStorage.setItem(THEME_KEY, isDark ? 'dark' : 'light');
}

// Runs immediately — before first paint
applyMode(getMode());
Any element with the class tf-theme-toggle or the attribute data-tf-theme-toggle is automatically wired to call toggleTheme() after the DOM loads. For authenticated users, the current theme is also persisted server-side. See JavaScript for the route and fetch call that handles this.

Home page variations

The Adventra theme ships with three home page layouts you can choose from in Admin → Appearance:

Quest

Card grid layout with a hero search bar. Focuses on adventure discovery.

Elite

Full-width slider hero with a popular destinations grid.

Voyage

Alternative layout optimized for showcasing long-haul packages.
Each variation extends the same app.blade.php layout, so they all inherit dynamic colors and the theme toggle automatically.

PWA configuration

The partials/pwa.blade.php partial renders an install prompt popup. The service worker at serviceworker.js (in the project root) handles caching and offline support. A separate firebase-messaging-sw.js handles background push notifications. See JavaScript for service worker details.

Admin-controlled theming

Everything visual that the admin controls flows through the BasicControl model:
SettingEffect
primary_colorBrand color — buttons, links, badges, sidebar active state
secondary_colorAccent color — used in dark mode and secondary elements
site_titleSets <title> via the basicControl('site_title') helper
Changing either color in Admin → Settings → Basic Control and clicking Save regenerates dynamic-colors.css and calls php artisan optimize:clear automatically. The frontend reflects the new colors on the next page load with no deployment required.

Build docs developers (and LLMs) love