# 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.
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
clickOutsidehook touseClickOutside(moved tosrc/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.logdebug statements from form submissions and navigation components - Code Quality: Removed the duplicate toast library (
react-toastify) - standardized onreact-hot-toasteverywhere - Refactor: Renamed
FooterLayouttoWebLayoutfor 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
useDynamicStyleshook 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
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:
indexWeb.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 validationsignUpValidation.js- Sign up form validationcontactFormValidation.js- Contact form validationresetPassValidation.js- Password reset validationtwoFactorValidation.js- 2FA code validationcommentValidation.js- Comment form validation
# CSS Architecture
The Problem & Solution
When the website and dashboard codebases were merged, their CSS files conflicted. The solution implements:
- Vite's ?inline imports - CSS is imported as raw strings
- useDynamicStyles hook - Injects CSS as <style> tags on mount
- 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.
/ redirects to /home via <Navigate to="/home" replace />, so the root URL never falls through to the 404 page.
Homepage Variants
| Route | Component | Description |
|---|---|---|
/home | HomeMain | Main homepage design |
/home-classic | HomeClassic | Classic listing style |
/home-grid | HomeGrid | Grid-based layout |
/home-map | HomeMap | Map-focused design |
/home-restaurant | HomeRestaurant | Restaurant listing style |
/home-rounded | HomeRounded | Rounded card design |
/home-waves | HomeWaves | Animated waves design |
/home-car | HomeCar | Car/vehicle listings |
Listing Pages
| Route | Component | Description |
|---|---|---|
/listing-grid | ListingGrid | Grid view listings |
/listing-list | ListingList | List view listings |
/listings-half-map | ListingHalfMap | Split view with map |
/listings-half-map-list | ListingHalfMapList | List + half map |
/listing-details | ListingDetails | Single listing details |
/listing-details-2 | ListingDetails2 | Alternative details layout |
Blog Pages
| Route | Component | Description |
|---|---|---|
/blog-grid | BlogGrid | Blog grid layout |
/blog-grid-sidebar | BlogGridSidebar | Blog with sidebar |
/blog-list | BlogList | Blog list layout |
/blog-list-sidebar | BlogListSidebar | Blog list with sidebar |
/blog-details | BlogDetails | Single blog post |
Template Pages
| Route | Component | Description |
|---|---|---|
/about | AboutOne | About page variant 1 |
/about-2 | AboutTwo | About page variant 2 |
/contact | ContactPage | Contact page |
/faq | FAQ | FAQ page |
/pricing | Pricing | Pricing plans |
/agent | Agent | Agent/team page |
/speciality | Speciality | Services/specialties |
/style-guide | StyleGuide | UI style guide |
/add-listing | AddListing | Public add listing |
/terms | TermsAndConditions | Terms & conditions |
Authentication Pages
| Route | Component | Description |
|---|---|---|
/sign-in | SignIn | Login page |
/sign-up | SignUp | Registration page |
/forgot-password | ForgotPassword | Password reset |
/two-factor-auth | TwoFactorAuth | 2FA verification |
# Dashboard Routes (DashLayout)
All dashboard pages are wrapped in DashLayout which provides the sidebar, navbar, and dashboard-specific CSS.
| Route | Component | Description |
|---|---|---|
/dashboard | DashHome | Dashboard home with analytics |
/dash-my-listings | MyListing | View/manage listings |
/dash-add-listings | AddListingForm | Create new listing |
/dash-bookings | Bookings | Manage bookings |
/dash-bookmarks | BookMarks | Saved/bookmarked items |
/dash-messages | Messeges | Chat/messaging system |
/dash-reviews | Reviews | Review management |
/dash-wallet | Wallet | Wallet/payments |
/dash-profile | EditProfile | Edit user profile |
/dash-settings | Settings | Account 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)
How It Works
The UnifiedThemeContext applies both theming approaches simultaneously:
data-bs-theme="dark|light"- Used by website (Bootstrap theme).darkclass 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>
);
};
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
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 ofquerySelectororgetElementById - Proper Cleanup: All event listeners, timers, and third-party plugins are cleaned up in
useEffectreturn functions - Memory Leak Prevention: Component unmounting properly destroys PerfectScrollbar, MetisMenu, and other plugin instances
- Performance Optimization: Context values are memoized with
useMemoanduseCallbackto prevent unnecessary rerenders
Code Quality
- Single Source of Truth: Removed duplicate theme contexts - only
UnifiedThemeContextis 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
| Slice | Location | Purpose |
|---|---|---|
| nav | features/navbar/navSlice.js | Navigation state management |
| priceFilter | features/price-filter/priceFilterSlice.js | Price filtering for listings |
| map | features/map/mapSlice.js | Google Maps state |
| chat | features/chat/ChatSlice.js | Chat messages |
| chatRightBar | features/ChatRight/chatRightSidebarSlice.js | Chat 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/:
# Getting Started
Prerequisites
- Node.js (v18 or higher recommended)
- npm or yarn package manager
- Google Maps API key (for maps features)
Installation Steps
-
Extract the template files
Unzip the downloaded file. You will get a folder named
liston-main -
Navigate to the project folder
Inside
liston-main, you'll find two folders:documentation- Contains this documentation fileliston- The main project source code
Open terminal in the
listonfolder: -
Install dependencies
npm install -
Configure environment variables
Create
.envfile in thelistonfolder with your API keys:VITE_GOOGLE_MAP_API_KEY=your_google_maps_api_key -
Start development server
npm run dev -
Open in browser
Navigate to
http://localhost:5173/home
Available Scripts
npm run dev- Start development server with hot reloadnpm run build- Build production-ready bundlenpm 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
- Create component in appropriate directory
- Add lazy import in
App.jsx:const MyNewPage = lazy(() => import('./components/MyNewPage')); - 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> - Update navigation menus if needed
Adding New CSS
To add layout-specific CSS that gets loaded/unloaded:
- Create CSS file in
src/assets/css/ - Import with
?inlinesuffix in the layout:import myNewCss from '../assets/css/myNew.css?inline'; - 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?
- Create slice in
src/features/myFeature/mySlice.js - 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
baseinvite.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
- React: JavaScript library for UI - react.dev
- Vite: Next generation frontend tooling - vitejs.dev
- Bootstrap: Build fast, responsive sites - getbootstrap.com
- Redux Toolkit: Official Redux toolset - redux-toolkit.js.org
- React Router: Declarative routing - reactrouter.com
UI Libraries
- Framer Motion: Production-ready motion library - framer.com/motion
- ApexCharts: Modern open-source charts - apexcharts.com
- TanStack Table: Headless UI for tables - tanstack.com/table
- Swiper: Modern mobile touch slider - swiperjs.com
- React Slick: Carousel component - react-slick.neostack.com
- AOS: Animate On Scroll Library - michalsnik.github.io/aos
Form & Validation
- Formik: Build forms in React - formik.org
- Yup: Schema validation library
- DOMPurify: XSS sanitizer for HTML - github.com/cure53/DOMPurify
Icons & Fonts
- React Icons: SVG React icons - react-icons.github.io
- React Feather: Feather icons as React components
- Font Awesome: Icon library - fontawesome.com
- Google Fonts - Wix Madefor Display: Primary font family
- Google Fonts - Caveat: Decorative font
Maps & Utilities
- React Google Maps API: Google Maps for React
- Snazzy Maps: Custom Google Maps styles - snazzymaps.com
- React Hot Toast: React notifications - react-hot-toast.com
- React Range: Range input component
- React CountUp: Count up animation
- MetisMenu: Collapsible menu plugin
- Perfect Scrollbar: Custom scrollbar
Images & Assets
- Unsplash: Free stock images - unsplash.com
- Freepik: Design assets - freepik.com
- Flaticon: Vector icons & stickers - flaticon.com
- unDraw: Open-source illustrations - undraw.co