Initial commit - Admin Template HTML
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Revenue', data: [1.8, 2.1, 1.9, 2.2, 2.4, 2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Target', data: [1.4, 1.6, 1.5, 1.7, 1.8, 1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Website', 'Referral', 'Social', 'Email', 'Others'], datasets: [{ data: [42, 22, 15, 12, 9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['Calls', 'Emails', 'Meetings', 'Total'], datasets: [{ label: 'Activity', data: [245, 450, 89, 784], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => v.toLocaleString() } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Revenue', data: [1.8, 2.1, 1.9, 2.2, 2.4, 2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Maintenance', data: [1.4, 1.6, 1.5, 1.7, 1.8, 1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Production', 'Utilities', 'Infrastructure', 'Transport', 'Facilities'], datasets: [{ data: [42, 22, 15, 12, 9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['PM', 'CM', 'Inspection', 'Total'], datasets: [{ label: 'Activity', data: [142, 86, 312, 540], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => v } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Revenue', data: [1.8, 2.1, 1.9, 2.2, 2.4, 2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Expenses', data: [1.4, 1.6, 1.5, 1.7, 1.8, 1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Payroll', 'Operations', 'Marketing', 'R&D', 'Others'], datasets: [{ data: [42, 22, 15, 12, 9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['Operating', 'Investing', 'Financing', 'Net Change'], datasets: [{ label: 'Cash Flow', data: [3.2, -1.1, -0.8, 1.3], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Revenue', data: [1.8, 2.1, 1.9, 2.2, 2.4, 2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'New Hires', data: [1.4, 1.6, 1.5, 1.7, 1.8, 1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Engineering', 'Marketing', 'Sales', 'Operations', 'HR & Finance'], datasets: [{ data: [42, 22, 15, 12, 9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['Active', 'On Leave', 'Probation', 'Contract End'], datasets: [{ label: 'Status', data: [89.2, 5.5, 4.2, 1.1], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Revenue', data: [1.8, 2.1, 1.9, 2.2, 2.4, 2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Resolved', data: [1.4, 1.6, 1.5, 1.7, 1.8, 1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Hardware', 'Software', 'Network', 'Security', 'Other'], datasets: [{ data: [28, 32, 18, 12, 10], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['Critical', 'High', 'Medium', 'Total'], datasets: [{ label: 'Priority', data: [8, 14, 18, 40], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Revenue', data: [1.8, 2.1, 1.9, 2.2, 2.4, 2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Target', data: [1.4, 1.6, 1.5, 1.7, 1.8, 1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Website', 'Referral', 'Social', 'Email', 'Others'], datasets: [{ data: [42, 22, 15, 12, 9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['Calls', 'Emails', 'Meetings', 'Total'], datasets: [{ label: 'Activity', data: [245, 450, 89, 784], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => v.toLocaleString() } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan','Feb','Mar','Apr','May','Jun'], datasets: [{ label: 'Scheduled', data: [1.8,2.1,1.9,2.2,2.4,2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Unfilled', data: [1.4,1.6,1.5,1.7,1.8,1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => v + 'K' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Morning','Afternoon','Night','Weekend','Others'], datasets: [{ data: [42,22,15,12,9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['Clock In','Clock Out','Breaks','Total'], datasets: [{ label: 'Activity', data: [245, 450, 89, 784], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 } } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
(function() {
|
||||
const nav = document.getElementById('sidebar-nav');
|
||||
const wrap = document.getElementById('sidebar-nav-wrap');
|
||||
const track = document.getElementById('sb-track');
|
||||
const thumb = document.getElementById('sb-thumb');
|
||||
if (!nav || !track || !thumb || !wrap) return;
|
||||
let isDragging = false;
|
||||
function show() { track.style.opacity = '1'; }
|
||||
function hide() { if (!isDragging) track.style.opacity = '0'; }
|
||||
function update() {
|
||||
const sh = nav.scrollHeight, ch = nav.clientHeight;
|
||||
if (sh <= ch) { track.style.display = 'none'; return; }
|
||||
track.style.display = 'block'; track.style.opacity = '1';
|
||||
const st = nav.scrollTop, th = Math.max((ch / sh) * ch, 24);
|
||||
const maxTop = ch - th, ratio = sh > ch ? st / (sh - ch) : 0;
|
||||
thumb.style.height = th + 'px'; thumb.style.top = (ratio * maxTop) + 'px';
|
||||
}
|
||||
const observer = new MutationObserver(function() {
|
||||
update(); setTimeout(function() {
|
||||
update();
|
||||
if (nav.scrollHeight > nav.clientHeight) { track.style.display = 'block'; track.style.opacity = '1'; }
|
||||
}, 350);
|
||||
});
|
||||
observer.observe(nav, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
|
||||
nav.addEventListener('scroll', update); window.addEventListener('resize', update);
|
||||
wrap.addEventListener('mouseenter', function() { show(); update(); });
|
||||
wrap.addEventListener('mouseleave', hide);
|
||||
thumb.addEventListener('mousedown', function(e) {
|
||||
e.preventDefault(); isDragging = true; track.style.opacity = '1';
|
||||
document.body.style.cursor = 'pointer'; document.body.style.userSelect = 'none';
|
||||
function onMove(ev) {
|
||||
if (!isDragging) return;
|
||||
const rect = track.getBoundingClientRect();
|
||||
nav.scrollTop = ((ev.clientY - rect.top) / rect.height) * (nav.scrollHeight - nav.clientHeight);
|
||||
}
|
||||
function onUp() {
|
||||
isDragging = false; document.body.style.cursor = ''; document.body.style.userSelect = '';
|
||||
document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp);
|
||||
}
|
||||
document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp);
|
||||
});
|
||||
update(); setTimeout(update, 300);
|
||||
})();
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan','Feb','Mar','Apr','May','Jun'], datasets: [{ label: 'Revenue', data: [1.8,2.1,1.9,2.2,2.4,2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Budget', data: [1.4,1.6,1.5,1.7,1.8,1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Direct Raw','Indirect','Logistics','IT','Others'], datasets: [{ data: [42,22,15,12,9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['PR Created','PO Issued','Deliveries','Total'], datasets: [{ label: 'Procurement', data: [423, 186, 52, 661], backgroundColor: ['#10b981', '#10b981', '#10b981', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 } } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
(function() {
|
||||
const nav = document.getElementById('sidebar-nav');
|
||||
const wrap = document.getElementById('sidebar-nav-wrap');
|
||||
const track = document.getElementById('sb-track');
|
||||
const thumb = document.getElementById('sb-thumb');
|
||||
if (!nav || !track || !thumb || !wrap) return;
|
||||
let isDragging = false;
|
||||
function show() { track.style.opacity = '1'; }
|
||||
function hide() { if (!isDragging) track.style.opacity = '0'; }
|
||||
function update() {
|
||||
const sh = nav.scrollHeight, ch = nav.clientHeight;
|
||||
if (sh <= ch) { track.style.display = 'none'; return; }
|
||||
track.style.display = 'block'; track.style.opacity = '1';
|
||||
const st = nav.scrollTop, th = Math.max((ch / sh) * ch, 24);
|
||||
const maxTop = ch - th, ratio = sh > ch ? st / (sh - ch) : 0;
|
||||
thumb.style.height = th + 'px'; thumb.style.top = (ratio * maxTop) + 'px';
|
||||
}
|
||||
const observer = new MutationObserver(function() {
|
||||
update(); setTimeout(function() {
|
||||
update();
|
||||
if (nav.scrollHeight > nav.clientHeight) { track.style.display = 'block'; track.style.opacity = '1'; }
|
||||
}, 350);
|
||||
});
|
||||
observer.observe(nav, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
|
||||
nav.addEventListener('scroll', update); window.addEventListener('resize', update);
|
||||
wrap.addEventListener('mouseenter', function() { show(); update(); });
|
||||
wrap.addEventListener('mouseleave', hide);
|
||||
thumb.addEventListener('mousedown', function(e) {
|
||||
e.preventDefault(); isDragging = true; track.style.opacity = '1';
|
||||
document.body.style.cursor = 'pointer'; document.body.style.userSelect = 'none';
|
||||
function onMove(ev) {
|
||||
if (!isDragging) return;
|
||||
const rect = track.getBoundingClientRect();
|
||||
nav.scrollTop = ((ev.clientY - rect.top) / rect.height) * (nav.scrollHeight - nav.clientHeight);
|
||||
}
|
||||
function onUp() {
|
||||
isDragging = false; document.body.style.cursor = ''; document.body.style.userSelect = '';
|
||||
document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp);
|
||||
}
|
||||
document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp);
|
||||
});
|
||||
update(); setTimeout(update, 300);
|
||||
})();
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan','Feb','Mar','Apr','May','Jun'], datasets: [{ label: 'Revenue', data: [1.8,2.1,1.9,2.2,2.4,2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Target', data: [1.4,1.6,1.5,1.7,1.8,1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Website','Referral','Social','Email','Others'], datasets: [{ data: [42,22,15,12,9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['Calls','Emails','Meetings','Total'], datasets: [{ label: 'Activity', data: [245, 450, 89, 784], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => v.toLocaleString() } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
(function() {
|
||||
const nav = document.getElementById('sidebar-nav');
|
||||
const wrap = document.getElementById('sidebar-nav-wrap');
|
||||
const track = document.getElementById('sb-track');
|
||||
const thumb = document.getElementById('sb-thumb');
|
||||
if (!nav || !track || !thumb || !wrap) return;
|
||||
let isDragging = false;
|
||||
function show() { track.style.opacity = '1'; }
|
||||
function hide() { if (!isDragging) track.style.opacity = '0'; }
|
||||
function update() {
|
||||
const sh = nav.scrollHeight, ch = nav.clientHeight;
|
||||
if (sh <= ch) { track.style.display = 'none'; return; }
|
||||
track.style.display = 'block'; track.style.opacity = '1';
|
||||
const st = nav.scrollTop, th = Math.max((ch / sh) * ch, 24);
|
||||
const maxTop = ch - th, ratio = sh > ch ? st / (sh - ch) : 0;
|
||||
thumb.style.height = th + 'px'; thumb.style.top = (ratio * maxTop) + 'px';
|
||||
}
|
||||
const observer = new MutationObserver(function() {
|
||||
update(); setTimeout(function() {
|
||||
update();
|
||||
if (nav.scrollHeight > nav.clientHeight) { track.style.display = 'block'; track.style.opacity = '1'; }
|
||||
}, 350);
|
||||
});
|
||||
observer.observe(nav, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
|
||||
nav.addEventListener('scroll', update); window.addEventListener('resize', update);
|
||||
wrap.addEventListener('mouseenter', function() { show(); update(); });
|
||||
wrap.addEventListener('mouseleave', hide);
|
||||
thumb.addEventListener('mousedown', function(e) {
|
||||
e.preventDefault(); isDragging = true; track.style.opacity = '1';
|
||||
document.body.style.cursor = 'pointer'; document.body.style.userSelect = 'none';
|
||||
function onMove(ev) {
|
||||
if (!isDragging) return;
|
||||
const rect = track.getBoundingClientRect();
|
||||
nav.scrollTop = ((ev.clientY - rect.top) / rect.height) * (nav.scrollHeight - nav.clientHeight);
|
||||
}
|
||||
function onUp() {
|
||||
isDragging = false; document.body.style.cursor = ''; document.body.style.userSelect = '';
|
||||
document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp);
|
||||
}
|
||||
document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp);
|
||||
});
|
||||
update(); setTimeout(update, 300);
|
||||
})();
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const grayText = '#94a3b8';
|
||||
const plRevenue = '#2563eb', plExpenses = '#f97316';
|
||||
new Chart(document.getElementById('plChart'), { type: 'bar', data: { labels: ['Jan','Feb','Mar','Apr','May','Jun'], datasets: [{ label: 'Revenue', data: [1.8,2.1,1.9,2.2,2.4,2.0], backgroundColor: plRevenue, borderRadius: 4, barPercentage: 0.4 }, { label: 'Outgoing', data: [1.4,1.6,1.5,1.7,1.8,1.5], backgroundColor: plExpenses, borderRadius: 4, barPercentage: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => '$' + v + 'M' } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
new Chart(document.getElementById('expenseChart'), { type: 'doughnut', data: { labels: ['Racking','Bulk','Overflow','Cold','Others'], datasets: [{ data: [42,22,15,12,9], backgroundColor: ['#2563eb', '#f97316', '#ec4899', '#8b5cf6', '#06b6d4'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, cutout: '72%', plugins: { legend: { display: false } } } });
|
||||
new Chart(document.getElementById('cashflowChart'), { type: 'bar', data: { labels: ['Goods Receive','Deliveries','Adjustments','Total'], datasets: [{ label: 'Activity', data: [450, 320, 180, 950], backgroundColor: ['#10b981', '#e11d48', '#e11d48', '#6366f1'], borderRadius: 4, barPercentage: 0.5 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ticks: { color: grayText, font: { size: 10 }, callback: v => v } }, x: { grid: { display: false }, ticks: { color: grayText, font: { size: 9 } } } } } });
|
||||
});
|
||||
@@ -0,0 +1,215 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const selectAll = document.getElementById('select-all-invoices');
|
||||
const invoiceChecks = document.querySelectorAll('.invoice-checkbox');
|
||||
const bulkToolbar = document.getElementById('bulk-toolbar');
|
||||
const selectedCount = document.getElementById('selected-count');
|
||||
if (selectAll && invoiceChecks.length) {
|
||||
function updateBulkToolbar() {
|
||||
const checked = document.querySelectorAll('.invoice-checkbox:checked');
|
||||
const count = checked.length;
|
||||
if (count > 0) {
|
||||
bulkToolbar.classList.remove('hidden');
|
||||
bulkToolbar.classList.add('flex');
|
||||
selectedCount.textContent = count + ' selected';
|
||||
invoiceChecks.forEach(function (cb) { cb.closest('tr').classList.toggle('bg-blue-50/40', cb.checked); });
|
||||
} else {
|
||||
bulkToolbar.classList.add('hidden');
|
||||
bulkToolbar.classList.remove('flex');
|
||||
selectedCount.textContent = '0 selected';
|
||||
invoiceChecks.forEach(function (cb) { cb.closest('tr').classList.remove('bg-blue-50/40'); });
|
||||
}
|
||||
}
|
||||
selectAll.addEventListener('change', function () {
|
||||
invoiceChecks.forEach(function (cb) { cb.checked = selectAll.checked; });
|
||||
updateBulkToolbar();
|
||||
});
|
||||
invoiceChecks.forEach(function (cb) {
|
||||
cb.addEventListener('change', function () {
|
||||
var allChecked = true;
|
||||
invoiceChecks.forEach(function (c) { if (!c.checked) allChecked = false; });
|
||||
selectAll.checked = allChecked;
|
||||
updateBulkToolbar();
|
||||
});
|
||||
});
|
||||
}
|
||||
var expandBtns = document.querySelectorAll('.expand-btn');
|
||||
expandBtns.forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var row = this.closest('tr');
|
||||
var detailRow = row.nextElementSibling;
|
||||
var icon = this.querySelector('.expand-icon');
|
||||
if (detailRow && detailRow.classList.contains('expand-detail')) {
|
||||
detailRow.classList.toggle('hidden');
|
||||
if (detailRow.classList.contains('hidden')) { icon.style.transform = 'rotate(0deg)'; }
|
||||
else { icon.style.transform = 'rotate(90deg)'; }
|
||||
}
|
||||
});
|
||||
});
|
||||
(function () {
|
||||
var searchInput = document.getElementById('product-search');
|
||||
var catSelect = document.getElementById('product-category');
|
||||
var tbody = document.getElementById('product-tbody');
|
||||
var infoEl = document.getElementById('product-info');
|
||||
if (!searchInput || !catSelect || !tbody || !infoEl) return;
|
||||
var productRows = Array.prototype.slice.call(tbody.querySelectorAll('tr'));
|
||||
function filterProducts() {
|
||||
var q = searchInput.value.toLowerCase().trim();
|
||||
var cat = catSelect.value;
|
||||
var visible = 0;
|
||||
var lowStock = 0;
|
||||
productRows.forEach(function (tr) {
|
||||
var cells = tr.querySelectorAll('td');
|
||||
if (cells.length < 5) return;
|
||||
var sku = cells[0].textContent.toLowerCase();
|
||||
var name = cells[1].textContent.toLowerCase();
|
||||
var category = cells[2].textContent.trim();
|
||||
var stockText = cells[3].textContent.trim();
|
||||
var stockNum = parseInt(stockText.replace(/[^0-9-]/g, '')) || 0;
|
||||
var matchSearch = q === '' || sku.indexOf(q) !== -1 || name.indexOf(q) !== -1;
|
||||
var matchCat = cat === '' || category === cat;
|
||||
if (matchSearch && matchCat) {
|
||||
tr.style.display = '';
|
||||
visible++;
|
||||
if (stockNum > 0 && stockNum < 100) lowStock++;
|
||||
} else {
|
||||
tr.style.display = 'none';
|
||||
}
|
||||
});
|
||||
infoEl.innerHTML = 'Showing <b class="text-gray-600">' + visible + '</b> of <b class="text-gray-600">' + productRows.length + '</b> products';
|
||||
var lowEl = infoEl.parentElement.querySelector('.text-amber-600');
|
||||
if (lowEl) lowEl.textContent = lowStock;
|
||||
}
|
||||
searchInput.addEventListener('input', filterProducts);
|
||||
catSelect.addEventListener('change', filterProducts);
|
||||
})();
|
||||
(function () {
|
||||
var tbody = document.getElementById('transactions-tbody');
|
||||
var infoEl = document.getElementById('transactions-info');
|
||||
var pageBtnsEl = document.getElementById('transactions-page-btns');
|
||||
if (!tbody || !infoEl || !pageBtnsEl) return;
|
||||
var perPage = 10;
|
||||
var totalEntries = 120;
|
||||
var totalPages = Math.ceil(totalEntries / perPage);
|
||||
var currentPage = 1;
|
||||
var accounts = [
|
||||
'PT. MegaCorp - 001-234-5678', 'TechDistrib Inc. - 002-987-6543',
|
||||
'CloudHost Ltd. - 003-456-7890', 'OfficePro Supply - 004-567-8901',
|
||||
'MegaNetwork Corp - 005-678-9012', 'Consulting Plus - 006-789-0123',
|
||||
'DataSys Solutions - 007-890-1234', 'GreenEnergy Corp - 008-901-2345',
|
||||
'SmartBuild Ltd. - 009-012-3456', 'MediCare Supplies - 010-123-4567',
|
||||
'AquaPure Systems - 011-234-5678', 'FinServe Global - 012-345-6789',
|
||||
'LogiTrack Inc. - 013-456-7890', 'BioHealth Labs - 014-567-8901',
|
||||
'EduPrime Academy - 015-678-9012'
|
||||
];
|
||||
var methods = ['Wire Transfer', 'Bank Transfer', 'Credit Card', 'ACH Transfer', 'Digital Wallet'];
|
||||
var statuses = [
|
||||
{ label: 'Success', chip: 'chip-green' },
|
||||
{ label: 'Pending', chip: 'chip-amber' },
|
||||
{ label: 'Processed', chip: 'chip-blue' },
|
||||
{ label: 'Failed', chip: 'chip-red' }
|
||||
];
|
||||
function rand(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
|
||||
function pick(arr) { return arr[rand(0, arr.length - 1)]; }
|
||||
var allData = [];
|
||||
for (var i = 1; i <= totalEntries; i++) {
|
||||
var amount = rand(500, 50000) + rand(0, 99) / 100;
|
||||
allData.push({
|
||||
id: 'TRX-2026-' + String(i).padStart(3, '0'),
|
||||
from: pick(accounts),
|
||||
to: pick(accounts),
|
||||
nominal: '$' + amount.toFixed(2),
|
||||
status: pick(statuses),
|
||||
method: pick(methods)
|
||||
});
|
||||
}
|
||||
var originalData = [
|
||||
{ id: 'TRX-2026-001', from: 'PT. MegaCorp - 001-234-5678', to: 'TechDistrib Inc. - 002-987-6543', nominal: '$24,500.00', status: { label: 'Success', chip: 'chip-green' }, method: 'Wire Transfer' },
|
||||
{ id: 'TRX-2026-002', from: 'CloudHost Ltd. - 003-456-7890', to: 'PT. MegaCorp - 001-234-5678', nominal: '$12,800.00', status: { label: 'Pending', chip: 'chip-amber' }, method: 'Bank Transfer' },
|
||||
{ id: 'TRX-2026-003', from: 'OfficePro Supply - 004-567-8901', to: 'PT. MegaCorp - 001-234-5678', nominal: '$6,200.00', status: { label: 'Processed', chip: 'chip-blue' }, method: 'Credit Card' },
|
||||
{ id: 'TRX-2026-004', from: 'PT. MegaCorp - 001-234-5678', to: 'MegaNetwork Corp - 005-678-9012', nominal: '$32,000.00', status: { label: 'Failed', chip: 'chip-red' }, method: 'Wire Transfer' },
|
||||
{ id: 'TRX-2026-005', from: 'Consulting Plus - 006-789-0123', to: 'PT. MegaCorp - 001-234-5678', nominal: '$18,000.00', status: { label: 'Success', chip: 'chip-green' }, method: 'Bank Transfer' },
|
||||
{ id: 'TRX-2026-006', from: 'DataSys Solutions - 007-890-1234', to: 'PT. MegaCorp - 001-234-5678', nominal: '$45,200.00', status: { label: 'Pending', chip: 'chip-amber' }, method: 'ACH Transfer' },
|
||||
{ id: 'TRX-2026-007', from: 'PT. MegaCorp - 001-234-5678', to: 'GreenEnergy Corp - 008-901-2345', nominal: '$28,900.00', status: { label: 'Processed', chip: 'chip-blue' }, method: 'Wire Transfer' },
|
||||
{ id: 'TRX-2026-008', from: 'SmartBuild Ltd. - 009-012-3456', to: 'PT. MegaCorp - 001-234-5678', nominal: '$8,750.00', status: { label: 'Failed', chip: 'chip-red' }, method: 'Credit Card' },
|
||||
{ id: 'TRX-2026-009', from: 'PT. MegaCorp - 001-234-5678', to: 'MediCare Supplies - 010-123-4567', nominal: '$19,300.00', status: { label: 'Success', chip: 'chip-green' }, method: 'Bank Transfer' },
|
||||
{ id: 'TRX-2026-010', from: 'AquaPure Systems - 011-234-5678', to: 'PT. MegaCorp - 001-234-5678', nominal: '$11,400.00', status: { label: 'Pending', chip: 'chip-amber' }, method: 'ACH Transfer' }
|
||||
];
|
||||
for (var idx = 0; idx < originalData.length; idx++) {
|
||||
allData[idx] = originalData[idx];
|
||||
}
|
||||
function renderPage(page) {
|
||||
var start = (page - 1) * perPage;
|
||||
var end = Math.min(start + perPage, totalEntries);
|
||||
var html = '';
|
||||
for (var i = start; i < end; i++) {
|
||||
var d = allData[i];
|
||||
html += '<tr class="bg-white hover:bg-gray-50/50 transition">' +
|
||||
'<td class="px-4 py-3 text-sm text-gray-700 font-mono font-medium">' + d.id + '</td>' +
|
||||
'<td class="px-4 py-3 text-sm text-gray-600">' + d.from + '</td>' +
|
||||
'<td class="px-4 py-3 text-sm text-gray-600">' + d.to + '</td>' +
|
||||
'<td class="px-4 py-3 text-sm text-gray-700 text-right font-mono">' + d.nominal + '</td>' +
|
||||
'<td class="px-4 py-3 text-center"><span class="chip ' + d.status.chip + '">' + d.status.label + '</span></td>' +
|
||||
'<td class="px-4 py-3 text-sm text-gray-600">' + d.method + '</td></tr>';
|
||||
}
|
||||
tbody.innerHTML = html;
|
||||
infoEl.innerHTML = 'Showing <b class="text-gray-600">' + (start + 1) + '</b> to <b class="text-gray-600">' + end + '</b> of <b class="text-gray-600">' + totalEntries + '</b> entries';
|
||||
var btnsHtml = '';
|
||||
var prevDisabled = page === 1;
|
||||
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border border-gray-200 bg-white text-gray-500 hover:bg-gray-50 transition' + (prevDisabled ? ' cursor-not-allowed opacity-50' : '') + '" data-page="prev"' + (prevDisabled ? ' disabled' : '') + '>Previous</button>';
|
||||
var maxVisible = 7;
|
||||
var startPage, endPage;
|
||||
if (totalPages <= maxVisible) {
|
||||
startPage = 1;
|
||||
endPage = totalPages;
|
||||
} else {
|
||||
var half = Math.floor(maxVisible / 2);
|
||||
if (page <= half + 1) {
|
||||
startPage = 1;
|
||||
endPage = maxVisible;
|
||||
} else if (page >= totalPages - half) {
|
||||
startPage = totalPages - maxVisible + 1;
|
||||
endPage = totalPages;
|
||||
} else {
|
||||
startPage = page - half;
|
||||
endPage = page + half;
|
||||
}
|
||||
}
|
||||
if (startPage > 1) {
|
||||
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border border-gray-200 bg-white text-gray-700 hover:bg-gray-50 transition" data-page="1">1</button>';
|
||||
if (startPage > 2) {
|
||||
btnsHtml += '<span class="px-1 text-gray-400">...</span>';
|
||||
}
|
||||
}
|
||||
for (var p = startPage; p <= endPage; p++) {
|
||||
var isActive = p === page;
|
||||
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border' +
|
||||
(isActive ? ' bg-blue-600 text-white border-blue-600' : ' border-gray-200 bg-white text-gray-700 hover:bg-gray-50 transition') +
|
||||
'" data-page="' + p + '">' + p + '</button>';
|
||||
}
|
||||
if (endPage < totalPages) {
|
||||
if (endPage < totalPages - 1) {
|
||||
btnsHtml += '<span class="px-1 text-gray-400">...</span>';
|
||||
}
|
||||
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border border-gray-200 bg-white text-gray-700 hover:bg-gray-50 transition" data-page="' + totalPages + '">' + totalPages + '</button>';
|
||||
}
|
||||
var nextDisabled = page === totalPages;
|
||||
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border border-gray-200 bg-white text-gray-500 hover:bg-gray-50 transition' + (nextDisabled ? ' cursor-not-allowed opacity-50' : '') + '" data-page="next"' + (nextDisabled ? ' disabled' : '') + '>Next</button>';
|
||||
pageBtnsEl.innerHTML = btnsHtml;
|
||||
var btns = pageBtnsEl.querySelectorAll('button:not([disabled])');
|
||||
btns.forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var target = this.getAttribute('data-page');
|
||||
var newPage = page;
|
||||
if (target === 'prev') newPage = page - 1;
|
||||
else if (target === 'next') newPage = page + 1;
|
||||
else newPage = parseInt(target);
|
||||
if (newPage >= 1 && newPage <= totalPages) {
|
||||
currentPage = newPage;
|
||||
renderPage(currentPage);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
renderPage(1);
|
||||
})();
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
function initScrollSpy() {
|
||||
const observer = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (e) {
|
||||
if (e.isIntersecting) {
|
||||
document.querySelectorAll('.nav-link').forEach(function (l) { l.classList.remove('active'); });
|
||||
var el = document.querySelector('.nav-link[href="#' + e.target.id + '"]');
|
||||
if (el) el.classList.add('active');
|
||||
}
|
||||
});
|
||||
}, { rootMargin: '-80px 0px -50% 0px' });
|
||||
document.querySelectorAll('section[id]').forEach(function (s) { observer.observe(s); });
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
(function () {
|
||||
const nav = document.getElementById('sidebar-nav');
|
||||
const wrap = document.getElementById('sidebar-nav-wrap');
|
||||
const track = document.getElementById('sb-track');
|
||||
const thumb = document.getElementById('sb-thumb');
|
||||
if (!nav || !track || !thumb || !wrap) return;
|
||||
let isDragging = false;
|
||||
function show() { track.style.opacity = '1'; }
|
||||
function hide() { if (!isDragging) track.style.opacity = '0'; }
|
||||
function update() {
|
||||
const sh = nav.scrollHeight, ch = nav.clientHeight;
|
||||
if (sh <= ch) { track.style.display = 'none'; return; }
|
||||
track.style.display = 'block'; track.style.opacity = '1';
|
||||
const st = nav.scrollTop, th = Math.max((ch / sh) * ch, 24);
|
||||
const maxTop = ch - th, ratio = sh > ch ? st / (sh - ch) : 0;
|
||||
thumb.style.height = th + 'px'; thumb.style.top = (ratio * maxTop) + 'px';
|
||||
}
|
||||
const observer = new MutationObserver(function () {
|
||||
update(); setTimeout(function () {
|
||||
update();
|
||||
if (nav.scrollHeight > nav.clientHeight) { track.style.display = 'block'; track.style.opacity = '1'; }
|
||||
}, 350);
|
||||
});
|
||||
observer.observe(nav, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
|
||||
nav.addEventListener('scroll', update); window.addEventListener('resize', update);
|
||||
wrap.addEventListener('mouseenter', function () { show(); update(); });
|
||||
wrap.addEventListener('mouseleave', hide);
|
||||
thumb.addEventListener('mousedown', function (e) {
|
||||
e.preventDefault(); isDragging = true; track.style.opacity = '1';
|
||||
document.body.style.cursor = 'pointer'; document.body.style.userSelect = 'none';
|
||||
function onMove(ev) {
|
||||
if (!isDragging) return;
|
||||
const rect = track.getBoundingClientRect();
|
||||
nav.scrollTop = ((ev.clientY - rect.top) / rect.height) * (nav.scrollHeight - nav.clientHeight);
|
||||
}
|
||||
function onUp() {
|
||||
isDragging = false; document.body.style.cursor = ''; document.body.style.userSelect = '';
|
||||
document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp);
|
||||
}
|
||||
document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp);
|
||||
});
|
||||
update(); setTimeout(update, 300);
|
||||
|
||||
nav.querySelectorAll('.submenu-group:not(.open) > .submenu-body').forEach(function (b) {
|
||||
b.style.maxHeight = '0px';
|
||||
});
|
||||
|
||||
function setBodyHeight(group) {
|
||||
const body = group.querySelector(':scope > .submenu-body');
|
||||
if (!body) return;
|
||||
if (group.classList.contains('open')) {
|
||||
body.style.maxHeight = body.scrollHeight + 'px';
|
||||
} else {
|
||||
body.style.maxHeight = '0px';
|
||||
}
|
||||
}
|
||||
|
||||
nav.addEventListener('transitionend', function (e) {
|
||||
if (!e.target.classList || !e.target.classList.contains('submenu-body')) return;
|
||||
if (e.propertyName !== 'max-height') return;
|
||||
if (e.target.style.maxHeight !== '0px') {
|
||||
e.target.style.maxHeight = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
nav.addEventListener('click', function (e) {
|
||||
const head = e.target.closest('.submenu-head');
|
||||
if (!head) return;
|
||||
const group = head.parentElement;
|
||||
if (group && group.classList.contains('submenu-group')) {
|
||||
group.classList.toggle('open');
|
||||
setBodyHeight(group);
|
||||
update();
|
||||
}
|
||||
});
|
||||
|
||||
function activateCurrent() {
|
||||
const currentPage = window.location.pathname.split('/').pop();
|
||||
if (!currentPage) return;
|
||||
const activeLink = nav.querySelector('a[href="' + currentPage + '"]');
|
||||
if (!activeLink) return;
|
||||
activeLink.classList.add('active');
|
||||
let node = activeLink.parentElement;
|
||||
while (node && node !== nav) {
|
||||
if (node.classList && node.classList.contains('submenu-group')) {
|
||||
node.classList.add('open');
|
||||
setBodyHeight(node);
|
||||
}
|
||||
node = node.parentElement;
|
||||
}
|
||||
update();
|
||||
requestAnimationFrame(function () { activeLink.scrollIntoView({ block: 'nearest' }); });
|
||||
}
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', activateCurrent);
|
||||
} else {
|
||||
activateCurrent();
|
||||
}
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+15
@@ -0,0 +1,15 @@
|
||||
function switchTab(group, tabId) {
|
||||
const tablist = document.getElementById('tablist' + group); if (!tablist) return;
|
||||
const tabs = tablist.querySelectorAll('[role="tab"]');
|
||||
tabs.forEach(t => { const isTarget = t.getAttribute('aria-controls') === 'panel' + group + '-' + tabId; t.setAttribute('aria-selected', isTarget ? 'true' : 'false'); t.classList.toggle('active', isTarget); });
|
||||
const panels = tablist.closest('.bg-white') ? tablist.closest('.bg-white').querySelectorAll('[role="tabpanel"]') : tablist.parentElement.parentElement.querySelectorAll('[role="tabpanel"]');
|
||||
panels.forEach(p => p.classList.toggle('hidden', p.id !== 'panel' + group + '-' + tabId));
|
||||
}
|
||||
function switchTabAnimated(group, tabId, btn) {
|
||||
const tablist = document.getElementById('tablist' + group); if (!tablist) return;
|
||||
const tabs = tablist.querySelectorAll('[role="tab"]');
|
||||
tabs.forEach(t => { t.setAttribute('aria-selected', 'false'); t.style.background = ''; t.style.border = ''; t.style.color = ''; });
|
||||
btn.setAttribute('aria-selected', 'true'); btn.style.background = 'white'; btn.style.border = '1px solid #e5e7eb'; btn.style.borderBottom = '1px solid white'; btn.style.color = '#1e293b';
|
||||
const panels = tablist.parentElement.parentElement.querySelectorAll('[role="tabpanel"]');
|
||||
panels.forEach(p => { const isTarget = p.id === 'panel' + group + '-' + tabId; if (isTarget) { p.classList.remove('hidden'); p.classList.add('tp-panel-enter'); const si = p.querySelectorAll('.stagger-item'); si.forEach((it, i) => { it.style.animation = 'none'; it.offsetHeight; it.style.animation = ''; }); } else { p.classList.add('hidden'); p.classList.remove('tp-panel-enter'); } });
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
class CRMTopbar1 extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<header class="sticky top-0 z-30 h-16 px-4 md:px-6 flex items-center justify-between" style="background:#f1f5f9;">
|
||||
<div class="flex items-center gap-4">
|
||||
<button x-on:click="side = !side" class="p-2 rounded-lg hover:bg-gray-100 transition"><svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg></button>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="relative p-2 rounded-lg hover:bg-gray-100 transition">
|
||||
<svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>
|
||||
<span class="absolute -top-0.5 -right-0.5 w-4 h-4 rounded-full bg-blue-500 text-white text-[10px] flex items-center justify-center font-bold">3</span>
|
||||
</button>
|
||||
<div class="flex items-center gap-2 pl-3 ml-1 border-l border-gray-200">
|
||||
<div class="w-8 h-8 rounded-full flex items-center justify-center text-white font-bold text-xs" style="background: #3b82f6;">JD</div>
|
||||
<div class="hidden sm:block text-sm leading-tight"><p class="font-semibold text-gray-800">John Doe</p><p class="text-gray-400 text-xs">Sales Admin</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('crm-topbar-1', CRMTopbar1);
|
||||
@@ -0,0 +1,22 @@
|
||||
class CRMTopbar2 extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<header class="sticky top-0 z-30 bg-white border-b border-gray-200 h-16 px-4 md:px-6 flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<button x-on:click="side = !side" class="p-2 rounded-lg hover:bg-gray-100 transition"><svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg></button>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="relative p-2 rounded-lg hover:bg-gray-100 transition">
|
||||
<svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>
|
||||
<span class="absolute -top-0.5 -right-0.5 w-4 h-4 rounded-full bg-blue-500 text-white text-[10px] flex items-center justify-center font-bold">3</span>
|
||||
</button>
|
||||
<div class="flex items-center gap-2 pl-3 ml-1 border-l border-gray-200">
|
||||
<div class="w-8 h-8 rounded-full flex items-center justify-center text-white font-bold text-xs" style="background: #3b82f6;">CF</div>
|
||||
<div class="hidden sm:block text-sm leading-tight"><p class="font-semibold text-gray-800">John Doe</p><p class="text-gray-400 text-xs">Sales Admin</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('crm-topbar-2', CRMTopbar2);
|
||||
@@ -0,0 +1,22 @@
|
||||
class CRMTopbar3 extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<header class="sticky top-0 z-30 bg-white border-b border-gray-200 h-16 px-4 md:px-6 flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<button x-on:click="side = !side" class="p-2 rounded-lg hover:bg-gray-100 transition"><svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg></button>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="relative p-2 rounded-lg hover:bg-gray-100 transition">
|
||||
<svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>
|
||||
<span class="absolute -top-0.5 -right-0.5 w-4 h-4 rounded-full bg-indigo-500 text-white text-[10px] flex items-center justify-center font-bold">3</span>
|
||||
</button>
|
||||
<div class="flex items-center gap-2 pl-3 ml-1 border-l border-gray-200">
|
||||
<div class="w-8 h-8 rounded-full flex items-center justify-center text-white font-bold text-xs" style="background: linear-gradient(135deg, #6366f1, #4f46e5);">JD</div>
|
||||
<div class="hidden sm:block text-sm leading-tight"><p class="font-semibold text-gray-800">John Doe</p><p class="text-gray-400 text-xs">Sales Admin</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('crm-topbar-3', CRMTopbar3);
|
||||
@@ -0,0 +1,22 @@
|
||||
class CRMTopbar4 extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<header class="sticky top-0 z-30 h-16 px-4 md:px-6 flex items-center justify-between" style="background:#f1f5f9;">
|
||||
<div class="flex items-center gap-4">
|
||||
<button x-on:click="side = !side" class="p-2 rounded-lg hover:bg-gray-100 transition"><svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg></button>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="relative p-2 rounded-lg hover:bg-gray-100 transition">
|
||||
<svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>
|
||||
<span class="absolute -top-0.5 -right-0.5 w-4 h-4 rounded-full bg-indigo-500 text-white text-[10px] flex items-center justify-center font-bold">3</span>
|
||||
</button>
|
||||
<div class="flex items-center gap-2 pl-3 ml-1">
|
||||
<div class="w-8 h-8 rounded-full flex items-center justify-center text-white font-bold text-xs" style="background: linear-gradient(135deg, #6366f1, #4f46e5);">JD</div>
|
||||
<div class="hidden sm:block text-sm leading-tight"><p class="font-semibold text-gray-800">John Doe</p><p class="text-gray-400 text-xs">Sales Admin</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('crm-topbar-4', CRMTopbar4);
|
||||
@@ -0,0 +1,22 @@
|
||||
class CRMTopbar5 extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<header class="sticky top-0 z-30 bg-white border-b border-gray-200 h-16 px-4 md:px-6 flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<button x-on:click="side = !side" class="p-2 rounded-lg hover:bg-gray-100 transition"><svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg></button>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="relative p-2 rounded-lg hover:bg-gray-100 transition">
|
||||
<svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>
|
||||
<span class="absolute -top-0.5 -right-0.5 w-4 h-4 rounded-full bg-blue-500 text-white text-[10px] flex items-center justify-center font-bold">3</span>
|
||||
</button>
|
||||
<div class="flex items-center gap-2 pl-3 ml-1 border-l border-gray-200">
|
||||
<div class="w-8 h-8 rounded-full flex items-center justify-center text-white font-bold text-xs" style="background: #3b82f6;">JD</div>
|
||||
<div class="hidden sm:block text-sm leading-tight"><p class="font-semibold text-gray-800">John Doe</p><p class="text-gray-400 text-xs">Sales Admin</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('crm-topbar-5', CRMTopbar5);
|
||||
Reference in New Issue
Block a user