SwapStation_WebApp/frontend/station_selection.html

231 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Swap Station Select a Station</title>
<script src="js/auth-guard.js"></script>
<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@400;500;600;700;800&display=swap" rel="stylesheet">
<script src="https://unpkg.com/lucide@latest" defer></script>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: { sans: ["Inter", "ui-sans-serif", "system-ui"] },
keyframes: {
pulseDot: { '0%,100%': { transform:'scale(1)', opacity: 1 }, '50%': { transform:'scale(1.25)', opacity: .65 } },
fadeUp: { '0%': { opacity:0, transform:'translateY(8px)' }, '100%': { opacity:1, transform:'translateY(0)' } },
},
animation: { pulseDot: 'pulseDot 1.2s ease-in-out infinite', fadeUp: 'fadeUp .25s ease-out both' }
}
}
}
</script>
<style>
:root { color-scheme: dark; }
html, body { height: 100%; }
</style>
</head>
<body class="min-h-screen bg-[#0a0a0a] text-gray-100">
<div class="pointer-events-none fixed inset-0">
<div class="absolute -top-24 -left-24 w-[32rem] h-[32rem] rounded-full bg-emerald-500/10 blur-3xl"></div>
<div class="absolute -bottom-24 -right-24 w-[36rem] h-[36rem] rounded-full bg-sky-500/10 blur-3xl"></div>
</div>
<!-- Header with Logout and Add User -->
<header class="relative z-10 border-b border-white/10 bg-black/20 backdrop-blur">
<div class="mx-auto max-w-7xl px-4 py-4 grid grid-cols-3 items-center gap-3">
<div>
<h1 class="text-xl md:text-2xl font-extratracking-tight">Select a Station</h1>
</div>
<div class="flex justify-center">
<img src="./assets/vec_logo.png" alt="VECMOCON"
class="h-7 w-auto opacity-90" onerror="this.style.display='none'"/>
</div>
<div class="flex items-center justify-end gap-4">
<div class="flex items-center gap-4 text-xs text-gray-400">
<span class="inline-flex items-center gap-1"><span class="h-2 w-2 rounded-full bg-emerald-400"></span> Online</span>
<span class="inline-flex items-center gap-1"><span class="h-2 w-2 rounded-full bg-rose-500"></span> Offline</span>
</div>
<div class="flex items-center gap-2">
<button id="addUserBtn" class="inline-flex items-center gap-2 rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-xs font-semibold hover:border-emerald-400/30">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.5 20.25a7.5 7.5 0 0115 0"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v6m3-3H9"/></svg>
Add User
</button>
<button id="logoutBtn" class="inline-flex items-center gap-2 rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-xs font-semibold hover:border-rose-400/30">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6A2.25 2.25 0 005.25 5.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9l3 3m0 0l-3 3m3-3H3"/></svg>
Logout
</button>
</div>
</div>
</div>
</header>
<main class="relative z-10 mx-auto max-w-7xl px-4 py-6">
<div class="mb-6 grid grid-cols-1 md:grid-cols-3 gap-3">
<div class="md:col-span-2">
<input id="search" type="text" placeholder="Search by name, ID or location"
class="w-full rounded-xl border border-white/10 bg-white/5 px-4 py-3 text-sm placeholder-gray-500 outline-none focus:ring-2 focus:ring-emerald-500/60" />
</div>
<!-- THEMED STATUS DROPDOWN -->
<div class="relative" id="statusFilterWrap">
<button id="statusBtn"
class="w-full flex items-center justify-between rounded-xl border border-white/10 bg-white/5 px-4 py-3 text-sm outline-none
focus:ring-2 focus:ring-emerald-500/60 hover:border-emerald-400/30 transition">
<span id="statusLabel">All statuses</span>
<svg class="h-4 w-4 opacity-80" viewBox="0 0 20 20" fill="currentColor"><path d="M5.23 7.21a.75.75 0 011.06.02L10 11l3.71-3.77a.75.75 0 011.08 1.04l-4.25 4.33a.75.75 0 01-1.08 0L5.21 8.27a.75.75 0 01.02-1.06z"/></svg>
</button>
<div id="statusMenu"
class="hidden absolute z-20 mt-2 w-full rounded-xl border border-white/10 bg-black/85 backdrop-blur-xl shadow-2xl overflow-hidden">
<button data-value="all" class="w-full text-left px-4 py-2 text-sm hover:bg-white/10">All statuses</button>
<button data-value="online" class="w-full text-left px-4 py-2 text-sm hover:bg-white/10">Online</button>
<button data-value="offline" class="w-full text-left px-4 py-2 text-sm hover:bg-white/10">Offline</button>
</div>
</div>
</div>
<!-- Grid -->
<div id="stations-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 items-start"></div>
<div id="empty-state" class="hidden mt-12 text-center text-gray-400">No stations match your filters.</div>
<div id="error-state" class="hidden mt-12 text-center text-rose-300"></div>
</main>
<!-- Station Card Template (with metrics) -->
<template id="station-card-template">
<div class="group rounded-2xl border border-white/10 bg-white/5 p-4 transition animate-fadeUp hover:-translate-y-1.5 hover:border-emerald-400/60 hover:shadow-[0_0_0_1px_rgba(16,185,129,0.25),0_20px_40px_rgba(0,0,0,0.45)]" data-station-id="">
<div class="flex items-start justify-between">
<div class="min-w-0">
<div class="flex items-center gap-2">
<span class="status-dot h-2.5 w-2.5 rounded-full"></span>
<p class="truncate text-sm text-gray-400"><span class="font-semibold text-gray-200 station-name">Station</span></p>
</div>
<!-- <p class="product-id mt-1 text-xs text-gray-400" title="Product ID">-</p> -->
<div class="product-id-wrapper mt-1 flex items-center gap-1.5 text-xs text-gray-400">
<i data-lucide="hash" class="h-3 w-3 text-gray-500"></i>
<span class="product-id"></span>
</div>
<!-- <p class="mt-1 text-xs text-gray-400 station-location">Location</p> -->
<div class="location-wrapper mt-1 flex items-center gap-1.5 text-xs text-gray-400">
<i data-lucide="map-pin" class="h-3 w-3 text-gray-500"></i>
<span class="station-location">Location</span>
</div>
</div>
<span class="status-badge rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide"></span>
</div>
<!-- ID + status row -->
<div class="mt-4 grid grid-cols-1 gap-2 text-xs">
<div class="rounded-lg border border-white/10 bg-black/20 p-2 min-w-0">
<p class="text-[10px] text-gray-400">Station ID</p>
<p class="station-id font-semibold text-gray-200 whitespace-nowrap overflow-x-auto leading-snug text-[11px]" title="Station ID"></p>
</div>
<!-- <div class="rounded-lg border border-white/10 bg-black/20 p-2 min-w-0">
<p class="text-[10px] text-gray-400">Product ID</p>
<p class="product-id font-semibold text-gray-200 whitespace-nowrap overflow-x-auto leading-snug text-[11px]" title="Product ID">—</p>
</div> -->
</div>
<!-- Metrics Row -->
<div class="mt-3 grid grid-cols-3 gap-2">
<div class="rounded-lg border border-white/10 bg-black/20 p-2 text-center">
<p class="text-[10px] text-gray-400">Total Starts</p>
<p class="metric-starts text-sm font-semibold">0</p>
</div>
<div class="rounded-lg border border-white/10 bg-black/20 p-2 text-center">
<p class="text-[10px] text-gray-400">Completed</p>
<p class="metric-success text-sm font-semibold">0</p>
</div>
<div class="rounded-lg border border-white/10 bg-black/20 p-2 text-center">
<p class="text-[10px] text-gray-400">Aborted</p>
<p class="metric-aborted text-sm font-semibold">0</p>
</div>
</div>
<div class="mt-4 flex items-center gap-2">
<button class="open-btn w-full flex-grow rounded-lg bg-gradient-to-r from-emerald-500 to-teal-500 px-3 py-2 text-xs font-semibold text-white transition hover:brightness-110">
Open
</button>
<button class="remove-btn flex-shrink-0 rounded-lg border border-white/10 bg-white/5 p-2 text-rose-400 transition hover:border-rose-400/60 hover:bg-rose-500/10">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-trash-2">
<path d="M3 6h18"/>
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/>
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>
<line x1="10" x2="10" y1="11" y2="17"/>
<line x1="14" x2="14" y1="11" y2="17"/>
</svg>
</button>
</div>
</div>
</template>
<!-- Add Station Card Template (goes LAST) -->
<template id="add-station-card-template">
<div class="flex h-full min-h-[160px] w-full items-center justify-center rounded-2xl border-2 border-dashed border-emerald-400/40 bg-emerald-500/5 p-6 text-emerald-300 hover:border-emerald-300 hover:text-emerald-200 cursor-pointer transition animate-fadeUp">
<div class="flex flex-col items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" /></svg>
<span class="font-semibold">Add Station</span>
</div>
</div>
</template>
<!-- User Modal -->
<div id="userModal" class="fixed inset-0 z-50 hidden bg-black/95">
<div class="absolute inset-0 flex items-center justify-center p-4">
<div class="w-full max-w-md rounded-2xl bg-white/10 p-6">
<h2 class="text-lg font-bold mb-4">Add User</h2>
<form id="userForm" class="space-y-4">
<input type="text" id="newUsername" placeholder="Username" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2" required>
<input type="password" id="newPassword" placeholder="Password" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2" required>
<label class="flex items-center gap-2 text-sm"><input type="checkbox" id="isAdmin" class="h-4 w-4"> Is Admin</label>
<div class="flex justify-end gap-2">
<button type="button" id="cancelUserBtn" class="px-4 py-2 rounded bg-gray-600/40">Cancel</button>
<button type="submit" class="px-4 py-2 rounded bg-emerald-600">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Station Modal -->
<div id="stationModal" class="fixed inset-0 z-50 hidden bg-black/95">
<div class="absolute inset-0 flex items-center justify-center p-4">
<div class="w-full max-w-lg rounded-2xl bg-white/10 p-6">
<h2 class="text-lg font-bold mb-4">Add Station</h2>
<form id="stationForm" class="space-y-3">
<input type="text" placeholder="Station ID" id="stationId" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2" required>
<input type="text" placeholder="Product ID" id="stationProductId" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2" required>
<input type="text" placeholder="Name" id="stationName" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2" required>
<input type="text" placeholder="Location" id="stationLocation" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2" required>
<input type="text" placeholder="MQTT Broker" id="mqttBroker" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2" required>
<input type="number" placeholder="MQTT Port" id="mqttPort" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2" required>
<input type="text" placeholder="MQTT Username" id="mqttUsername" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2">
<input type="password" placeholder="MQTT Password" id="mqttPassword" class="w-full rounded-lg border border-white/20 bg-black/40 px-3 py-2">
<div class="flex justify-end gap-2">
<button type="button" id="cancelStationBtn" class="px-4 py-2 rounded bg-gray-600/40">Cancel</button>
<button type="submit" class="px-4 py-2 rounded bg-emerald-600">Save</button>
</div>
</form>
</div>
</div>
</div>
<script src="./js/station_selection.js"></script>
</body>
</html>