1092 lines
38 KiB
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> |