Spaces:
Running
Running
Download index.html from tomzarai/anycoder-0ceb77c8: direct link, hf CLI and curl.
- Browser
- Download file 44.1 kB
-
https://huggingface.co/spaces/tomzarai/anycoder-0ceb77c8/resolve/main/index.html
- Command line
-
hf download hf://spaces/tomzarai/anycoder-0ceb77c8/index.html
-
curl -L -o index.html https://huggingface.co/spaces/tomzarai/anycoder-0ceb77c8/resolve/main/index.html
44.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Device Manager | Apple Style</title>
<!-- Import Google Fonts (San Francisco style approximation) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Font Awesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #007AFF;
--primary-hover: #0056b3;
--danger-color: #FF3B30;
--danger-hover: #d63226;
--success-color: #34C759;
--bg-color: #F5F5F7;
--card-bg: #FFFFFF;
--text-main: #1D1D1F;
--text-secondary: #8E8E93;
--border-color: #D2D2D7;
--shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
--transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
[data-theme="dark"] {
--bg-color: #000000;
--card-bg: #1D1D1D;
--text-main: #F5F5F7;
--text-secondary: #8E8E93;
--border-color: #38383A;
--shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background-color: var(--bg-color);
color: var(--text-main);
line-height: 1.5;
transition: var(--transition);
padding: 20px;
}
/* Header Section */
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 40px;
flex-wrap: wrap;
gap: 20px;
}
.brand {
display: flex;
align-items: center;
gap: 12px;
}
.brand-icon {
width: 40px;
height: 40px;
background: linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
}
h1 {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.5px;
}
.brand-subtitle {
font-size: 14px;
color: var(--text-secondary);
font-weight: 400;
}
.controls {
display: flex;
gap: 15px;
align-items: center;
}
.theme-toggle {
background: none;
border: none;
color: var(--text-main);
font-size: 20px;
cursor: pointer;
padding: 8px;
border-radius: 50%;
transition: background 0.2s;
}
.theme-toggle:hover {
background-color: rgba(128,128,128,0.2);
}
/* Stats Cards */
.stats-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.stat-card {
background-color: var(--card-bg);
padding: 24px;
border-radius: 16px;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
justify-content: space-between;
transition: var(--transition);
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(0,0,0,0.12);
}
.stat-label {
font-size: 14px;
color: var(--text-secondary);
font-weight: 500;
}
.stat-value {
font-size: 36px;
font-weight: 700;
margin: 8px 0 16px 0;
color: var(--primary-color);
}
.stat-trend {
font-size: 13px;
color: var(--success-color);
display: flex;
align-items: center;
gap: 5px;
}
/* Main Content Layout */
.main-container {
display: grid;
grid-template-columns: 350px 1fr;
gap: 30px;
}
@media (max-width: 900px) {
.main-container {
grid-template-columns: 1fr;
}
}
/* Sidebar / Add Device Form */
.sidebar-panel {
background-color: var(--card-bg);
padding: 30px;
border-radius: 20px;
box-shadow: var(--shadow);
height: fit-content;
}
.panel-header {
font-size: 20px;
font-weight: 600;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1px solid var(--border-color);
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
font-size: 13px;
font-weight: 600;
margin-bottom: 8px;
color: var(--text-secondary);
}
input, select, textarea {
width: 100%;
padding: 12px;
border-radius: 10px;
border: 1px solid var(--border-color);
background-color: var(--bg-color);
color: var(--text-main);
font-family: inherit;
font-size: 14px;
transition: var(--transition);
outline: none;
}
input:focus, select:focus, textarea:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.2);
}
.btn {
width: 100%;
padding: 14px;
border: none;
border-radius: 12px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.btn-primary {
background-color: var(--primary-color);
color: white;
box-shadow: 0 4px 8px rgba(0, 122, 255, 0.3);
}
.btn-primary:hover {
background-color: var(--primary-hover);
transform: translateY(-1px);
}
.btn-secondary {
background-color: var(--bg-color);
color: var(--text-main);
border: 1px solid var(--border-color);
margin-top: 10px;
}
.btn-secondary:hover {
background-color: var(--border-color);
}
/* Device List */
.device-list-container {
background-color: var(--card-bg);
border-radius: 20px;
box-shadow: var(--shadow);
overflow: hidden;
display: flex;
flex-direction: column;
}
.list-header {
padding: 24px;
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 15px;
}
.search-box {
position: relative;
width: 100%;
max-width: 300px;
}
.search-box i {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--text-secondary);
}
.search-box input {
padding-left: 40px;
}
.table-responsive {
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background-color: var(--bg-color);
text-align: left;
padding: 16px 24px;
font-size: 12px;
font-weight: 600;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
td {
padding: 18px 24px;
border-bottom: 1px solid var(--border-color);
font-size: 14px;
color: var(--text-main);
}
tr:hover {
background-color: rgba(0,0,0,0.02);
}
[data-theme="dark"] tr:hover {
background-color: rgba(255,255,255,0.05);
}
.status-badge {
display: inline-block;
padding: 4px 10px;
border-radius: 20px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
}
.status-active { background-color: rgba(52, 199, 89, 0.2); color: var(--success-color); }
.status-pending { background-color: rgba(255, 165, 0, 0.2); color: #FF9500; }
.status-offline { background-color: rgba(255, 59, 48, 0.2); color: var(--danger-color); }
.device-name {
font-weight: 600;
display: flex;
align-items: center;
gap: 10px;
}
.device-icon {
width: 32px;
height: 32px;
background: rgba(0,0,0,0.05);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: var(--primary-color);
}
[data-theme="dark"] .device-icon {
background: rgba(255,255,255,0.1);
}
.action-group {
display: flex;
gap: 8px;
}
.action-btn {
width: 32px;
height: 32px;
border-radius: 8px;
border: none;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s;
font-size: 14px;
}
.btn-edit {
background-color: rgba(0, 122, 255, 0.1);
color: var(--primary-color);
}
.btn-edit:hover { background-color: var(--primary-color); color: white; }
.btn-delete {
background-color: rgba(255, 59, 48, 0.1);
color: var(--danger-color);
}
.btn-delete:hover { background-color: var(--danger-color); color: white; }
/* Modal Styles */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);
z-index: 1000;
display: none;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.modal-overlay.active {
display: flex;
opacity: 1;
}
.modal {
background-color: var(--card-bg);
padding: 30px;
border-radius: 24px;
width: 90%;
max-width: 500px;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
transform: scale(0.9);
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.modal-overlay.active .modal {
transform: scale(1);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.close-modal {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: var(--text-secondary);
}
/* Toast Notification */
.toast {
position: fixed;
bottom: 30px;
right: 30px;
background-color: var(--card-bg);
padding: 16px 24px;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
display: flex;
align-items: center;
gap: 12px;
transform: translateY(100px);
transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55);
z-index: 2000;
border-left: 4px solid var(--primary-color);
}
.toast.show {
transform: translateY(0);
}
.toast.success { border-left-color: var(--success-color); }
.toast.error { border-left-color: var(--danger-color); }
/* Built with Link */
.attribution {
margin-top: 50px;
text-align: center;
font-size: 12px;
}
.attribution a {
color: var(--text-secondary);
text-decoration: none;
transition: color 0.2s;
}
.attribution a:hover {
color: var(--primary-color);
text-decoration: underline;
}
</style>
</head>
<body>
<!-- Header -->
<header>
<div class="brand">
<div class="brand-icon">
<i class="fa-solid fa-device-robot"></i>
</div>
<div>
<h1>Device Manager</h1>
<span class="brand-subtitle">Apple Ecosystem Management System</span>
</div>
</div>
<div class="controls">
<button class="theme-toggle" id="themeToggle" title="Toggle Dark Mode">
<i class="fa-solid fa-moon"></i>
</button>
<button class="btn btn-primary" style="width: auto; padding: 10px 24px;" onclick="openModal()">
<i class="fa-solid fa-plus"></i> Add Device
</button>
</div>
</header>
<!-- Statistics -->
<section class="stats-container">
<div class="stat-card">
<span class="stat-label">Total Devices</span>
<div class="stat-value" id="totalDevices">0</div>
<span class="stat-trend"><i class="fa-solid fa-circle-chevron-up"></i> +2 this week</span>
</div>
<div class="stat-card">
<span class="stat-label">Active Devices</span>
<div class="stat-value" id="activeDevices" style="color: var(--success-color)">0</div>
<span class="stat-trend"><i class="fa-solid fa-check-double"></i> System Online</span>
</div>
<div class="stat-card">
<span class="stat-label">Storage Used</span>
<div class="stat-value" id="totalStorage">0 TB</div>
<span class="stat-trend" style="color: var(--primary-color)"><i class="fa-solid fa-hard-drive"></i> Calculating...</span>
</div>
</section>
<div class="main-container">
<!-- Sidebar Form -->
<aside class="sidebar-panel">
<div class="panel-header">
<i class="fa-solid fa-circle-plus" style="color: var(--primary-color); margin-right: 8px;"></i>
Register New Device
</div>
<form id="deviceForm">
<input type="hidden" id="deviceId">
<div class="form-group">
<label for="deviceName">Device Name</label>
<input type="text" id="deviceName" placeholder="e.g., John's iPhone 15 Pro" required>
</div>
<div class="form-group">
<label for="deviceType">Product Type</label>
<select id="deviceType" required>
<option value="" disabled selected>Select a product</option>
<optgroup label="iPhone">
<option value="iPhone 15 Pro Max">iPhone 15 Pro Max</option>
<option value="iPhone 15 Pro">iPhone 15 Pro</option>
<option value="iPhone 15 Plus">iPhone 15 Plus</option>
<option value="iPhone 15">iPhone 15</option>
<option value="iPhone 14 Pro Max">iPhone 14 Pro Max</option>
<option value="iPhone 14">iPhone 14</option>
<option value="iPhone SE (2022)">iPhone SE (2022)</option>
</optgroup>
<optgroup label="iPad">
<option value="iPad Pro 12.9">iPad Pro 12.9 (M2)</option>
<option value="iPad Pro 11">iPad Pro 11 (M2)</option>
<option value="iPad Air 10.9">iPad Air 10.9 (M2)</option>
<option value="iPad (10th Gen)">iPad (10th Generation)</option>
<option value="iPad Mini (6th Gen)">iPad Mini (6th Generation)</option>
</optgroup>
<optgroup label="Mac">
<option value="MacBook Pro 14">MacBook Pro 14 (M3)</option>
<option value="MacBook Pro 16">MacBook Pro 16 (M3 Max)</option>
<option value="MacBook Air 15">MacBook Air 15 (M2)</option>
<option value="MacBook Air 13">MacBook Air 13 (M2)</option>
<option value="iMac 24">iMac 24 (M3)</option>
<option value="Mac mini (M2)">Mac mini (M2)</option>
<option value="Mac Studio">Mac Studio (M2 Max)</option>
<option value="Mac Pro">Mac Pro (M2 Ultra)</option>
</optgroup>
<optgroup label="Watch">
<option value="Apple Watch Ultra 2">Apple Watch Ultra 2</option>
<option value="Apple Watch Series 9">Apple Watch Series 9</option>
<option value="Apple Watch SE (2nd Gen)">Apple Watch SE (2nd Gen)</option>
</optgroup>
<optgroup label="Audio">
<option value="AirPods Pro 2">AirPods Pro 2 (USB-C)</option>
<option value="AirPods Max">AirPods Max</option>
<option value="AirPods 3">AirPods 3</option>
</optgroup>
</select>
</div>
<div class="form-group">
<label for="serialNumber">Serial Number</label>
<input type="text" id="serialNumber" placeholder="e.g., F2X3L4567890" required pattern="[A-Za-z0-9]+">
</div>
<div class="form-group">
<label for="ownerName">Owner / User</label>
<input type="text" id="ownerName" placeholder="e.g., John Doe" required>
</div>
<div class="form-group">
<label for="purchaseDate">Purchase Date</label>
<input type="date" id="purchaseDate" required>
</div>
<div class="form-group">
<label for="status">Device Status</label>
<select id="status">
<option value="Active">Active (In Use)</option>
<option value="Pending">Pending (Setup)</option>
<option value="Offline">Offline (Repair)</option>
<option value="Archived">Archived</option>
</select>
</div>
<div class="form-group">
<label for="notes">Notes</label>
<textarea id="notes" rows="3" placeholder="Any specific details..."></textarea>
</div>
<button type="submit" class="btn btn-primary" id="submitBtn">
<i class="fa-solid fa-floppy-disk"></i> Save Device
</button>
<button type="button" class="btn btn-secondary" id="cancelBtn" style="display: none;">Cancel Edit</button>
</form>
</aside>
<!-- Device List -->
<main class="device-list-container">
<div class="list-header">
<h2 style="font-size: 20px;">Registered Devices</h2>
<div class="search-box">
<i class="fa-solid fa-magnifying-glass"></i>
<input type="text" id="searchInput" placeholder="Search devices, serials, or owners...">
</div>
</div>
<div class="table-responsive">
<table>
<thead>
<tr>
<th>Device</th>
<th>Owner</th>
<th>Serial Number</th>
<th>Purchase Date</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="deviceTableBody">
<!-- Rows will be populated by JS -->
<tr>
<td colspan="6" style="text-align: center; padding: 40px; color: var(--text-secondary);">
<i class="fa-solid fa-table-list" style="font-size: 32px; margin-bottom: 10px; display: block;"></i>
No devices registered yet. Click "Add Device" to get started.
</td>
</tr>
</tbody>
</table>
</div>
</main>
</div>
<div class="attribution">
Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
</div>
<!-- Edit/View Modal -->
<div class="modal-overlay" id="detailModal">
<div class="modal">
<div class="modal-header">
<h2 id="modalTitle" style="font-size: 22px; font-weight: 600;">Device Details</h2>
<button class="close-modal" onclick="closeModal()">×</button>
</div>
<div id="modalContent">
<!-- Dynamic Content Here -->
</div>
<div style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 30px;">
<button class="btn btn-secondary" onclick="closeModal()">Close</button>
<button class="btn btn-primary" onclick="editCurrentDevice()">
<i class="fa-solid fa-pen-to-square"></i> Edit Device
</button>
</div>
</div>
</div>
<!-- Toast Notification -->
<div class="toast" id="toast">
<i class="fa-solid fa-circle-check" style="font-size: 24px;"></i>
<span id="toastMessage">Action Successful</span>
</div>
<script>
// --- Data Management ---
let devices = [
{
id: '1',
name: 'Sarah\'s iPhone 15 Pro',
type: 'iPhone 15 Pro',
serial: 'F8X2K912345',
owner: 'Sarah Jenkins',
purchaseDate: '2023-10-15',
status: 'Active',
notes: 'Silver finish, insurance included.'
},
{
id: '2',
name: 'Work MacBook Air',
type: 'MacBook Air 15 (M2)',
serial: 'C8D4M567890',
owner: 'Company Asset',
purchaseDate: '2023-02-10',
status: 'Active',
notes: 'Company managed device.'
},
{
id: '3',
name: 'Home iPad Pro',
type: 'iPad Pro 12.9',
serial: 'G9H3N123456',
owner: 'Michael Ross',
purchaseDate: '2022-07-20',
status: 'Offline',
notes: 'Needs screen replacement.'
}
];
// --- DOM Elements ---
const deviceForm = document.getElementById('deviceForm');
const tableBody = document.getElementById('deviceTableBody');
const searchInput = document.getElementById('searchInput');
const themeToggle = document.getElementById('themeToggle');
const modal = document.getElementById('detailModal');
const modalContent = document.getElementById('modalContent');
const submitBtn = document.getElementById('submitBtn');
const cancelBtn = document.getElementById('cancelBtn');
const toast = document.getElementById('toast');
// --- Initialization ---
document.addEventListener('DOMContentLoaded', () => {
renderDevices(devices);
updateStats();
// Check system preference for theme
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.body.setAttribute('data-theme', 'dark');
updateThemeIcon();
}
});
// --- Core Functions ---
function renderDevices(deviceList) {
tableBody.innerHTML = '';
if (deviceList.length === 0) {
tableBody.innerHTML = `
<tr>
<td colspan="6" style="text-align: center; padding: 40px; color: var(--text-secondary);">
<i class="fa-solid fa-table-list" style="font-size: 32px; margin-bottom: 10px; display: block;"></i>
No devices found matching your criteria.
</td>
</tr>`;
return;
}
deviceList.forEach(device => {
const tr = document.createElement('tr');
// Determine Icon based on type
let iconClass = 'fa-mobile';
if (device.type.includes('iPhone')) iconClass = 'fa-mobile';
else if (device.type.includes('iPad')) iconClass = 'fa-tablet';
else if (device.type.includes('Mac')) iconClass = 'fa-laptop';
else if (device.type.includes('Watch')) iconClass = 'fa-watch';
else if (device.type.includes('AirPods')) iconClass = 'fa-headphones';
// Status Badge Logic
let statusClass = '';
if (device.status === 'Active') statusClass = 'status-active';
else if (device.status === 'Pending') statusClass = 'status-pending';
else if (device.status === 'Offline') statusClass = 'status-offline';
else statusClass = 'status-offline'; // Default for archived
tr.innerHTML = `
<td>
<div class="device-name">
<div class="device-icon">
<i class="fa-solid ${iconClass}"></i>
</div>
<div>
<div style="font-weight: 600;">${device.name}</div>
<div style="font-size: 12px; color: var(--text-secondary);">${device.type}</div>
</div>
</div>
</td>
<td style="font-weight: 500;">${device.owner}</td>
<td style="font-family: monospace; font-size: 13px; color: var(--text-secondary);">${device.serial}</td>
<td>${device.purchaseDate}</td>
<td><span class="status-badge ${statusClass}">${device.status}</span></td>
<td>
<div class="action-group">
<button class="action-btn btn-edit" title="View Details" onclick="viewDevice('${device.id}')">
<i class="fa-solid fa-eye"></i>
</button>
<button class="action-btn btn-edit" title="Edit" onclick="editDevice('${device.id}')">
<i class="fa-solid fa-pen-to-square"></i>
</button>
<button class="action-btn btn-delete" title="Delete" onclick="deleteDevice('${device.id}')">
<i class="fa-solid fa-trash"></i>
</button>
</div>
</td>
`;
tableBody.appendChild(tr);
});
updateStats();
}
function updateStats() {
const total = devices.length;
const active = devices.filter(d => d.status === 'Active').length;
document.getElementById('totalDevices').innerText = total;
document.getElementById('activeDevices').innerText = active;
// Simple estimation for storage (Mock logic)
let totalStorage = 0;
devices.forEach(d => {
if(d.type.includes('iPhone') || d.type.includes('iPad')) totalStorage += 256; // assume 256GB avg
else if(d.type.includes('Mac')) totalStorage += 1000; // assume 1TB avg
else totalStorage += 64; // assume 64GB avg
});
const tb = (totalStorage / 1024).toFixed(1);
document.getElementById('totalStorage').innerText = `${tb} TB`;
}
function searchDevices(e) {
const term = e.target.value.toLowerCase();
const filtered = devices.filter(device =>
device.name.toLowerCase().includes(term) ||
device.owner.toLowerCase().includes(term) ||
device.serial.toLowerCase().includes(term) ||
device.type.toLowerCase().includes(term)
);
renderDevices(filtered);
}
// --- Form Handling ---
deviceForm.addEventListener('submit', (e) => {
e.preventDefault();
const deviceId = document.getElementById('deviceId').value;
const name = document.getElementById('deviceName').value;
const type = document.getElementById('deviceType').value;
const serial = document.getElementById('serialNumber').value.toUpperCase();
const owner = document.getElementById('ownerName').value;
const purchaseDate = document.getElementById('purchaseDate').value;
const status = document.getElementById('status').value;
const notes = document.getElementById('notes').value;
if (deviceId) {
// Edit existing
const index = devices.findIndex(d => d.id === deviceId);
if (index !== -1) {
devices[index] = {
id: deviceId,
name,
type,
serial,
owner,
purchaseDate,
status,
notes
};
showToast('Device updated successfully!', 'success');
}
resetForm();
} else {
// Add new
const newDevice = {
id: Date.now().toString(),
name,
type,
serial,
owner,
purchaseDate,
status,
notes
};
devices.unshift(newDevice); // Add to top
showToast('New device added to inventory!', 'success');
resetForm();
}
renderDevices(devices);
});
function resetForm() {
deviceForm.reset();
document.getElementById('deviceId').value = '';
submitBtn.innerHTML = '<i class="fa-solid fa-floppy-disk"></i> Save Device';
cancelBtn.style.display = 'none';
document.querySelector('.panel-header').innerHTML =
'<i class="fa-solid fa-circle-plus" style="color: var(--primary-color); margin-right: 8px;"></i> Register New Device';
}
function editDevice(id) {
const device = devices.find(d => d.id === id);
if (!device) return;
document.getElementById('deviceId').value = device.id;
document.getElementById('deviceName').value = device.name;
document.getElementById('deviceType').value = device.type;
document.getElementById('serialNumber').value = device.serial;
document.getElementById('ownerName').value = device.owner;
document.getElementById('purchaseDate').value = device.purchaseDate;
document.getElementById('status').value = device.status;
document.getElementById('notes').value = device.notes || '';
// Update UI for Edit mode
submitBtn.innerHTML = '<i class="fa-solid fa-check"></i> Update Device';
cancelBtn.style.display = 'block';
document.querySelector('.panel-header').innerHTML =
`<i class="fa-solid fa-pen-to-square" style="color: var(--primary-color); margin-right: 8px;"></i> Edit ${device.name}`;
window.scrollTo({ top: 0, behavior: 'smooth' });
}
function deleteDevice(id) {
if (confirm('Are you sure you want to remove this device from management? This action cannot be undone.')) {
devices = devices.filter(d => d.id !== id);
renderDevices(devices);
showToast('Device removed from system.', 'success');
updateStats();
}
}
// --- Modal Functions ---
function viewDevice(id) {
const device = devices.find(d => d.id === id);
if (!device) return;
let iconClass = 'fa-mobile';
if (device.type.includes('iPhone')) iconClass = 'fa-mobile';
else if (device.type.includes('iPad')) iconClass = 'fa-tablet';
else if (device.type.includes('Mac')) iconClass = 'fa-laptop';
else if (device.type.includes('Watch')) iconClass = 'fa-watch';
modalContent.innerHTML = `
<div style="display: flex; align-items: center; gap: 20px; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 1px solid var(--border-color);">
<div style="font-size: 60px; color: var(--primary-color);">
<i class="fa-solid ${iconClass}"></i>
</div>
<div>
<h3 style="font-size: 24px; font-weight: 700;">${device.name}</h3>
<p style="color: var(--text-secondary); font-size: 16px;">${device.type}</p>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div class="form-group">
<label>Serial Number</label>
<div style="font-family: monospace; font-size: 16px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color);">
${device.serial}
</div>
</div>
<div class="form-group">
<label>Owner</label>
<div style="font-size: 16px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color);">
${device.owner}
</div>
</div>
<div class="form-group">
<label>Purchase Date</label>
<div style="font-size: 16px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color);">
${formatDate(device.purchaseDate)}
</div>
</div>
<div class="form-group">
<label>Management Status</label>
<div style="font-size: 16px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color);">
<span class="status-badge ${getStatusClass(device.status)}">${device.status}</span>
</div>
</div>
</div>
<div class="form-group">
<label>Notes</label>
<div style="font-size: 14px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color); color: var(--text-secondary);">
${device.notes || 'No notes available.'}
</div>
</div>
`;
modal.classList.add('active');
}
function editCurrentDevice() {
// Get ID from the modal content (stored in a data attribute or logic)
// Since we don't store ID in modal DOM, we find it by matching content or passing it better.
// Let's fix the viewDevice function to pass ID or store it.
// For this simple implementation, we'll just grab the first device that matches the name and serial (risky but works for demo)
// Better approach: Add ID to modalContent.innerHTML as a hidden field or attribute
// Let's re-implement viewDevice to store ID globally temporarily
const device = devices.find(d =>
modalContent.innerText.includes(d.serial) &&
modalContent.innerText.includes(d.name)
);
if(device) {
closeModal();
editDevice(device.id);
}
}
// Fix for editCurrentDevice to work reliably
let currentModalDeviceId = null;
function viewDevice(id) {
currentModalDeviceId = id;
const device = devices.find(d => d.id === id);
if (!device) return;
let iconClass = 'fa-mobile';
if (device.type.includes('iPhone')) iconClass = 'fa-mobile';
else if (device.type.includes('iPad')) iconClass = 'fa-tablet';
else if (device.type.includes('Mac')) iconClass = 'fa-laptop';
else if (device.type.includes('Watch')) iconClass = 'fa-watch';
modalContent.innerHTML = `
<div style="display: flex; align-items: center; gap: 20px; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 1px solid var(--border-color);">
<div style="font-size: 60px; color: var(--primary-color);">
<i class="fa-solid ${iconClass}"></i>
</div>
<div>
<h3 style="font-size: 24px; font-weight: 700;">${device.name}</h3>
<p style="color: var(--text-secondary); font-size: 16px;">${device.type}</p>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div class="form-group">
<label>Serial Number</label>
<div style="font-family: monospace; font-size: 16px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color);">
${device.serial}
</div>
</div>
<div class="form-group">
<label>Owner</label>
<div style="font-size: 16px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color);">
${device.owner}
</div>
</div>
<div class="form-group">
<label>Purchase Date</label>
<div style="font-size: 16px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color);">
${formatDate(device.purchaseDate)}
</div>
</div>
<div class="form-group">
<label>Management Status</label>
<div style="font-size: 16px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color);">
<span class="status-badge ${getStatusClass(device.status)}">${device.status}</span>
</div>
</div>
</div>
<div class="form-group">
<label>Notes</label>
<div style="font-size: 14px; padding: 10px; background: var(--bg-color); border-radius: 8px; border: 1px solid var(--border-color); color: var(--text-secondary);">
${device.notes || 'No notes available.'}
</div>
</div>
`;
modal.classList.add('active');
}
function editCurrentDevice() {
if (currentModalDeviceId) {
closeModal();
editDevice(currentModalDeviceId);
}
}
function closeModal() {
modal.classList.remove('active');
currentModalDeviceId = null;
}
// --- Utilities ---
function showToast(message, type) {
const toastMsg = document.getElementById('toastMessage');
toastMsg.innerText = message;
toast.className = 'toast show ' + type;
if (type === 'success') {
document.getElementById('toast').innerHTML = '<i class="fa-solid fa-circle-check"></i> <span id="toastMessage">' + message + '</span>';
} else {
document.getElementById('toast').innerHTML = '<i class="fa-solid fa-circle-exclamation"></i> <span id="toastMessage">' + message + '</span>';
}
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
function updateThemeIcon() {
const isDark = document.body.getAttribute('data-theme') === 'dark';
const icon = themeToggle.querySelector('i');
if (isDark) {
icon.className = 'fa-solid fa-sun';
} else {
icon.className = 'fa-solid fa-moon';
}
}
themeToggle.addEventListener('click', () => {
if (document.body.getAttribute('data-theme') === 'dark') {
document.body.removeAttribute('data-theme');
} else {
document.body.setAttribute('data-theme', 'dark');
}
updateThemeIcon();
});
function getStatusClass(status) {
if (status === 'Active') return 'status-active';
if (status === 'Pending') return 'status-pending';
if (status === 'Offline') return 'status-offline';
return 'status-offline';
}
function formatDate(dateString) {
const options = { year: 'numeric', month: 'short', day: 'numeric' };
return new Date(dateString).toLocaleDateString('en-US', options);
}
// Close modal on outside click
window.onclick = function(event) {
if (event.target == modal) {
closeModal();
}
}
cancelBtn.addEventListener('click', resetForm);
</script>
</body>
</html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Device Manager | Apple Style</title>
<!-- Import Google Fonts (San Francisco style approximation) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Font Awesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #007AFF;
--primary-hover: #0056b3;
--danger-color: #FF3B30;
--danger-hover: #d63226;
--success-color: #34C759;
--bg-color: #F5F5F7;
--card-bg: #FFFFFF;
--text-main: #1D1D1F;
--text-secondary: #8E8E93;
--border-color: #D2D2D7;
--shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
--transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
[data-theme="dark"] {
--bg-color: #000000;
--card-bg: #1D1D1D;
--text-main: #F5F5F7;
--text-secondary: #8E8E93;
--border-color: #38383A;
--shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background-color: var(--bg-color);
color: var(--text-main);
line-height: 1.5;
transition: var(--transition);
padding: 20px;
}
/* Header Section */
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 40px;
flex-wrap: wrap;
gap: 20px;
}
.brand {
display: flex;
align-items: center;
gap: 12px;
}
.brand-icon {
width: 40px;
height: 40px;
background: linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
}
h1 {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.5px;
}
.brand-subtitle {
font-size: 14px;
color: var(--text-secondary);
font-weight: 400;
}
.controls {
display: flex;
gap: 15px;
align-items: center;
}