infinite-agents-public/src/ui_hybrid_9.html

1092 lines
38 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Industrial Design Data Explorer</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@400;500;600;700&display=swap');
:root {
--steel-primary: #2c3e50;
--steel-secondary: #34495e;
--aluminum: #95a5a6;
--chrome: #bdc3c7;
--gunmetal: #1e2329;
--copper: #d35400;
--brass: #f39c12;
--industrial-blue: #3498db;
--warning-orange: #e67e22;
--success-green: #27ae60;
--rivet-shadow: #1a1a1a;
--text-primary: #ecf0f1;
--text-secondary: #95a5a6;
--surface-bg: linear-gradient(135deg, #2c3e50 0%, #1e2329 100%);
--metal-gradient: linear-gradient(90deg, #34495e 0%, #2c3e50 50%, #34495e 100%);
--brushed-steel:
linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%),
linear-gradient(0deg, #2c3e50 0%, #34495e 30%, #2c3e50 60%, #34495e 100%);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
background: var(--surface-bg);
color: var(--text-primary);
min-height: 100vh;
overflow-x: auto;
}
main {
padding: 2rem;
max-width: 1400px;
margin: 0 auto;
}
h1 {
font-family: 'JetBrains Mono', monospace;
font-size: 2.5rem;
font-weight: 700;
color: var(--chrome);
text-align: center;
margin-bottom: 3rem;
text-transform: uppercase;
letter-spacing: 4px;
text-shadow:
0 0 10px rgba(189, 195, 199, 0.3),
2px 2px 4px var(--rivet-shadow);
position: relative;
}
h1::before {
content: '';
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
width: 200px;
height: 4px;
background: var(--metal-gradient);
border-radius: 2px;
box-shadow:
0 0 10px rgba(52, 152, 219, 0.3),
inset 0 1px 2px rgba(255,255,255,0.1);
}
.hybrid-component {
background: var(--brushed-steel);
border-radius: 12px;
box-shadow:
0 20px 40px rgba(0,0,0,0.3),
inset 0 1px 2px rgba(255,255,255,0.1),
0 0 0 1px var(--aluminum);
overflow: hidden;
position: relative;
}
.hybrid-component::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg,
var(--copper) 0%,
var(--brass) 25%,
var(--industrial-blue) 50%,
var(--brass) 75%,
var(--copper) 100%);
animation: energyFlow 4s linear infinite;
}
@keyframes energyFlow {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
.control-panel {
background: var(--metal-gradient);
padding: 2rem;
border-bottom: 2px solid var(--aluminum);
display: grid;
grid-template-columns: 1fr auto auto;
gap: 2rem;
align-items: end;
position: relative;
}
.control-panel::after {
content: '';
position: absolute;
top: 1rem;
right: 1rem;
width: 12px;
height: 12px;
background: var(--success-green);
border-radius: 50%;
box-shadow:
0 0 10px var(--success-green),
inset 0 1px 2px rgba(255,255,255,0.3);
animation: statusPulse 2s ease-in-out infinite;
}
@keyframes statusPulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.6; transform: scale(0.9); }
}
.search-unit {
position: relative;
}
.search-unit label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
font-weight: 500;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 1px;
display: block;
margin-bottom: 0.5rem;
}
.search-input {
width: 100%;
background: var(--gunmetal);
border: 2px solid var(--aluminum);
border-radius: 6px;
padding: 0.75rem 1rem 0.75rem 3rem;
color: var(--text-primary);
font-family: 'JetBrains Mono', monospace;
font-size: 0.9rem;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
}
.search-input:focus {
outline: none;
border-color: var(--industrial-blue);
box-shadow:
inset 0 2px 4px rgba(0,0,0,0.3),
0 0 0 3px rgba(52, 152, 219, 0.2);
}
.search-icon {
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
color: var(--aluminum);
font-size: 1rem;
pointer-events: none;
}
.filter-controls {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.filter-group {
position: relative;
}
.filter-group label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
font-weight: 500;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 1px;
display: block;
margin-bottom: 0.5rem;
}
.filter-select {
background: var(--gunmetal);
border: 2px solid var(--aluminum);
border-radius: 6px;
padding: 0.75rem 2.5rem 0.75rem 1rem;
color: var(--text-primary);
font-family: 'JetBrains Mono', monospace;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
appearance: none;
}
.filter-select:focus {
outline: none;
border-color: var(--industrial-blue);
box-shadow:
inset 0 2px 4px rgba(0,0,0,0.3),
0 0 0 3px rgba(52, 152, 219, 0.2);
}
.export-controls {
display: flex;
gap: 1rem;
}
.export-btn {
background: var(--metal-gradient);
border: 2px solid var(--copper);
border-radius: 6px;
padding: 0.75rem 1.5rem;
color: var(--text-primary);
font-family: 'JetBrains Mono', monospace;
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
text-transform: uppercase;
letter-spacing: 1px;
position: relative;
overflow: hidden;
}
.export-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
transition: left 0.5s;
}
.export-btn:hover {
border-color: var(--brass);
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0,0,0,0.3);
}
.export-btn:hover::before {
left: 100%;
}
.export-btn:active {
transform: translateY(0);
}
.data-table-container {
position: relative;
overflow: hidden;
}
.data-table {
width: 100%;
background: var(--gunmetal);
border-collapse: separate;
border-spacing: 0;
}
.data-table thead {
background: var(--metal-gradient);
position: sticky;
top: 0;
z-index: 10;
}
.data-table th {
padding: 1.25rem 1rem;
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
font-weight: 600;
color: var(--chrome);
text-transform: uppercase;
letter-spacing: 1px;
text-align: left;
border-bottom: 2px solid var(--aluminum);
position: relative;
cursor: pointer;
transition: all 0.3s ease;
}
.data-table th:hover {
background: rgba(52, 152, 219, 0.1);
}
.data-table th.sortable::after {
content: '⇅';
position: absolute;
right: 1rem;
top: 50%;
transform: translateY(-50%);
font-size: 0.8rem;
color: var(--aluminum);
transition: all 0.3s ease;
}
.data-table th.sort-asc::after {
content: '↑';
color: var(--industrial-blue);
}
.data-table th.sort-desc::after {
content: '↓';
color: var(--industrial-blue);
}
.data-table td {
padding: 1rem;
border-bottom: 1px solid var(--steel-secondary);
font-family: 'Inter', sans-serif;
font-size: 0.9rem;
color: var(--text-primary);
transition: all 0.3s ease;
}
.data-table tr:hover td {
background: rgba(52, 152, 219, 0.1);
}
.data-table tr.selected td {
background: rgba(52, 152, 219, 0.2);
border-color: var(--industrial-blue);
}
.checkbox-cell {
width: 60px;
text-align: center;
}
.mechanical-checkbox {
position: relative;
width: 20px;
height: 20px;
cursor: pointer;
}
.mechanical-checkbox input {
opacity: 0;
position: absolute;
width: 100%;
height: 100%;
cursor: pointer;
}
.checkbox-frame {
width: 20px;
height: 20px;
background: var(--gunmetal);
border: 2px solid var(--aluminum);
border-radius: 3px;
position: relative;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
}
.checkbox-frame::before {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0) rotate(-180deg);
color: var(--industrial-blue);
font-size: 12px;
font-weight: bold;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.mechanical-checkbox input:checked + .checkbox-frame {
border-color: var(--industrial-blue);
background: rgba(52, 152, 219, 0.1);
}
.mechanical-checkbox input:checked + .checkbox-frame::before {
transform: translate(-50%, -50%) scale(1) rotate(0deg);
}
.status-indicator {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 0.5rem;
}
.status-active { background: var(--success-green); box-shadow: 0 0 8px var(--success-green); }
.status-pending { background: var(--warning-orange); box-shadow: 0 0 8px var(--warning-orange); }
.status-inactive { background: var(--aluminum); }
.pagination-controls {
background: var(--metal-gradient);
padding: 1.5rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 2px solid var(--aluminum);
}
.pagination-info {
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 1px;
}
.pagination-nav {
display: flex;
gap: 0.5rem;
}
.page-btn {
background: var(--gunmetal);
border: 2px solid var(--aluminum);
border-radius: 6px;
padding: 0.5rem 1rem;
color: var(--text-primary);
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.page-btn:hover {
border-color: var(--industrial-blue);
transform: translateY(-2px);
}
.page-btn:active {
transform: translateY(0);
}
.page-btn.active {
background: var(--industrial-blue);
border-color: var(--industrial-blue);
color: white;
}
.page-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
.selected-count {
background: var(--copper);
color: white;
padding: 0.5rem 1rem;
border-radius: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 1px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
opacity: 0;
transform: translateY(-10px);
transition: all 0.3s ease;
}
.selected-count.visible {
opacity: 1;
transform: translateY(0);
}
.rivets {
position: absolute;
width: 8px;
height: 8px;
background: radial-gradient(circle, var(--aluminum) 30%, var(--steel-secondary) 70%);
border-radius: 50%;
box-shadow:
inset 0 1px 2px rgba(255,255,255,0.2),
0 1px 2px var(--rivet-shadow);
}
.rivet-tl { top: 1rem; left: 1rem; }
.rivet-tr { top: 1rem; right: 1rem; }
.rivet-bl { bottom: 1rem; left: 1rem; }
.rivet-br { bottom: 1rem; right: 1rem; }
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(30, 35, 41, 0.9);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
z-index: 100;
}
.loading-overlay.active {
opacity: 1;
visibility: visible;
}
.industrial-spinner {
width: 60px;
height: 60px;
position: relative;
}
.gear {
width: 100%;
height: 100%;
border: 4px solid var(--aluminum);
border-radius: 50%;
position: relative;
animation: rotate 2s linear infinite;
}
.gear::before {
content: '';
position: absolute;
top: -4px;
left: 50%;
transform: translateX(-50%);
width: 8px;
height: 8px;
background: var(--copper);
border-radius: 50%;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@media (max-width: 768px) {
.control-panel {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.filter-controls {
justify-content: center;
}
.export-controls {
justify-content: center;
}
.pagination-controls {
flex-direction: column;
gap: 1rem;
}
.data-table {
font-size: 0.8rem;
}
.data-table th,
.data-table td {
padding: 0.75rem 0.5rem;
}
}
</style>
</head>
<body>
<main>
<h1>Data Explorer - Industrial Design Theme</h1>
<div class="hybrid-component">
<div class="rivets rivet-tl"></div>
<div class="rivets rivet-tr"></div>
<div class="rivets rivet-bl"></div>
<div class="rivets rivet-br"></div>
<div class="control-panel">
<div class="search-unit">
<label for="data-search">System Search</label>
<div style="position: relative;">
<span class="search-icon">🔍</span>
<input type="text" id="data-search" class="search-input" placeholder="Enter search parameters...">
</div>
</div>
<div class="filter-controls">
<div class="filter-group">
<label for="status-filter">Status Filter</label>
<select id="status-filter" class="filter-select">
<option value="">All Status</option>
<option value="active">Active</option>
<option value="pending">Pending</option>
<option value="inactive">Inactive</option>
</select>
</div>
<div class="filter-group">
<label for="department-filter">Department</label>
<select id="department-filter" class="filter-select">
<option value="">All Departments</option>
<option value="engineering">Engineering</option>
<option value="manufacturing">Manufacturing</option>
<option value="quality">Quality Control</option>
<option value="operations">Operations</option>
</select>
</div>
</div>
<div class="export-controls">
<button class="export-btn" data-format="csv">Export CSV</button>
<button class="export-btn" data-format="json">Export JSON</button>
</div>
<div class="selected-count" id="selected-count">
<span id="count-text">0 Selected</span>
</div>
</div>
<div class="data-table-container">
<table class="data-table" id="data-table">
<thead>
<tr>
<th class="checkbox-cell">
<label class="mechanical-checkbox">
<input type="checkbox" id="select-all">
<div class="checkbox-frame"></div>
</label>
</th>
<th class="sortable" data-column="id">ID</th>
<th class="sortable" data-column="name">Component Name</th>
<th class="sortable" data-column="department">Department</th>
<th class="sortable" data-column="status">Status</th>
<th class="sortable" data-column="created">Created</th>
<th class="sortable" data-column="updated">Last Updated</th>
</tr>
</thead>
<tbody id="table-body">
<!-- Data will be populated by JavaScript -->
</tbody>
</table>
</div>
<div class="pagination-controls">
<div class="pagination-info" id="pagination-info">
Showing 1-10 of 150 components
</div>
<div class="pagination-nav">
<button class="page-btn" id="prev-btn">← Previous</button>
<button class="page-btn active" data-page="1">1</button>
<button class="page-btn" data-page="2">2</button>
<button class="page-btn" data-page="3">3</button>
<button class="page-btn" data-page="4">4</button>
<button class="page-btn" data-page="5">5</button>
<button class="page-btn" id="next-btn">Next →</button>
</div>
</div>
<div class="loading-overlay" id="loading-overlay">
<div class="industrial-spinner">
<div class="gear"></div>
</div>
</div>
</div>
</main>
<script>
// Industrial Data Explorer System
class IndustrialDataExplorer {
constructor() {
this.data = this.generateSampleData();
this.filteredData = [...this.data];
this.currentPage = 1;
this.itemsPerPage = 10;
this.sortColumn = null;
this.sortDirection = 'asc';
this.selectedItems = new Set();
this.initializeEventListeners();
this.renderTable();
this.updatePaginationInfo();
}
generateSampleData() {
const components = [
'Hydraulic Actuator', 'Precision Bearing', 'Control Valve', 'Pressure Sensor',
'Motor Assembly', 'Gear Reducer', 'Flow Meter', 'Temperature Probe',
'Safety Switch', 'Power Supply', 'Drive Controller', 'Coupling Unit',
'Pneumatic Cylinder', 'Encoder System', 'Brake Assembly', 'Filter Unit'
];
const departments = ['engineering', 'manufacturing', 'quality', 'operations'];
const statuses = ['active', 'pending', 'inactive'];
return Array.from({ length: 150 }, (_, i) => ({
id: String(i + 1).padStart(4, '0'),
name: components[Math.floor(Math.random() * components.length)] + ` ${String.fromCharCode(65 + Math.floor(Math.random() * 26))}${Math.floor(Math.random() * 999) + 1}`,
department: departments[Math.floor(Math.random() * departments.length)],
status: statuses[Math.floor(Math.random() * statuses.length)],
created: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toLocaleDateString(),
updated: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000).toLocaleDateString()
}));
}
initializeEventListeners() {
// Search functionality
document.getElementById('data-search').addEventListener('input', (e) => {
this.handleSearch(e.target.value);
});
// Filter functionality
document.getElementById('status-filter').addEventListener('change', (e) => {
this.handleFilter();
});
document.getElementById('department-filter').addEventListener('change', (e) => {
this.handleFilter();
});
// Sort functionality
document.querySelectorAll('.sortable').forEach(header => {
header.addEventListener('click', () => {
this.handleSort(header.dataset.column);
});
});
// Select all functionality
document.getElementById('select-all').addEventListener('change', (e) => {
this.handleSelectAll(e.target.checked);
});
// Export functionality
document.querySelectorAll('.export-btn').forEach(btn => {
btn.addEventListener('click', () => {
this.handleExport(btn.dataset.format);
});
});
// Pagination
document.getElementById('prev-btn').addEventListener('click', () => {
this.changePage(this.currentPage - 1);
});
document.getElementById('next-btn').addEventListener('click', () => {
this.changePage(this.currentPage + 1);
});
document.querySelectorAll('.page-btn[data-page]').forEach(btn => {
btn.addEventListener('click', () => {
this.changePage(parseInt(btn.dataset.page));
});
});
}
handleSearch(query) {
this.showLoading();
setTimeout(() => {
const searchTerm = query.toLowerCase().trim();
if (searchTerm === '') {
this.filteredData = [...this.data];
} else {
this.filteredData = this.data.filter(item =>
item.name.toLowerCase().includes(searchTerm) ||
item.id.includes(searchTerm) ||
item.department.toLowerCase().includes(searchTerm)
);
}
this.applyFilters();
this.currentPage = 1;
this.renderTable();
this.updatePaginationInfo();
this.hideLoading();
}, 300);
}
handleFilter() {
this.showLoading();
setTimeout(() => {
this.applyFilters();
this.currentPage = 1;
this.renderTable();
this.updatePaginationInfo();
this.hideLoading();
}, 200);
}
applyFilters() {
const statusFilter = document.getElementById('status-filter').value;
const departmentFilter = document.getElementById('department-filter').value;
const searchTerm = document.getElementById('data-search').value.toLowerCase().trim();
let filtered = [...this.data];
// Apply search filter
if (searchTerm) {
filtered = filtered.filter(item =>
item.name.toLowerCase().includes(searchTerm) ||
item.id.includes(searchTerm) ||
item.department.toLowerCase().includes(searchTerm)
);
}
// Apply status filter
if (statusFilter) {
filtered = filtered.filter(item => item.status === statusFilter);
}
// Apply department filter
if (departmentFilter) {
filtered = filtered.filter(item => item.department === departmentFilter);
}
this.filteredData = filtered;
}
handleSort(column) {
if (this.sortColumn === column) {
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
} else {
this.sortColumn = column;
this.sortDirection = 'asc';
}
this.filteredData.sort((a, b) => {
let aVal = a[column];
let bVal = b[column];
if (column === 'created' || column === 'updated') {
aVal = new Date(aVal);
bVal = new Date(bVal);
}
if (aVal < bVal) return this.sortDirection === 'asc' ? -1 : 1;
if (aVal > bVal) return this.sortDirection === 'asc' ? 1 : -1;
return 0;
});
this.updateSortHeaders();
this.renderTable();
}
updateSortHeaders() {
document.querySelectorAll('.sortable').forEach(header => {
header.classList.remove('sort-asc', 'sort-desc');
if (header.dataset.column === this.sortColumn) {
header.classList.add(`sort-${this.sortDirection}`);
}
});
}
handleSelectAll(checked) {
const currentPageData = this.getCurrentPageData();
if (checked) {
currentPageData.forEach(item => this.selectedItems.add(item.id));
} else {
currentPageData.forEach(item => this.selectedItems.delete(item.id));
}
this.renderTable();
this.updateSelectedCount();
}
handleRowSelect(itemId, checked) {
if (checked) {
this.selectedItems.add(itemId);
} else {
this.selectedItems.delete(itemId);
}
this.updateSelectedCount();
this.updateSelectAllState();
}
updateSelectAllState() {
const currentPageData = this.getCurrentPageData();
const allSelected = currentPageData.every(item => this.selectedItems.has(item.id));
const someSelected = currentPageData.some(item => this.selectedItems.has(item.id));
const selectAllCheckbox = document.getElementById('select-all');
selectAllCheckbox.checked = allSelected;
selectAllCheckbox.indeterminate = someSelected && !allSelected;
}
updateSelectedCount() {
const count = this.selectedItems.size;
const countElement = document.getElementById('selected-count');
const countText = document.getElementById('count-text');
countText.textContent = `${count} Selected`;
if (count > 0) {
countElement.classList.add('visible');
} else {
countElement.classList.remove('visible');
}
}
handleExport(format) {
this.showLoading();
setTimeout(() => {
const dataToExport = this.selectedItems.size > 0
? this.data.filter(item => this.selectedItems.has(item.id))
: this.filteredData;
let exportData;
let mimeType;
let filename;
if (format === 'csv') {
exportData = this.convertToCSV(dataToExport);
mimeType = 'text/csv';
filename = 'industrial_data_export.csv';
} else if (format === 'json') {
exportData = JSON.stringify(dataToExport, null, 2);
mimeType = 'application/json';
filename = 'industrial_data_export.json';
}
this.downloadFile(exportData, mimeType, filename);
this.hideLoading();
}, 500);
}
convertToCSV(data) {
if (data.length === 0) return '';
const headers = Object.keys(data[0]);
const csvHeaders = headers.join(',');
const csvRows = data.map(item =>
headers.map(header => `"${item[header]}"`).join(',')
);
return [csvHeaders, ...csvRows].join('\n');
}
downloadFile(content, mimeType, filename) {
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
getCurrentPageData() {
const startIndex = (this.currentPage - 1) * this.itemsPerPage;
const endIndex = startIndex + this.itemsPerPage;
return this.filteredData.slice(startIndex, endIndex);
}
renderTable() {
const tbody = document.getElementById('table-body');
const currentPageData = this.getCurrentPageData();
tbody.innerHTML = currentPageData.map(item => `
<tr class="${this.selectedItems.has(item.id) ? 'selected' : ''}">
<td class="checkbox-cell">
<label class="mechanical-checkbox">
<input type="checkbox" ${this.selectedItems.has(item.id) ? 'checked' : ''}
onchange="dataExplorer.handleRowSelect('${item.id}', this.checked)">
<div class="checkbox-frame"></div>
</label>
</td>
<td>${item.id}</td>
<td>${item.name}</td>
<td style="text-transform: capitalize;">${item.department}</td>
<td>
<span class="status-indicator status-${item.status}"></span>
<span style="text-transform: capitalize;">${item.status}</span>
</td>
<td>${item.created}</td>
<td>${item.updated}</td>
</tr>
`).join('');
this.updateSelectAllState();
}
changePage(page) {
const maxPage = Math.ceil(this.filteredData.length / this.itemsPerPage);
if (page < 1 || page > maxPage) return;
this.currentPage = page;
this.renderTable();
this.updatePaginationInfo();
this.updatePaginationButtons();
}
updatePaginationInfo() {
const start = (this.currentPage - 1) * this.itemsPerPage + 1;
const end = Math.min(this.currentPage * this.itemsPerPage, this.filteredData.length);
const total = this.filteredData.length;
document.getElementById('pagination-info').textContent =
`Showing ${start}-${end} of ${total} components`;
}
updatePaginationButtons() {
const maxPage = Math.ceil(this.filteredData.length / this.itemsPerPage);
document.getElementById('prev-btn').disabled = this.currentPage === 1;
document.getElementById('next-btn').disabled = this.currentPage === maxPage;
document.querySelectorAll('.page-btn[data-page]').forEach(btn => {
btn.classList.toggle('active', parseInt(btn.dataset.page) === this.currentPage);
});
}
showLoading() {
document.getElementById('loading-overlay').classList.add('active');
}
hideLoading() {
document.getElementById('loading-overlay').classList.remove('active');
}
}
// Initialize the Industrial Data Explorer
const dataExplorer = new IndustrialDataExplorer();
// Add some industrial sound effects (optional)
function playMechanicalSound() {
// Create a simple mechanical click sound using Web Audio API
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(200, audioContext.currentTime + 0.1);
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.1);
}
// Add mechanical sound to button clicks
document.addEventListener('click', (e) => {
if (e.target.matches('.export-btn, .page-btn, .mechanical-checkbox input')) {
try {
playMechanicalSound();
} catch (err) {
// Sound is optional, ignore errors
}
}
});
</script>
</body>
</html>