vanillajs-excelike-table
Version:
A user-friendly pure JavaScript table library with Excel-like features, preset configurations, and intuitive column helpers. Vanilla JS implementation - no frameworks required!
353 lines (323 loc) • 11 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VanillaJS ExceLike Table - Advanced Example</title>
<link rel="stylesheet" href="../src/ExceLikeTable.css">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1000px;
margin: 0 auto;
background: white;
padding: 24px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
h1 {
color: #1890ff;
margin-bottom: 20px;
text-align: center;
}
.table-container {
height: 500px;
border: 1px solid #d9d9d9;
border-radius: 4px;
}
.progress-bar {
width: 100%;
height: 16px;
background: #f0f0f0;
border-radius: 8px;
overflow: hidden;
position: relative;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #52c41a 0%, #faad14 50%, #ff4d4f 100%);
transition: width 0.3s ease;
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 12px;
font-weight: 500;
color: #333;
}
.status-badge {
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
display: inline-block;
}
.status-active { background: #f6ffed; color: #52c41a; border: 1px solid #b7eb8f; }
.status-inactive { background: #f5f5f5; color: #8c8c8c; border: 1px solid #d9d9d9; }
.status-pending { background: #fffbe6; color: #faad14; border: 1px solid #ffe58f; }
.status-suspended { background: #fff2f0; color: #ff4d4f; border: 1px solid #ffb3b3; }
.demo-controls {
margin-bottom: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.demo-btn {
padding: 6px 12px;
border: 1px solid #d9d9d9;
background: white;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
}
.demo-btn:hover {
border-color: #1890ff;
color: #1890ff;
}
.feature-info {
background: #e6f7ff;
padding: 12px;
border-radius: 4px;
margin-bottom: 16px;
border: 1px solid #91d5ff;
}
.feature-info h3 {
margin: 0 0 8px 0;
color: #1890ff;
}
.feature-info ul {
margin: 0;
padding-left: 20px;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<h1>⚡ VanillaJS ExceLike Table - Advanced Features</h1>
<div class="feature-info">
<h3>Advanced Features Demonstrated:</h3>
<ul>
<li><strong>Custom Renderers:</strong> Progress bars, status badges, formatted numbers</li>
<li><strong>Range Filters:</strong> Numeric columns with slider controls</li>
<li><strong>Date Hierarchy:</strong> Expandable year/month filtering</li>
<li><strong>Custom Sorters:</strong> Complex sorting logic for formatted data</li>
<li><strong>Dynamic Updates:</strong> Real-time data modification</li>
</ul>
</div>
<div class="demo-controls">
<button class="demo-btn" onclick="updateProgress()">Update Progress</button>
<button class="demo-btn" onclick="changeStatuses()">Change Statuses</button>
<button class="demo-btn" onclick="addNewEmployee()">Add Employee</button>
<button class="demo-btn" onclick="refreshData()">Refresh Data</button>
</div>
<div class="table-container" id="table-container"></div>
</div>
<script src="../src/ExceLikeTable.js"></script>
<script>
let table;
let employeeData = [];
// Generate advanced sample data
function generateAdvancedData() {
const names = ['John Smith', 'Jane Doe', 'Bob Johnson', 'Alice Brown', 'Charlie Davis', 'Diana Wilson', 'Eve Miller', 'Frank Garcia', 'Grace Martinez', 'Henry Anderson', 'Ivy Chen', 'Jack Wilson', 'Kate Roberts', 'Liam Taylor', 'Mia Johnson'];
const departments = ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance', 'Operations', 'Design', 'Product', 'Support', 'Research'];
const locations = ['New York', 'San Francisco', 'London', 'Tokyo', 'Sydney', 'Toronto', 'Berlin', 'Singapore', 'Mumbai', 'Dubai'];
const statuses = ['Active', 'Inactive', 'Pending', 'Suspended'];
const skills = ['JavaScript', 'React', 'Node.js', 'Python', 'Java', 'C++', 'SQL', 'MongoDB', 'AWS', 'Docker'];
const data = [];
for (let i = 1; i <= 30; i++) {
const startDate = new Date(2020, 0, 1);
const endDate = new Date(2024, 11, 31);
const randomDate = new Date(startDate.getTime() + Math.random() * (endDate.getTime() - startDate.getTime()));
data.push({
id: i,
name: names[Math.floor(Math.random() * names.length)],
department: departments[Math.floor(Math.random() * departments.length)],
location: locations[Math.floor(Math.random() * locations.length)],
salary: Math.floor(Math.random() * 150000) + 50000,
experience: Math.floor(Math.random() * 20) + 1,
joinDate: randomDate.toISOString().split('T')[0],
status: statuses[Math.floor(Math.random() * statuses.length)],
performance: Math.floor(Math.random() * 100) + 1,
projectsCompleted: Math.floor(Math.random() * 50) + 1,
skills: skills.slice(0, Math.floor(Math.random() * 5) + 2).join(', '),
rating: (Math.random() * 4 + 1).toFixed(1)
});
}
return data;
}
// Advanced column definitions with custom renderers
const advancedColumns = [
{
key: 'id',
title: 'ID',
dataIndex: 'id',
width: 80,
sortable: true,
filterable: true
},
{
key: 'name',
title: 'Employee Name',
dataIndex: 'name',
width: 150,
sortable: true,
filterable: true,
render: (value, record) => {
return `<strong>${value}</strong><br><small style="color: #999;">${record.department}</small>`;
}
},
{
key: 'location',
title: 'Location',
dataIndex: 'location',
width: 120,
sortable: true,
filterable: true
},
{
key: 'salary',
title: 'Salary',
dataIndex: 'salary',
width: 120,
sortable: true,
filterable: true,
render: (value) => `$${value.toLocaleString()}`
},
{
key: 'experience',
title: 'Experience',
dataIndex: 'experience',
width: 100,
sortable: true,
filterable: true,
render: (value) => `${value} yrs`
},
{
key: 'joinDate',
title: 'Join Date',
dataIndex: 'joinDate',
width: 130,
sortable: true,
filterable: true,
filterType: 'date-hierarchy'
},
{
key: 'status',
title: 'Status',
dataIndex: 'status',
width: 100,
sortable: true,
filterable: true,
render: (value) => {
const className = `status-${value.toLowerCase()}`;
return `<span class="status-badge ${className}">${value}</span>`;
}
},
{
key: 'performance',
title: 'Performance',
dataIndex: 'performance',
width: 120,
sortable: true,
filterable: true,
render: (value) => {
return `
<div class="progress-bar">
<div class="progress-fill" style="width: ${value}%"></div>
<div class="progress-text">${value}%</div>
</div>
`;
}
},
{
key: 'projectsCompleted',
title: 'Projects',
dataIndex: 'projectsCompleted',
width: 100,
sortable: true,
filterable: true,
render: (value) => `<span style="color: #1890ff; font-weight: 500;">${value}</span>`
},
{
key: 'rating',
title: 'Rating',
dataIndex: 'rating',
width: 100,
sortable: true,
filterable: true,
render: (value) => {
const stars = '★'.repeat(Math.floor(value)) + '☆'.repeat(5 - Math.floor(value));
return `<span style="color: #faad14;">${stars}</span><br><small>${value}/5</small>`;
}
}
];
// Demo control functions
function updateProgress() {
employeeData = employeeData.map(emp => ({
...emp,
performance: Math.floor(Math.random() * 100) + 1
}));
table.setData(employeeData);
}
function changeStatuses() {
const statuses = ['Active', 'Inactive', 'Pending', 'Suspended'];
employeeData = employeeData.map(emp => ({
...emp,
status: statuses[Math.floor(Math.random() * statuses.length)]
}));
table.setData(employeeData);
}
function addNewEmployee() {
const newId = Math.max(...employeeData.map(e => e.id)) + 1;
const names = ['Alex Johnson', 'Sam Wilson', 'Taylor Brown', 'Jordan Davis', 'Casey Miller'];
const departments = ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance'];
const newEmployee = {
id: newId,
name: names[Math.floor(Math.random() * names.length)],
department: departments[Math.floor(Math.random() * departments.length)],
location: 'New York',
salary: Math.floor(Math.random() * 100000) + 60000,
experience: Math.floor(Math.random() * 10) + 1,
joinDate: new Date().toISOString().split('T')[0],
status: 'Active',
performance: Math.floor(Math.random() * 100) + 1,
projectsCompleted: Math.floor(Math.random() * 20) + 1,
skills: 'JavaScript, React, Node.js',
rating: (Math.random() * 4 + 1).toFixed(1)
};
employeeData.push(newEmployee);
table.setData(employeeData);
}
function refreshData() {
employeeData = generateAdvancedData();
table.setData(employeeData);
}
// Initialize advanced table
document.addEventListener('DOMContentLoaded', () => {
employeeData = generateAdvancedData();
table = new ExceLikeTable('#table-container', {
data: employeeData,
columns: advancedColumns,
rowKey: 'id',
pagination: {
pageSize: 8,
showSizeChanger: true,
showTotal: (total, range) => `Showing ${range[0]}-${range[1]} of ${total} employees`
},
bordered: true,
size: 'middle',
loading: false
});
});
</script>
</body>
</html>