Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions ASSESSMENT_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Mazer – Customized Assessment Build

This repo is a customized fork of Mazer focused on UI tweaks and data-driven components for a front‑end assessment.

- Original template: https://github.com/zuramai/mazer
- Fork: https://github.com/subrahmanyam024/mazer

## What’s included
- Data-bound dashboard KPIs and chart (reads from JSON)
- New Products page (search + pagination from JSON)
- Theme tweaks (primary color, rounded cards, active sidebar)
- Sidebar navigation entry for Products
- CDN fallbacks for vendor scripts during dev

## Getting started
1) Install and run
```
npm install
npm run dev
# open http://localhost:5173
```

2) Build
```
npm run build
```

## Data source
- JSON: `src/assets/data/data.json`
- Loader: `src/assets/js/services/dataService.js`
- Fetch path is relative for portability:
- `fetch('assets/data/data.json', { cache: 'no-store' })`

## Dashboard data binding
- Page: `src/index.html`
- Four KPI hooks via `data-kpi`:
- `data-kpi="totalUsers"`, `activeSessions`, `revenueToday`, `conversionRate`
- Script: `src/assets/static/js/pages/dashboard.js`
- Imported as a module in `index.html`
- Loads JSON and updates KPI elements
- Updates the main ApexCharts series from `salesSeries`

## Products page (data-driven table)
- Page: `src/products.html`
- Script: `src/assets/static/js/pages/products.js`
- Features:
- Pulls `topProducts` from `data.json`
- Client-side search (SKU/Name)
- Simple pagination (10 per page)

## Theme customization
- File: `src/assets/scss/_custom.scss`
- Primary color `#6b5bff`
- Rounded cards
- Active sidebar link highlight
- Included from `src/assets/scss/app.scss`

## Navigation
- Vertical sidebar items: `src/sidebar-items.json`
- Added `Products` → `products.html`
- Horizontal menu items (for reference): `src/horizontal-menu-items.json`

## Vendor/CDN notes
- During dev, some vendor files under `assets/extensions` may be missing. We use CDN for:
- Perfect Scrollbar: injected in `src/layouts/master.html`
- ApexCharts: injected in `src/index.html`
- You can switch back to local packages by ensuring Vite copies extensions (see `vite.config.js` modulesToCopy).

## Vite config
- `vite.config.js`
- `base` is `./` in dev and `/mazer/` in production (helpful for GitHub Pages)
- Static assets served from `src/assets/static`

## Branch and commit
- Suggested branch: `feat/custom-assessment`
- Example commit:
`feat: data-bound dashboard, products page, theme tweaks, CDN fixes`

## Key files changed/added
- `src/index.html` (KPI hooks, module script, CDN ApexCharts)
- `src/assets/static/js/pages/dashboard.js` (data binding)
- `src/assets/js/services/dataService.js` (data loader)
- `src/assets/data/data.json` (sample data)
- `src/products.html`, `src/assets/static/js/pages/products.js`
- `src/assets/scss/_custom.scss`, `src/assets/scss/app.scss`
- `src/layouts/master.html` (Perfect Scrollbar CDN)
- `src/sidebar-items.json` (Products menu)
- `vite.config.js` (prod base path)

## References
- Mazer template: https://github.com/zuramai/mazer


50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,53 @@ Mazer is created by <a href="https://saugi.me">Saugi</a>.
## Sponsors

![zuramai's sponsors](https://raw.githubusercontent.com/zuramai/static/main/sponsors.svg)

---

## Assessment Customization (Task 3)

This fork customizes Mazer to demonstrate real‑world adaptation: data binding, new page, and theme tweaks.

### Setup
- Node 18+ recommended
- Install and run
- `npm install`
- `npm run dev`
- Open `http://localhost:5173`

### Data binding
- Source: `src/assets/data/data.json`
- Loader: `src/assets/js/services/dataService.js`
- Dashboard bindings:
- File: `src/assets/static/js/pages/dashboard.js` (loaded as `type="module"`)
- Updates KPI elements in `src/index.html` via `data-kpi` attributes: `totalUsers`, `activeSessions`, `revenueToday`, `conversionRate`
- Updates ApexCharts series for the main chart from `salesSeries`

### New page: Products (data‑driven table)
- Page: `src/products.html`
- Script: `src/assets/static/js/pages/products.js`
- Features: client‑side search and pagination powered by `topProducts` in `data.json`
- Navigation: added "Products" under Table in `src/horizontal-menu-items.json`

### Theme customization
- Overrides in `src/assets/scss/_custom.scss` (primary color, rounded cards, active sidebar)
- Included from `src/assets/scss/app.scss`

### Vendor/CDN notes
- To avoid missing local vendor files during dev, we load CDNs:
- Perfect Scrollbar in `src/layouts/master.html`
- ApexCharts in `src/index.html`

### Branch & commits
- Recommended branch: `feat/custom-assessment`
- Example commit message: `feat: data-bound dashboard, products page, theme tweaks, CDN fixes`

### Files changed/added (key)
- `src/index.html` (KPI hooks, script type=module, ApexCharts CDN)
- `src/assets/static/js/pages/dashboard.js` (data binding)
- `src/assets/js/services/dataService.js` (data loader)
- `src/assets/data/data.json` (sample data)
- `src/products.html`, `src/assets/static/js/pages/products.js`
- `src/assets/scss/_custom.scss`, `src/assets/scss/app.scss`
- `src/layouts/master.html` (Perfect Scrollbar CDN)
- `src/horizontal-menu-items.json` (Products menu)
17 changes: 17 additions & 0 deletions src/assets/data/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"kpis": {
"totalUsers": 12450,
"activeSessions": 342,
"revenueToday": 18750,
"conversionRate": 3.9
},
"salesSeries": [
{ "name": "2025", "data": [31, 40, 28, 51, 42, 109, 100, 95, 88, 120, 140, 155] }
],
"topProducts": [
{ "sku": "A-100", "name": "Alpha Chair", "price": 129.99, "sold": 523 },
{ "sku": "B-220", "name": "Bravo Desk", "price": 299.0, "sold": 341 },
{ "sku": "C-330", "name": "Charlie Lamp", "price": 49.5, "sold": 812 },
{ "sku": "D-990", "name": "Delta Shelf", "price": 89.0, "sold": 211 }
]
}
5 changes: 5 additions & 0 deletions src/assets/js/services/dataService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export async function loadDashboardData() {
const response = await fetch('/assets/data/data.json', { cache: 'no-store' });
if (!response.ok) throw new Error(`Failed to load data.json: ${response.status}`);
return await response.json();
}
18 changes: 18 additions & 0 deletions src/assets/scss/_custom.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
:root {
--bs-primary: #6b5bff;
--bs-primary-rgb: 107, 91, 255;
}

.card {
border-radius: .75rem;
}

.sidebar .sidebar-item.active .sidebar-link {
background: rgba(var(--bs-primary-rgb), .12);
}

.btn-primary {
background-color: var(--bs-primary);
border-color: var(--bs-primary);
}

2 changes: 2 additions & 0 deletions src/assets/scss/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ body .bi::before, [class^=bi-]::before, [class*=" bi-"]::before {

// Mazer CSS
@import "./mazer";
// Custom theme overrides
@import "./custom";
31 changes: 30 additions & 1 deletion src/assets/static/js/pages/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { loadDashboardData } from "../../../js/services/dataService.js";

var optionsProfileVisit = {
annotations: {
position: "back",
Expand Down Expand Up @@ -164,4 +166,31 @@ chartAmerica.render()
chartIndia.render()
chartEurope.render()
chartProfileVisit.render()
chartVisitorsProfile.render()
chartVisitorsProfile.render();

// Bind KPIs and chart data from data.json
(async function bindDashboardFromData() {
try {
const data = await loadDashboardData()

// KPI elements (ensure hooks exist in HTML)
const elUsers = document.querySelector('[data-kpi="totalUsers"]')
const elSessions = document.querySelector('[data-kpi="activeSessions"]')
const elRevenue = document.querySelector('[data-kpi="revenueToday"]')
const elConv = document.querySelector('[data-kpi="conversionRate"]')

if (elUsers) elUsers.textContent = Number(data.kpis.totalUsers).toLocaleString()
if (elSessions) elSessions.textContent = Number(data.kpis.activeSessions).toLocaleString()
if (elRevenue) elRevenue.textContent = `$${Number(data.kpis.revenueToday).toLocaleString()}`
if (elConv) elConv.textContent = `${Number(data.kpis.conversionRate)}%`

// Update main sales/profile visit chart series
if (typeof chartProfileVisit !== "undefined" && data.salesSeries && data.salesSeries[0]) {
chartProfileVisit.updateSeries([
{ name: data.salesSeries[0].name || "sales", data: data.salesSeries[0].data || [] },
])
}
} catch (err) {
console.error("Failed to bind dashboard from data.json", err)
}
})()
71 changes: 71 additions & 0 deletions src/assets/static/js/pages/products.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { loadDashboardData } from "../../../js/services/dataService.js";

const PAGE_SIZE = 10;

function renderRows(tbody, rows) {
tbody.innerHTML = rows
.map(
(p) => `
<tr>
<td>${p.sku}</td>
<td>${p.name}</td>
<td class="text-end">$${Number(p.price).toFixed(2)}</td>
<td class="text-end">${Number(p.sold).toLocaleString()}</td>
</tr>`
)
.join("");
}

function renderPagination(container, total, currentPage, onPage) {
const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
container.innerHTML = Array.from({ length: totalPages }, (_, i) => i + 1)
.map(
(page) => `
<li class="page-item ${page === currentPage ? "active" : ""}">
<a class="page-link" href="#" data-page="${page}">${page}</a>
</li>`
)
.join("");

container.querySelectorAll('a[data-page]').forEach((a) => {
a.addEventListener('click', (e) => {
e.preventDefault();
onPage(parseInt(a.dataset.page, 10));
});
});
}

(async function initProducts() {
const tbody = document.querySelector('#productsTable tbody');
const pagination = document.querySelector('#productsPagination');
const search = document.querySelector('#productsSearch');
if (!tbody || !pagination) return;

const { topProducts } = await loadDashboardData();

let query = '';
let currentPage = 1;

function apply() {
const filtered = topProducts.filter((p) =>
[p.sku, p.name].join(' ').toLowerCase().includes(query.toLowerCase())
);
const start = (currentPage - 1) * PAGE_SIZE;
const pageRows = filtered.slice(start, start + PAGE_SIZE);
renderRows(tbody, pageRows);
renderPagination(pagination, filtered.length, currentPage, (page) => {
currentPage = page;
apply();
});
}

search?.addEventListener('input', () => {
query = search.value || '';
currentPage = 1;
apply();
});

apply();
})();


5 changes: 5 additions & 0 deletions src/horizontal-menu-items.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@
"name": "Datatable (jQuery)",
"url": "table-datatable-jquery.html",
"icon": "file-earmark-spreadsheet-fill"
},
{
"name": "Products",
"url": "products.html",
"icon": "bag-fill"
}
]
},
Expand Down
12 changes: 6 additions & 6 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ <h3>Profile Statistics</h3>
</div>
<div class="col-md-8 col-lg-12 col-xl-12 col-xxl-7">
<h6 class="text-muted font-semibold">Profile Views</h6>
<h6 class="font-extrabold mb-0">112.000</h6>
<h6 class="font-extrabold mb-0" data-kpi="totalUsers">0</h6>
</div>
</div>
</div>
Expand All @@ -43,7 +43,7 @@ <h6 class="font-extrabold mb-0">112.000</h6>
</div>
<div class="col-md-8 col-lg-12 col-xl-12 col-xxl-7">
<h6 class="text-muted font-semibold">Followers</h6>
<h6 class="font-extrabold mb-0">183.000</h6>
<h6 class="font-extrabold mb-0" data-kpi="activeSessions">0</h6>
</div>
</div>
</div>
Expand All @@ -60,7 +60,7 @@ <h6 class="font-extrabold mb-0">183.000</h6>
</div>
<div class="col-md-8 col-lg-12 col-xl-12 col-xxl-7">
<h6 class="text-muted font-semibold">Following</h6>
<h6 class="font-extrabold mb-0">80.000</h6>
<h6 class="font-extrabold mb-0" data-kpi="revenueToday">$0</h6>
</div>
</div>
</div>
Expand All @@ -77,7 +77,7 @@ <h6 class="font-extrabold mb-0">80.000</h6>
</div>
<div class="col-md-8 col-lg-12 col-xl-12 col-xxl-7">
<h6 class="text-muted font-semibold">Saved Post</h6>
<h6 class="font-extrabold mb-0">112</h6>
<h6 class="font-extrabold mb-0" data-kpi="conversionRate">0%</h6>
</div>
</div>
</div>
Expand Down Expand Up @@ -319,6 +319,6 @@ <h4>Visitors Profile</h4>
{% endblock %}
{% block js %}
<!-- Need: Apexcharts -->
<script src="assets/extensions/apexcharts/apexcharts.min.js"></script>
<script src="assets/static/js/pages/dashboard.js"></script>
<script src="https://cdn.jsdelivr.net/gh/zuramai/mazer@docs/demo/assets/extensions/apexcharts/apexcharts.min.js"></script>
<script type="module" src="assets/static/js/pages/dashboard.js"></script>
{% endblock %}
2 changes: 1 addition & 1 deletion src/layouts/master.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</div>
</div>
<script src="assets/static/js/components/dark.js"></script>
<script src="assets/extensions/perfect-scrollbar/perfect-scrollbar.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/zuramai/mazer@docs/demo/assets/extensions/perfect-scrollbar/perfect-scrollbar.min.js"></script>

{% if isDev %}
<script src="assets/js/app.js" type="module"></script>
Expand Down
Loading