Notika Admin Template
A green-themed Bootstrap 5 admin dashboard with 41 pages — dashboards, analytics, charts, forms, tables, email, and UI components. Powered by Vite 7.3 with ES6 modules and zero jQuery.
What's Included
Theme Colors
Notika uses a clean green accent on a white background:
Getting Started
Notika uses Vite as its build system. You need Node.js installed to run the dev server and build for production.
Prerequisites
Installation
-
Clone the repository
git clone https://github.com/nicdev/notika.git cd notika -
Install dependencies
npm installThis installs all npm packages listed in
package.json(Bootstrap, Chart.js, Vite, etc.). -
Start the dev server
npm run devOpens the template at
http://localhost:3100with hot module replacement (HMR). Any changes to HTML, JS, or SCSS files reflect instantly. -
Build for production
npm run buildOutputs optimized files to
dist/with minified CSS/JS, code-split chunks, and sourcemaps.
Available Commands
| Command | Description |
|---|---|
npm run dev |
Start Vite dev server with HMR on port 3100 |
npm run build |
Production build to dist/ directory |
npm run preview |
Preview production build locally on port 4173 |
npm run lint |
Run ESLint to check code quality |
npm run type-check |
Run TypeScript type checking |
Ctrl+C to stop it. Changes to SCSS files trigger instant recompilation and injection without a full page reload.
Page Catalog
All 41 pages organized by category. Each page uses the shared horizontal navigation layout except auth and error pages.
Dashboards 5
Feature Chart.js charts, counter animations, widget cards, and data visualizations.
Email 3
Charts 4
Powered by Chart.js 4.5 with bar, line, area, doughnut, and mixed chart types.
Tables 2
UI Components 10
Interface 6
Code Editor uses CodeMirror 6, Image Cropper uses Cropper.js 2, Maps use Leaflet 1.9.
Miscellaneous 5
Auth & Error 2
These pages use a minimal layout without the header and navigation.
File Structure
The Vite root is notika/green-horizotal/ (not the project root). The vite.config.js lives at the project root.
-
notika/ — project root
- package.json — dependencies and scripts
- vite.config.js — Vite build config (multi-page, Handlebars, chunks)
-
notika/green-horizotal/ — Vite root
- style.css — main theme (4,400+ lines, BS5 overrides)
- *.html (41 pages)
-
src/js/ — ES6 modules
- main.js — NotikaApp class, CSS imports, entry point (~1,185 lines)
-
modules/ — shared modules
- charts.js — NotikaCharts (Chart.js wrapper, instance Map)
- ui.js — NotikaUI (Bootstrap init, counters, toasts)
-
pages/ (31 page modules extending NotikaApp)
- analytics.js, animations.js, area-charts.js, bar-charts.js, ...
- data-table.js, form-components.js, form-elements.js, ...
- tabs.js, widgets.js, wizard.js, ...
-
src/css/ — source styles
- modern.scss — modern SCSS with CSS custom properties
- dashboard-widgets.css — widget layout styles
-
src/partials/ — Handlebars templates
- header.hbs — top header with search, messages, notifications
- navbar.hbs — horizontal dropdown navigation
- footer.hbs — page footer
- breadcrumb.hbs — dynamic breadcrumb with icons
-
css/ — component CSS
- header-modern-clean.css — header styling
- navbar-stable.css — horizontal navigation
- mobile-menu.css — offcanvas mobile menu
- responsive.css — responsive breakpoints
- widgets-consistent.css — widget spacing
-
img/ — images (Vite publicDir)
- logo/ — SVG logos (horizontal, dark, icon)
- post/, country/, cropper/, blog/, dialog/, widgets/
-
dist/ — production build output
- Optimized HTML, CSS, JS with code-split chunks
Key Files
vite.config.js |
Build configuration — multi-page input, Handlebars plugin, manual chunks, SCSS compilation, PostCSS |
src/js/main.js |
NotikaApp class (~1,185 lines) — imports all CSS, registers Font Awesome icons, initializes navigation, mobile menu, AOS, charts |
src/js/modules/charts.js |
NotikaCharts class — Chart.js wrapper storing instances in a Map for access, refresh, and destroy |
src/js/modules/ui.js |
NotikaUI class — Bootstrap component init, counter animations via IntersectionObserver, toast notifications |
style.css |
Main theme (4,400+ lines) — Bootstrap 5 overrides, component styles, layout rules |
src/css/modern.scss |
Modern SCSS with CSS custom properties for spacing, card shadows, and design tokens |
HTML Structure
All pages use a horizontal navigation layout with shared Handlebars partials for the header, navbar, footer, and breadcrumb.
Standardized Head
Every page uses this consistent <head> structure. CSS is imported through Vite (no <link> tags for libraries):
<html lang="en" data-page-module="pagename">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Title | Notika - Modern Vite Template</title>
<meta name="description" content="...">
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/logo/notika-icon.svg">
<link rel="alternate icon" href="/favicon.ico">
<!-- Google Fonts (only external CSS link needed) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<!-- All other CSS imported via Vite in main.js -->
</head>
<link> tags for Bootstrap, Font Awesome, AOS, or other libraries. They are all imported through main.js and bundled by Vite.
Standard Page Layout
Dashboard pages use this structure with Handlebars partials:
<body>
<!-- Header with logo, search, notifications -->
{{> header}}
<!-- Horizontal dropdown navbar -->
{{> navbar}}
<!-- Breadcrumb -->
{{> breadcrumb}}
<!-- Page Content -->
<div class="all-content-wrapper mg-b-15">
<div class="container">
<div class="row pt-3">
<div class="col-lg-12">
<!-- Your content here -->
</div>
</div>
</div>
</div>
<!-- Footer -->
{{> footer}}
<!-- Page module script -->
<script type="module" src="/src/js/pages/pagename.js"></script>
</body>
Handlebars Partials
Four shared partials live in src/partials/ and are injected at build time:
| Partial | Description |
|---|---|
| header.hbs | Top header bar with logo, search dropdown, message/notification/chat icons with badge counts |
| navbar.hbs | Horizontal dropdown navigation with 8 menu groups (Home, Email, Interface, Charts, Tables, Forms, Components, Pages) |
| breadcrumb.hbs | Dynamic breadcrumb with section-based icons (computed from filename in vite.config.js) |
| footer.hbs | Page footer with copyright and year (dynamic via Handlebars context) |
Navigation Structure
The template uses two navigation modes based on viewport width:
| Desktop (≥992px) | Horizontal dropdown navbar (.notika-navbar.d-none.d-lg-block) with 8 menu groups and Bootstrap 5 dropdowns |
| Mobile (<992px) | Offcanvas menu (#mobileNavOffcanvas) triggered by a hamburger button (.d-lg-none), forcefully hidden on desktop via CSS and JS |
Card Pattern
Content cards follow this consistent structure:
<div class="recent-post-wrapper notika-shadow">
<div class="recent-post-ctn">
<div class="recent-post-title">
<h2>Card Title</h2>
</div>
<div class="recent-post-items">
<!-- Card body content -->
</div>
</div>
</div>
Architecture
Notika uses a class-based ES6 module architecture with inheritance. A base NotikaApp class handles shared initialization, and page-specific modules extend it.
Class Hierarchy
NotikaApp (main.js)
├── NotikaCharts (modules/charts.js) — Chart.js wrapper
├── NotikaUI (modules/ui.js) — Bootstrap components, counters, toasts
│
└── Page Modules (pages/*.js) — 31 modules extending NotikaApp
├── AnalyticsPage
├── BarChartsPage
├── DataTablePage
├── TabsPage
└── ... (28 more)
How Pages Work
There are two types of pages:
Pages with custom logic
These set data-page-module on <html> and load a page-specific script. This prevents NotikaApp from auto-initializing:
<html lang="en" data-page-module="analytics">
...
<script type="module" src="/src/js/pages/analytics.js"></script>
Pages without custom logic
These omit data-page-module and load main.js directly. NotikaApp auto-initializes at the bottom of main.js:
<html lang="en">
...
<script type="module" src="/src/js/main.js"></script>
Page Module Pattern
Every page module follows this structure:
import { NotikaApp } from '../main.js'
class MyPage extends NotikaApp {
async init() {
await super.init() // Initialize shared features
// Page-specific setup here
this.initCustomChart()
this.initSpecialWidget()
}
initCustomChart() {
const el = document.getElementById('my-chart')
if (!el) return // Guard clause
// Chart initialization...
}
}
// Instantiate when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
window.myPage = new MyPage()
window.myPage.init()
})
} else {
window.myPage = new MyPage()
window.myPage.init()
}
export { MyPage }
Shared Modules
| Module | Class | Responsibility |
|---|---|---|
| modules/charts.js | NotikaCharts |
Wraps Chart.js — stores instances in a Map, manages color palette, handles initialization of sales/items/sparkline/knob charts, provides access/refresh/destroy methods |
| modules/ui.js | NotikaUI |
Bootstrap component initialization (tooltips, popovers), counter animations using IntersectionObserver + requestAnimationFrame, toast notification system |
CSS Loading Strategy
All CSS is imported through main.js via Vite. This means:
- No
<link>tags needed for any library CSS - Vite bundles, minifies, and code-splits CSS automatically
- Only Google Fonts and mobile menu CSS use traditional
<link>tags
// In main.js — CSS imports (order matters)
import 'bootstrap/dist/css/bootstrap.css'
import 'aos/dist/aos.css'
import 'leaflet/dist/leaflet.css'
import 'swiper/css'
import '../../css/header-modern-clean.css'
import '../../css/navbar-stable.css'
import '../../css/responsive.css'
import '../../css/widgets-consistent.css'
import '../../style.css'
import '../css/modern.scss'
import '../css/dashboard-widgets.css'
JavaScript
All JavaScript is vanilla ES6 modules — no jQuery. The main entry point registers Font Awesome icons, imports CSS, and initializes the NotikaApp class.
Design Principles
- One function per feature —
initMobileMenu(),initScrollbarCleanup(), etc. - Guard clauses — every function starts with
if (!el) returnto skip gracefully on pages where elements don't exist - No global state — library instances are scoped within their init function or class
- Modern APIs —
IntersectionObserver,requestAnimationFrame,classList,querySelectorAll - AOS initialized outside DOMContentLoaded — scripts are at the body bottom, so AOS must run immediately
Font Awesome Tree-Shaking
Icons are explicitly imported and registered. Only imported icons are bundled:
// In main.js
import { library, dom } from '@fortawesome/fontawesome-svg-core'
import { faHouse, faEnvelope, faBell, faChartColumn, ... }
from '@fortawesome/free-solid-svg-icons'
import { faGithub, faTwitter, ... }
from '@fortawesome/free-brands-svg-icons'
library.add(faHouse, faEnvelope, faBell, faChartColumn, ...)
dom.watch() // Converts <i> tags to SVGs
To use a new icon:
- Import it:
import { faNewIcon } from '@fortawesome/free-solid-svg-icons' - Register it: add to
library.add(...) - Use in HTML:
<i class="fa-solid fa-new-icon"></i>
NotikaApp Class Methods
- async init() Main initialization — calls all sub-initializers in order
- initCharts() Creates NotikaCharts instance, initializes Chart.js charts
- initUI() Creates NotikaUI instance for Bootstrap components and counters
- initAOS() Scroll-reveal animations via AOS (initialized outside DOMContentLoaded)
- initMobileMenu() Offcanvas mobile navigation with prevention on desktop
- preventMobileMenuOnDesktop() Blocks offcanvas show event on ≥992px viewports
- removeAllScrollbarRules() Strips webkit scrollbar CSS rules to restore native scrollbars
Auto-Initialization
At the bottom of main.js, the app checks for data-page-module. If absent, it auto-initializes:
// At bottom of main.js (line ~1181)
if (!document.documentElement.dataset.pageModule) {
const app = new NotikaApp()
app.init()
}
Page modules that set data-page-module handle their own initialization by extending NotikaApp and calling super.init().
Chart.js Registration
Chart.js components are registered globally in main.js so all page modules can use them:
import { Chart, registerables } from 'chart.js'
Chart.register(...registerables)
window.bootstrap = bootstrap // Also exposed globally
CSS & Styling
CSS is loaded through Vite imports in main.js. The template uses a mix of compiled CSS files and modern SCSS with CSS custom properties.
CSS Architecture
| File | Purpose |
|---|---|
| style.css | Main theme (4,400+ lines) — all Bootstrap 5 overrides, component styles, layout, cards, forms |
| src/css/modern.scss | Modern SCSS with CSS custom properties (--notika-spacing-*), card shadows, design tokens |
| css/header-modern-clean.css | Header bar styling — .notika-header, dropdown menus, icon badges |
| css/navbar-stable.css | Horizontal dropdown navigation — .notika-navbar, active states, transitions |
| css/mobile-menu.css | Offcanvas mobile menu — responsive toggle, forced hiding on desktop |
| css/responsive.css | Legacy responsive breakpoints (being gradually cleaned up) |
| css/widgets-consistent.css | Widget card spacing and grid layout consistency |
CSS Custom Properties
Spacing and design tokens use CSS custom properties defined in modern.scss:
:root {
--notika-spacing-xs: 8px;
--notika-spacing-sm: 16px;
--notika-spacing-md: 24px;
--notika-spacing-lg: 32px;
}
Card Shadows
/* Default card shadow */
.notika-shadow {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* Hover state */
.notika-shadow:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
Z-Index Layers
| Header | z-index: 1090 (header-modern-clean.css) |
| Navbar | z-index: 1085 (navbar-stable.css) |
| Mobile Offcanvas | z-index: 1045 (Bootstrap default) |
SCSS Compilation
SCSS uses the modern compiler API via Vite, with PostCSS for autoprefixer and cssnano:
// In vite.config.js
css: {
preprocessorOptions: {
scss: { api: 'modern-compiler' }
},
postcss: {
plugins: [autoprefixer(), cssnano({ preset: 'default' })]
}
}
Build System
Notika uses Vite 7.3.1 as its build tool. The config lives at the project root but sets root to ./notika/green-horizotal.
Multi-Page Setup
All 41 HTML pages are listed as separate entry points in rollupOptions.input. This ensures each page gets its own optimized bundle:
// vite.config.js
build: {
outDir: '../../dist',
rollupOptions: {
input: {
main: resolve(cwd, 'notika/green-horizotal/index.html'),
analytics: resolve(cwd, 'notika/green-horizotal/analytics.html'),
'index-2': resolve(cwd, 'notika/green-horizotal/index-2.html'),
// ... 38 more pages
}
}
}
Code Splitting
Vite automatically code-splits, plus three manual chunks for better caching:
vendor |
Bootstrap CSS and JS — cached separately since it rarely changes |
charts |
Chart.js — only loaded on pages with charts |
ui |
Swiper + AOS — carousel and animation libraries |
Handlebars Plugin
The vite-plugin-handlebars plugin provides template partials and dynamic context computed from the filename:
plugins: [
handlebars({
partialDirectory: resolve(cwd, 'notika/green-horizotal/src/partials'),
context: (pagePath) => {
const pageName = pagePath.split('/').pop()?.replace('.html', '')
return {
pageTitle: pageName.charAt(0).toUpperCase() + pageName.slice(1),
year: new Date().getFullYear(),
isHome: ['index', 'analytics', 'widgets'].some(p => pageName.includes(p)),
isCharts: ['bar-charts', 'line-charts', ...].some(p => pageName.includes(p)),
// ... more nav active flags
breadcrumbIcon: pageName.includes('chart') ? 'fa-solid fa-chart-column' : '...'
}
}
})
]
Dev Server
Production Build
Path Aliases
resolve: {
alias: {
'@': resolve(cwd, './src'),
'@css': resolve(cwd, './notika/green-horizotal/css'),
'@js': resolve(cwd, './notika/green-horizotal/js'),
'@img': resolve(cwd, './notika/green-horizotal/img')
}
}
Libraries & Dependencies
All libraries are bundled via Vite from npm packages. No CDN links, no local vendor files. This section lists every dependency and its purpose.
Core Stack
| Library | Version | Purpose |
|---|---|---|
| Vite | 7.3.1 | Build system with HMR, code splitting, SCSS, multi-page support |
| Bootstrap | 5.3.8 | CSS framework + JS components (dropdowns, modals, tooltips, offcanvas) |
| Font Awesome | 7.2.0 | Tree-shaken SVG icons (solid + brand packages) |
Charts & Maps
| Library | Version | Used On |
|---|---|---|
| Chart.js | 4.5.1 | All dashboards and chart pages — bar, line, area, doughnut, sparkline |
| Leaflet | 1.9.4 | Google Map and Data Maps pages — interactive tile-based maps |
UI & Animation
| Library | Version | Purpose |
|---|---|---|
| Swiper | 12.1.0 | Touch-enabled carousel slider for dashboards |
| AOS | 2.3.4 | Scroll-reveal animations (fade, slide, zoom effects) |
| Animate.css | 4.1.1 | CSS animation library for the Animations page |
| Day.js | 1.11.19 | Lightweight date formatting and manipulation |
Editors & Media
| Library | Version | Purpose |
|---|---|---|
| CodeMirror | 6.x | In-browser code editor with HTML and JS language support, One Dark theme |
| Cropper.js | 2.1.0 | Image cropping and manipulation on the Image Cropper page |
Dev Dependencies
| Library | Version | Purpose |
|---|---|---|
| Sass | 1.97.3 | SCSS compilation with modern compiler API |
| PostCSS | 8.5.6 | CSS processing pipeline |
| Autoprefixer | 10.4.24 | Automatic vendor prefixes for cross-browser support |
| cssnano | 7.1.2 | CSS minification for production builds |
| TypeScript | 5.9.3 | Type checking (optional, via npm run type-check) |
| ESLint | 10.0.0 | Code linting (via npm run lint) |
| Prettier | 3.8.1 | Code formatting |
| vite-plugin-handlebars | 2.0.0 | Handlebars template partials and dynamic context |
Customization
How to modify the template's appearance and behavior to match your project requirements.
Changing Theme Colors
The primary green color (#00c292) is used throughout the template. To change it, search and replace in these files:
/* style.css — Primary accent color */
/* Search for #00c292 and replace globally */
/* src/js/modules/charts.js — Chart colors */
this.colors = {
primary: '#00c292', /* Change this */
secondary: '#03a9f3',
success: '#00c292',
warning: '#ff9800',
danger: '#e91e63',
info: '#03a9f3'
}
Adding a New Page
-
Create the HTML file
Copy an existing page (e.g.
tabs.html) tonotika/green-horizotal/newpage.html. Update the<title>and content. -
Register in Vite config
Add the page to
rollupOptions.inputinvite.config.js:newpage: resolve(process.cwd(), 'notika/green-horizotal/newpage.html'), -
Create a page module (optional)
If the page needs custom JavaScript, create
src/js/pages/newpage.js:import { NotikaApp } from '../main.js' class NewPage extends NotikaApp { async init() { await super.init() // Custom logic here } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { window.newPage = new NewPage() window.newPage.init() }) } else { window.newPage = new NewPage() window.newPage.init() } export { NewPage } -
Set the data attribute and script
In your HTML, set
data-page-moduleand load the page script:<html lang="en" data-page-module="newpage"> ... <script type="module" src="/src/js/pages/newpage.js"></script>
Adding Font Awesome Icons
Icons are tree-shaken, so only imported icons are bundled. To add a new icon:
// 1. Import in main.js
import { faNewIcon } from '@fortawesome/free-solid-svg-icons'
// 2. Add to library.add() call
library.add(faHouse, faEnvelope, faBell, faNewIcon, ...)
// 3. Use in HTML
<i class="fa-solid fa-new-icon"></i>
@fortawesome/free-solid-svg-icons and @fortawesome/free-brands-svg-icons packages are available. Browse all icons at fontawesome.com.
Adding Charts
Chart.js is globally registered. Add a canvas element and initialize:
<!-- 1. Add a canvas -->
<canvas id="myChart"></canvas>
<!-- 2. Initialize in your page module -->
// In your page module's init()
initMyChart() {
const canvas = document.getElementById('myChart')
if (!canvas) return
new Chart(canvas, {
type: 'bar',
data: {
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
datasets: [{
label: 'Sales',
data: [30, 40, 35, 50, 49],
backgroundColor: '#00c292'
}]
},
options: {
responsive: true,
plugins: { legend: { display: false } }
}
})
}
Modifying the Navigation
The navigation is defined in src/partials/navbar.hbs. To add a new menu item:
<!-- In navbar.hbs -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">
<i class="fa-solid fa-star"></i>
<span>New Section</span>
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="newpage.html">New Page</a></li>
</ul>
</li>
Don't forget to add a corresponding active-state flag in vite.config.js's context function.
Responsive Breakpoints
| 992px and above | Full horizontal navbar with dropdowns, desktop header layout |
| Below 992px | Offcanvas mobile menu, hamburger toggle, simplified header |
| Below 768px | Single-column layout, cards stack vertically, compact icon logo |
Spacing Convention
The template follows a consistent spacing pattern:
mg-b-15on the main content wrapperpt-3on the first.rowinside contentmt-4on subsequent rows- CSS custom properties for reusable spacing:
--notika-spacing-xs(8px) through--notika-spacing-lg(32px)
Sources & Credits
Third-party libraries and resources used in this template.
Framework & Build
Charts & Maps
UI & Animation
Editors & Media
Build Tools
Support
Thank you for using Notika. If you have any questions or run into issues, we're here to help.
Browser Support
Need Help?
Our support team is happy to assist with questions about setup, customization, or troubleshooting.
Contact Colorlib