# Introduction

ListOn is a comprehensive REACT-based template that combines a beautiful directory/listing website with a powerful admin dashboard - all in a single, unified codebase. This merged solution offers the best of both worlds: an intuitive public-facing website for showcasing listings and a feature-rich dashboard for managing content.

Unified Solution: This template seamlessly integrates the website and dashboard with intelligent CSS isolation, ensuring styles never clash between the two interfaces.

What's Included

Website (WebLayout)

  • 8 unique homepage designs
  • Listing pages with grid/list/map views
  • Blog system with details
  • Authentication pages
  • Contact, About, FAQ pages
  • Responsive footer on all pages

Dashboard (DashLayout)

  • Dashboard home with analytics
  • Listing management (CRUD)
  • Bookings management
  • Messages/Chat system
  • Reviews management
  • Wallet & Settings

Developed with the latest web technologies including React 19, Bootstrap 5, and Vite, ListOn ensures excellent performance and developer experience. The template features a unified dark mode that works seamlessly across both interfaces.

# Changelog

Version 2.2 - July 2026 (Current)

  • Bug Fix: Renamed the non-standard clickOutside hook to useClickOutside (moved to src/hooks/) to comply with React's Rules of Hooks so the React Compiler can statically analyze it
  • Bug Fix: Wired up the dashboard's page loader correctly - removed a dead/unreachable JSX block and connected the loader's completion callback so it unmounts properly
  • Bug Fix: Added a root route (/) that redirects to /home, so visiting the site root no longer falls through to the 404 page
  • Bug Fix: Fixed a MetisMenu memory leak - sidebar menu instances are now properly disposed on dashboard unmount
  • Bug Fix: Fixed the dashboard's review image gallery modal rendering unstyled at the bottom of the page - its CSS is no longer incorrectly scoped to a DOM ancestor the portal renders outside of
  • Bug Fix: Fixed dark mode on the car listing page's rating overview and "Helpful Review" buttons, which were previously hardcoded to a white background
  • Code Quality: Removed leftover console.log debug statements from form submissions and navigation components
  • Code Quality: Removed the duplicate toast library (react-toastify) - standardized on react-hot-toast everywhere
  • Refactor: Renamed FooterLayout to WebLayout for clearer, more accurate naming

Version 2.1 - May 2026

  • Security: Added DOMPurify for XSS protection against malicious HTML
  • Performance: Optimized UnifiedThemeContext with useMemo and useCallback
  • Code Quality: Removed direct DOM manipulation in favor of React refs and state
  • Code Quality: Removed duplicate theme contexts (ThemeContext, ThemeContextDash)
  • Bug Fix: Fixed memory leak in CustomGoogleMap timeout cleanup
  • Enhancement: Improved React best practices throughout codebase
  • Enhancement: Proper cleanup for all third-party plugin instances

Version 2.0 - 2025

  • Major: Merged website and dashboard into unified codebase
  • Major: Implemented intelligent CSS isolation with dynamic loading
  • Major: Added UnifiedThemeContext for cross-layout dark mode
  • Created useDynamicStyles hook for CSS injection/removal
  • Upgraded to React 19.2.0
  • Fixed light mode styling in dashboard
  • Added wave animations to homepage variants
  • Implemented React.lazy() for all 68+ components

Version 1.0 - December 07, 2024

  • Initial release

# Features

Powered by React 19 & Vite
08 engaging homepage styles
Complete admin dashboard
Unified dark mode
Intelligent CSS isolation
Google Maps integration
Fully responsive layout
Chat/Messaging system
ApexCharts analytics
Framer Motion animations
Auth pages (Sign in/up/2FA)
Code-split lazy loading

Complete Feature List:

  • Powered by REACT 19 with Vite build system
  • 08 engaging homepage styles (Classic, Grid, Main, Map, Restaurant, Rounded, Waves, Car)
  • Complete admin dashboard with sidebar navigation
  • Unified dark mode that syncs across website and dashboard
  • Dynamic CSS architecture - CSS loads/unloads on route changes
  • 68+ lazy-loaded components for optimal performance
  • Extensive maps integration with Snazzy Maps styling
  • Listing details pages (2 variants)
  • Listing views: Grid, List, and Half-map layouts
  • Dashboard features: Listings, Bookings, Messages, Reviews, Wallet, Settings
  • Built with Bootstrap 5.3.8 for modern styling
  • Redux Toolkit for state management
  • ApexCharts for beautiful data visualization
  • React Hot Toast for notifications
  • Framer Motion for smooth animations
  • Form handling with Formik & Yup validation
  • Cross-browser compatible and retina ready
  • SEO-friendly code structure
  • Well-documented and commented code

# Tech Stack

Core Technologies

  • React: 19.2.0 (Latest)
  • Build Tool: Vite 7.2.2 with React plugin
  • State Management: Redux Toolkit 2.10.1
  • Routing: React Router DOM 7.9.6
  • UI Framework: Bootstrap 5.3.8
  • Animations: Framer Motion (motion 12.23.24)
  • Form Handling: Formik 2.4.9 + Yup validation

UI & Visualization Libraries

  • Charts: ApexCharts / React ApexCharts
  • Icons: React Icons, React Feather, Font Awesome
  • Carousels: Swiper 12.2.0, React Slick 0.30.3
  • Tables: TanStack Table (React Table) 8.21.3
  • Notifications: React Hot Toast
  • Scroll Animation: AOS (Animate On Scroll)
  • Range Input: React Range 1.10.0

Maps & Utilities

  • Maps: @react-google-maps/api 2.20.6
  • Security: DOMPurify (XSS protection)
  • Menu: MetisMenu (sidebar navigation)
  • Scrollbar: Perfect Scrollbar
  • Counting: React CountUp

# File Structure

liston-web-admin/
├── public/
│   └── assets/
│       ├── documentation/         # This documentation
│       └── images/                # Public images
│           ├── about/, avatar/, blog/, brand-logo/
│           ├── car-parts/, header/, icon/
│           ├── listing-details/, locations/
│           ├── place/, png-img/, service/
│           └── img/avatar/, img/reviews/
│
├── src/
│   ├── App.jsx                    # Main routing configuration
│   ├── main.jsx                   # Entry point with Redux Provider
│   ├── indexWeb.css               # Website-specific global styles
│   ├── indexDash.css              # Dashboard-specific global styles
│   │
│   ├── app/
│   │   └── store.js               # Redux store configuration
│   │
│   ├── assets/
│   │   ├── css/
│   │   │   ├── app.min.css        # Dashboard base styles
│   │   │   ├── styleDash.css      # Dashboard custom styles
│   │   │   ├── styleWeb.css       # Website custom styles
│   │   │   ├── pageLoader.css     # Page loader (static)
│   │   │   └── BackToTop.css      # Back to top button
│   │   └── svgs/                  # 50+ SVG icon components
│   │
│   ├── components/
│   │   ├── Footer.jsx             # Website footer
│   │   ├── Navbar.jsx             # Website navbar
│   │   ├── dashboard-components/  # Dashboard components
│   │   │   ├── DashHome.jsx, Sidebar.jsx, NavbarDash.jsx
│   │   │   ├── MyListing.jsx, AddListingForm.jsx
│   │   │   ├── Bookings.jsx, Messeges.jsx, Reviews.jsx
│   │   │   ├── BookMarks.jsx, Wallet.jsx, Settings.jsx
│   │   │   └── EditProfile.jsx
│   │   ├── home-components/       # 8 homepage variants
│   │   ├── listing-components/    # Grid, list, map listings
│   │   ├── nav-components/        # Navigation sub-components
│   │   └── templates-components/  # Auth, about, blog, etc.
│   │
│   ├── features/                  # Redux slices
│   │   ├── navbar/navSlice.js
│   │   ├── price-filter/priceFilterSlice.js
│   │   ├── map/mapSlice.js
│   │   ├── chat/ChatSlice.js
│   │   └── ChatRight/chatRightSidebarSlice.js
│   │
│   ├── hooks/
│   │   ├── useClickOutside.js     # Click-outside detection hook
│   │   └── useDynamicStyles.js    # CSS injection/removal hook
│   │
│   ├── layouts/
│   │   ├── WebLayout.jsx          # Website layout wrapper
│   │   ├── dash-layout/
│   │   │   └── DashLayout.jsx     # Dashboard layout wrapper
│   │   ├── home-layouts/          # Home page layouts
│   │   ├── listing-layouts/       # Listing page layouts
│   │   ├── blog-layout/           # Blog layouts
│   │   ├── contact-layouts/       # Contact layouts
│   │   └── template-layout/       # Misc template layouts
│   │
│   ├── services/
│   │   ├── UnifiedThemeContext.jsx  # Unified dark mode (optimized)
│   │   ├── CustomGoogleMap.jsx      # Google Maps wrapper
│   │   ├── PageLoader.jsx           # Loading component
│   │   ├── ScrollbarDash.jsx        # Dashboard scrollbar
│   │   ├── ScrollForChat.jsx        # Chat scrollbar
│   │   └── useIsLargeScreen.js      # Screen size hook
│   │
│   └── utils/
│       └── *Validation.js           # Form validation schemas
│
├── index.html                     # HTML entry point
├── vite.config.js                 # Vite configuration
├── eslint.config.js               # ESLint configuration
└── package.json                   # Dependencies

# Architecture

Dual Layout System

The application uses two distinct layout wrappers that handle CSS loading and theming:

App.jsx (Router)
↓
WebLayout
↓
Website Pages
styleWeb.css
indexWeb.css
DashLayout
↓
Dashboard Pages
styleDash.css
app.min.css
indexDash.css

Component Loading Strategy

All 68+ page components are lazy-loaded using React.lazy() with Suspense boundaries:

// Example from App.jsx
const HomeMain = lazy(() => import('./components/home-components/HomeMain'));
const DashHome = lazy(() => import('./components/dashboard-components/DashHome'));

// Usage with Suspense
<Suspense fallback={<PageLoader />}>
  <Routes>
    {/* Root redirects to /home so visiting "/" never 404s */}
    <Route path="/" element={<Navigate to="/home" replace />} />

    <Route element={<WebLayout />}>
      <Route path="/home" element={<HomeMain />} />
    </Route>
    <Route element={<DashLayout />}>
      <Route path="/dashboard" element={<DashHome />} />
    </Route>
  </Routes>
</Suspense>

State Management (Redux)

Redux Toolkit manages global state with 5 feature slices:

// src/app/store.js
export const store = configureStore({
  reducer: {
    nav: navReducer,           // Navigation state
    priceFilter: priceFilterReducer,  // Price filtering
    map: mapReducer,           // Map state
    chat: chatReducer,         // Chat messages
    chatRightBar: chatRightBarReducer // Chat sidebar
  }
});

Form Handling

Forms use Formik with Yup validation schemas located in src/utils/:

  • signInValidation.js - Sign in form validation
  • signUpValidation.js - Sign up form validation
  • contactFormValidation.js - Contact form validation
  • resetPassValidation.js - Password reset validation
  • twoFactorValidation.js - 2FA code validation
  • commentValidation.js - Comment form validation

# CSS Architecture

Important: This project uses dynamic CSS loading to prevent style conflicts between the website and dashboard interfaces.

The Problem & Solution

When the website and dashboard codebases were merged, their CSS files conflicted. The solution implements:

  1. Vite's ?inline imports - CSS is imported as raw strings
  2. useDynamicStyles hook - Injects CSS as <style> tags on mount
  3. Automatic cleanup - Removes CSS when navigating away

CSS Files by Layout

Website (WebLayout)

styleWeb.css Website-specific custom styles, wave animations
indexWeb.css Website global styles and overrides

Dashboard (DashLayout)

app.min.css Dashboard base styles and layout
styleDash.css Dashboard custom styles, CSS variables
indexDash.css Dashboard global styles and overrides

Static (Always Loaded)

pageLoader.css Loading spinner - must load before components

useDynamicStyles Hook

// src/hooks/useDynamicStyles.js
import { useEffect } from 'react';

const useDynamicStyles = (cssModules, id) => {
  useEffect(() => {
    const styleElements = [];
    
    cssModules.forEach((cssContent, index) => {
      const style = document.createElement('style');
      style.id = `${id}-style-${index}`;
      style.textContent = cssContent;
      document.head.appendChild(style);
      styleElements.push(style);
    });

    // Cleanup on unmount
    return () => {
      styleElements.forEach((style) => {
        if (style.parentNode) {
          style.parentNode.removeChild(style);
        }
      });
    };
  }, [id]);
};

export default useDynamicStyles;

Usage in Layouts

// WebLayout.jsx
import styleWebCss from '../assets/css/styleWeb.css?inline';
import indexWebCss from '../indexWeb.css?inline';

const WebLayout = () => {
  useDynamicStyles([styleWebCss, indexWebCss], 'footer-layout');
  return (<Outlet />);
};

// DashLayout.jsx
import appMinCss from '../../assets/css/app.min.css?inline';
import styleDashCss from '../../assets/css/styleDash.css?inline';

const DashLayout = () => {
  useDynamicStyles([appMinCss, styleDashCss, indexDashCss], 'dash-layout');
  return (<Outlet />);
};

# Website Routes (WebLayout)

All website pages are wrapped in WebLayout which provides the footer and website-specific CSS.

Root redirect: Visiting / redirects to /home via <Navigate to="/home" replace />, so the root URL never falls through to the 404 page.

Homepage Variants

RouteComponentDescription
/homeHomeMainMain homepage design
/home-classicHomeClassicClassic listing style
/home-gridHomeGridGrid-based layout
/home-mapHomeMapMap-focused design
/home-restaurantHomeRestaurantRestaurant listing style
/home-roundedHomeRoundedRounded card design
/home-wavesHomeWavesAnimated waves design
/home-carHomeCarCar/vehicle listings

Listing Pages

RouteComponentDescription
/listing-gridListingGridGrid view listings
/listing-listListingListList view listings
/listings-half-mapListingHalfMapSplit view with map
/listings-half-map-listListingHalfMapListList + half map
/listing-detailsListingDetailsSingle listing details
/listing-details-2ListingDetails2Alternative details layout

Blog Pages

RouteComponentDescription
/blog-gridBlogGridBlog grid layout
/blog-grid-sidebarBlogGridSidebarBlog with sidebar
/blog-listBlogListBlog list layout
/blog-list-sidebarBlogListSidebarBlog list with sidebar
/blog-detailsBlogDetailsSingle blog post

Template Pages

RouteComponentDescription
/aboutAboutOneAbout page variant 1
/about-2AboutTwoAbout page variant 2
/contactContactPageContact page
/faqFAQFAQ page
/pricingPricingPricing plans
/agentAgentAgent/team page
/specialitySpecialityServices/specialties
/style-guideStyleGuideUI style guide
/add-listingAddListingPublic add listing
/termsTermsAndConditionsTerms & conditions

Authentication Pages

RouteComponentDescription
/sign-inSignInLogin page
/sign-upSignUpRegistration page
/forgot-passwordForgotPasswordPassword reset
/two-factor-authTwoFactorAuth2FA verification

# Dashboard Routes (DashLayout)

All dashboard pages are wrapped in DashLayout which provides the sidebar, navbar, and dashboard-specific CSS.

RouteComponentDescription
/dashboardDashHomeDashboard home with analytics
/dash-my-listingsMyListingView/manage listings
/dash-add-listingsAddListingFormCreate new listing
/dash-bookingsBookingsManage bookings
/dash-bookmarksBookMarksSaved/bookmarked items
/dash-messagesMessegesChat/messaging system
/dash-reviewsReviewsReview management
/dash-walletWalletWallet/payments
/dash-profileEditProfileEdit user profile
/dash-settingsSettingsAccount settings

Dashboard Features

  • Collapsible Sidebar: Toggle between full and mini sidebar
  • Hover Expansion: Sidebar expands on hover in collapsed mode
  • Toast Notifications: Welcome message and action feedback
  • Page Loader: Animated loading spinner on initial load
  • ApexCharts: Interactive charts and analytics
  • TanStack Table: Advanced data tables with sorting/filtering

# Theme System (Dark Mode)

Unified Theme: The project uses a unified theme context that synchronizes dark mode across both website and dashboard interfaces.

How It Works

The UnifiedThemeContext applies both theming approaches simultaneously:

  • data-bs-theme="dark|light" - Used by website (Bootstrap theme)
  • .dark class on <html> - Used by dashboard styles

UnifiedThemeContext Implementation

// src/services/UnifiedThemeContext.jsx
import { useMemo, useCallback } from 'react';

export const UnifiedThemeProvider = ({ children }) => {
  const [isDark, setIsDark] = useState(false);

  useEffect(() => {
    const html = document.documentElement;
    const themeValue = isDark ? 'dark' : 'light';

    // Apply BOTH approaches
    html.setAttribute('data-bs-theme', themeValue);  // Website
    html.classList.toggle('dark', isDark);           // Dashboard

    // Sync localStorage
    localStorage.setItem('theme', themeValue);
    localStorage.setItem('dark-mode', themeValue);
  }, [isDark]);

  // Memoized callback to prevent recreation on every render
  const toggleTheme = useCallback(() => {
    setIsDark(prev => !prev);
  }, []);

  // Memoized value object to prevent unnecessary rerenders
  const value = useMemo(() => ({
    isDark,
    theme: isDark ? 'dark' : 'light',
    toggleTheme,
  }), [isDark, toggleTheme]);

  return (
    <UnifiedThemeContext.Provider value={value}>
      {children}
    </UnifiedThemeContext.Provider>
  );
};
Performance Optimization: The context uses useMemo and useCallback to prevent unnecessary rerenders of consuming components.

Using the Theme

import { useTheme } from '../services/UnifiedThemeContext';

const MyComponent = () => {
  const { isDark, theme, toggleTheme } = useTheme();
  
  return (
    <button onClick={toggleTheme}>
      Current: {theme} | Click to toggle
    </button>
  );
};

Theme Persistence

Theme preference is stored in localStorage under two keys for backward compatibility:

  • theme - Primary key ('dark' or 'light')
  • dark-mode - Legacy compatibility key

# Security & Best Practices

Production Ready: This template follows React best practices and includes security measures to protect against common vulnerabilities.

XSS Protection

All user-generated HTML content is sanitized using DOMPurify before rendering:

import DOMPurify from 'dompurify';

// Safe HTML rendering
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userContent) }} />

// Even better: Avoid dangerouslySetInnerHTML when possible
// Use React's safe rendering instead:
{text.split('\n').map((line, i) => (
  <React.Fragment key={i}>
    {line}
    {i < array.length - 1 && <br />}
  </React.Fragment>
))}

React Best Practices

  • No Direct DOM Manipulation: All components use React refs (useRef) and state (useState) instead of querySelector or getElementById
  • Proper Cleanup: All event listeners, timers, and third-party plugins are cleaned up in useEffect return functions
  • Memory Leak Prevention: Component unmounting properly destroys PerfectScrollbar, MetisMenu, and other plugin instances
  • Performance Optimization: Context values are memoized with useMemo and useCallback to prevent unnecessary rerenders

Code Quality

  • Single Source of Truth: Removed duplicate theme contexts - only UnifiedThemeContext is used
  • Declarative Code: Components follow React's declarative model throughout
  • Type Safety: ESLint configuration helps catch common errors
  • Code Splitting: All 68+ components are lazy-loaded for optimal performance

Example: Proper useEffect Cleanup

// PerfectScrollbar + MetisMenu initialization with full cleanup
useEffect(() => {
  const psInstances = [];
  const metisMenuInstances = [];

  const timer = setTimeout(() => {
    document.querySelectorAll('.sidebar-body').forEach(el => {
      psInstances.push(new PerfectScrollbar(el));
    });

    document.querySelectorAll('.metismenu').forEach(el => {
      metisMenuInstances.push(new MetisMenu(el));
    });
  }, 100);

  // Cleanup function - runs on unmount
  return () => {
    clearTimeout(timer);
    psInstances.forEach(ps => {
      if (ps && typeof ps.destroy === 'function') ps.destroy();
    });
    metisMenuInstances.forEach(mm => {
      if (mm && typeof mm.dispose === 'function') mm.dispose();
    });
  };
}, []);

# State Management

Redux Store Structure

store
├── nav          # Navigation state (mobile menu, dropdowns)
├── priceFilter  # Price range filter values
├── map          # Map center, zoom, markers
├── chat         # Chat messages and conversations
└── chatRightBar # Chat sidebar visibility

Feature Slices

SliceLocationPurpose
navfeatures/navbar/navSlice.jsNavigation state management
priceFilterfeatures/price-filter/priceFilterSlice.jsPrice filtering for listings
mapfeatures/map/mapSlice.jsGoogle Maps state
chatfeatures/chat/ChatSlice.jsChat messages
chatRightBarfeatures/ChatRight/chatRightSidebarSlice.jsChat sidebar toggle

Using Redux

import { useSelector, useDispatch } from 'react-redux';
import { toggleNav } from '../features/navbar/navSlice';

const Navigation = () => {
  const dispatch = useDispatch();
  const { isOpen } = useSelector(state => state.nav);
  
  return (
    <button onClick={() => dispatch(toggleNav())}>
      {isOpen ? 'Close' : 'Open'} Menu
    </button>
  );
};

# Components

Component Organization

src/components/
├── Footer.jsx                 # Website footer
├── Navbar.jsx                 # Website navigation
│
├── dashboard-components/      # Dashboard-specific
│   ├── DashHome.jsx          # Dashboard home page
│   ├── Sidebar.jsx           # Collapsible sidebar
│   ├── NavbarDash.jsx        # Dashboard top navbar
│   ├── MyListing.jsx         # Listings management
│   ├── AddListingForm.jsx    # Create listing form
│   ├── Bookings.jsx          # Bookings table
│   ├── Messeges.jsx          # Chat interface
│   ├── Reviews.jsx           # Reviews table
│   ├── BookMarks.jsx         # Bookmarks list
│   ├── Wallet.jsx            # Wallet/payments
│   ├── EditProfile.jsx       # Profile editor
│   └── Settings.jsx          # Settings page
│
├── home-components/           # Homepage variants
│   ├── HomeMain.jsx          # Main homepage
│   ├── HomeClassic.jsx       # Classic style
│   ├── HomeGrid.jsx          # Grid layout
│   ├── HomeMap.jsx           # Map-focused
│   ├── HomeRestaurant.jsx    # Restaurant style
│   ├── HomeRounded.jsx       # Rounded cards
│   ├── HomeWaves.jsx         # Wave animations
│   └── HomeCar.jsx           # Car listings
│
├── listing-components/        # Listing pages
│   ├── grid-view/            # Grid view components
│   ├── list-view/            # List view components
│   ├── listing-details/      # Details page components
│   └── listings-map/         # Map view components
│
├── nav-components/            # Navigation sub-components
│
└── templates-components/      # Template pages
    ├── sign-in/, sign-up/    # Authentication
    ├── about-1/, about-2/    # About pages
    ├── blog/                 # Blog components
    ├── contact/              # Contact page
    ├── faq/, pricing/        # FAQ & Pricing
    └── agent/, speciality/   # Other templates

SVG Icon Components

50+ custom SVG icons as React components in src/assets/svgs/:

AlarmIcon, BellIcon
ArrowLeft, ArrowRight
BookMark, Cart
ChatIcon, Clock
EyeIcon, Fuel
...and 45+ more

# Getting Started

Prerequisites

  • Node.js (v18 or higher recommended)
  • npm or yarn package manager
  • Google Maps API key (for maps features)

Installation Steps

  1. Extract the template files

    Unzip the downloaded file. You will get a folder named liston-main

  2. Navigate to the project folder

    Inside liston-main, you'll find two folders:

    • documentation - Contains this documentation file
    • liston - The main project source code

    Open terminal in the liston folder:

  3. Install dependencies
    npm install
  4. Configure environment variables

    Create .env file in the liston folder with your API keys:

    VITE_GOOGLE_MAP_API_KEY=your_google_maps_api_key
  5. Start development server
    npm run dev
  6. Open in browser

    Navigate to http://localhost:5173/home

Available Scripts

  • npm run dev - Start development server with hot reload
  • npm run build - Build production-ready bundle
  • npm run preview - Preview production build locally

Quick Navigation

  • Website: http://localhost:5173/ (and all /home-* routes)
  • Dashboard: http://localhost:5173/dashboard
  • Toggle dark mode using the theme switch in navbar

# Customization

Changing Theme Colors

Primary colors can be modified in the CSS files:

  • Website: Edit src/assets/css/styleWeb.css
  • Dashboard: Edit src/assets/css/styleDash.css
  • Override Bootstrap variables using CSS custom properties

Adding New Pages

  1. Create component in appropriate directory
  2. Add lazy import in App.jsx:
    const MyNewPage = lazy(() => import('./components/MyNewPage'));
  3. Add route under correct layout:
    // Website page (with footer)
    <Route element={<WebLayout />}>
      <Route path="/my-page" element={<MyNewPage />} />
    </Route>
    
    // Dashboard page (with sidebar)
    <Route element={<DashLayout />}>
      <Route path="/dash-my-page" element={<MyNewPage />} />
    </Route>
  4. Update navigation menus if needed

Adding New CSS

To add layout-specific CSS that gets loaded/unloaded:

  1. Create CSS file in src/assets/css/
  2. Import with ?inline suffix in the layout:
    import myNewCss from '../assets/css/myNew.css?inline';
  3. Add to the useDynamicStyles array:
    useDynamicStyles([existingCss, myNewCss], 'layout-id');

Frequently Asked Questions

Why do styles conflict between website and dashboard?

If you see style conflicts, ensure you're using the useDynamicStyles hook correctly and that CSS files are imported with ?inline. The hook ensures CSS is removed when navigating away.

How do I add a new Redux slice?

  1. Create slice in src/features/myFeature/mySlice.js
  2. Import and add to store in src/app/store.js

Can I use different themes for website and dashboard?

The unified theme keeps them in sync. If you need separate themes, you would need to modify UnifiedThemeContext to track separate states and apply different attributes per layout.

# Deployment

Building for Production

npm run build

This creates an optimized production build in the dist/ directory.

Deployment Platforms

ListOn can be deployed to:

  • Vercel: Zero-config deployment for Vite apps - npx vercel
  • Netlify: Drag-and-drop or Git-based deployment
  • GitHub Pages: Set base in vite.config.js
  • Traditional hosting: Upload dist/ folder to any web server

Environment Variables

Create .env files for different environments:

# .env.production
VITE_GOOGLE_MAP_API_KEY=your_production_maps_key

# .env.development
VITE_GOOGLE_MAP_API_KEY=your_development_maps_key

Build Optimization

The build already includes:

  • Code splitting via React.lazy() for all 68+ components
  • Tree shaking for unused code removal
  • CSS minification and optimization
  • Asset hashing for cache busting

# Sources and Credits

Libraries, icons, images, and resources used in this template:

Core Libraries

  1. React: JavaScript library for UI - react.dev
  2. Vite: Next generation frontend tooling - vitejs.dev
  3. Bootstrap: Build fast, responsive sites - getbootstrap.com
  4. Redux Toolkit: Official Redux toolset - redux-toolkit.js.org
  5. React Router: Declarative routing - reactrouter.com

UI Libraries

  1. Framer Motion: Production-ready motion library - framer.com/motion
  2. ApexCharts: Modern open-source charts - apexcharts.com
  3. TanStack Table: Headless UI for tables - tanstack.com/table
  4. Swiper: Modern mobile touch slider - swiperjs.com
  5. React Slick: Carousel component - react-slick.neostack.com
  6. AOS: Animate On Scroll Library - michalsnik.github.io/aos

Form & Validation

  1. Formik: Build forms in React - formik.org
  2. Yup: Schema validation library
  3. DOMPurify: XSS sanitizer for HTML - github.com/cure53/DOMPurify

Icons & Fonts

  1. React Icons: SVG React icons - react-icons.github.io
  2. React Feather: Feather icons as React components
  3. Font Awesome: Icon library - fontawesome.com
  4. Google Fonts - Wix Madefor Display: Primary font family
  5. Google Fonts - Caveat: Decorative font

Maps & Utilities

  1. React Google Maps API: Google Maps for React
  2. Snazzy Maps: Custom Google Maps styles - snazzymaps.com
  3. React Hot Toast: React notifications - react-hot-toast.com
  4. React Range: Range input component
  5. React CountUp: Count up animation
  6. MetisMenu: Collapsible menu plugin
  7. Perfect Scrollbar: Custom scrollbar

Images & Assets

  1. Unsplash: Free stock images - unsplash.com
  2. Freepik: Design assets - freepik.com
  3. Flaticon: Vector icons & stickers - flaticon.com
  4. unDraw: Open-source illustrations - undraw.co
Thank you for purchasing ListOn! This template combines a beautiful directory website with a powerful admin dashboard. If you have questions beyond this documentation, please contact us at [email protected]. We're happy to help!