2025-08-27 13:34:10 +08:00

380 lines
24 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="scroll-smooth">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Leitan GPS · Employee Portal — Internal Resources</title>
<meta name="description" content="Employee-only resources: restricted manuals, firmware/software, knowledge base articles, and howto videos for field service." />
<meta name="theme-color" content="#0ea5e9" />
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='46' fill='%230ea5e9'/%3E%3Cpath d='M50 20a30 30 0 1030 30A30 30 0 0050 20zm0 10a20 20 0 11-20 20A20 20 0 0150 30z' fill='white'/%3E%3C/svg%3E" />
<!-- Tailwind v4 Play CDN -->
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script type="tailwind-config">
export default {
darkMode: 'class',
theme: {
extend: {
colors: {
brand: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a'
}
},
boxShadow: {
soft: '0 10px 30px rgba(0,0,0,0.06)'
}
}
}
}
</script>
<style>
html { scroll-behavior: smooth; }
::selection { background: #bfdbfe; }
</style>
</head>
<body class="bg-white text-gray-800 antialiased dark:bg-gray-950 dark:text-gray-100">
<!-- Decorative BG -->
<div aria-hidden="true" class="pointer-events-none fixed inset-0 -z-10 overflow-hidden">
<div class="absolute -top-32 left-1/2 h-80 w-[1100px] -translate-x-1/2 rounded-full bg-gradient-to-r from-brand-400/30 via-sky-400/20 to-cyan-400/30 blur-3xl dark:from-brand-600/30 dark:via-sky-600/20 dark:to-cyan-600/30"></div>
</div>
<!-- Header -->
<header class="sticky top-0 z-50 backdrop-blur supports-[backdrop-filter]:bg-white/60 bg-white/80 border-b border-gray-200/70 dark:bg-gray-950/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 items-center justify-between">
<a href="/index.html" class="flex items-center gap-2">
<span class="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-brand-600 text-white shadow-soft">L</span>
<span class="font-semibold">Leitan GPS</span>
</a>
<nav class="hidden md:flex items-center gap-8 text-sm">
<a href="/index.html#support" class="hover:text-brand-600 dark:hover:text-brand-400">Support</a>
<a href="/index.html#catalog" class="hover:text-brand-600 dark:hover:text-brand-400">Catalog</a>
<span class="h-5 w-px bg-gray-300/60 dark:bg-gray-700"></span>
<a href="/employee/index.html" aria-current="page" class="text-brand-700 dark:text-brand-300 font-medium">Employee</a>
<span class="h-5 w-px bg-gray-300/60 dark:bg-gray-700"></span>
<!-- Language (no real switch yet) -->
<div class="flex items-center gap-3" role="group" aria-label="Language">
<button type="button" class="text-xs px-2 py-1 rounded border border-gray-300/80 hover:border-brand-500 hover:text-brand-600 dark:border-gray-700 dark:hover:border-brand-500" title="Italiano (not implemented)">IT</button>
<button type="button" class="text-xs px-2 py-1 rounded border border-brand-500 text-brand-700 dark:text-brand-300" aria-pressed="true" title="English">EN</button>
</div>
</nav>
<div class="flex items-center gap-3">
<button id="themeToggle" aria-label="Toggle theme" class="inline-flex h-9 w-9 items-center justify-center rounded-lg border border-gray-300 bg-white shadow-sm hover:border-brand-500 dark:bg-gray-900 dark:border-gray-700">
<svg id="iconSun" class="h-5 w-5 hidden" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2m0 14v2m9-9h-2M5 12H3m15.364-6.364l-1.414 1.414M7.05 16.95l-1.414 1.414m0-11.314l1.414 1.414M16.95 16.95l1.414 1.414"/><circle cx="12" cy="12" r="4"/></svg>
<svg id="iconMoon" class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
</button>
</div>
</div>
</div>
</header>
<!-- Hero / Access State -->
<section class="relative">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="grid lg:grid-cols-2 gap-10 py-12 lg:py-16 items-start">
<div>
<p class="inline-flex items-center gap-2 rounded-full border border-brand-200 bg-white/80 px-3 py-1 text-xs text-brand-700 shadow-sm dark:bg-gray-900/70 dark:border-brand-800 dark:text-brand-300">
<span class="h-2 w-2 rounded-full bg-brand-500"></span> Employee Portal
</p>
<h1 class="mt-4 text-3xl sm:text-4xl font-bold tracking-tight">Internal resources for field service</h1>
<p class="mt-3 text-base text-gray-600 dark:text-gray-300 max-w-2xl">
Sign in to access restricted manuals, firmware, troubleshooting guides, service bulletins and internal videos. This is a <strong>static demo</strong> with simulated signin (no real authentication).
</p>
<!-- Simulated Access Controls -->
<div class="mt-6 flex flex-wrap items-center gap-3">
<button id="btnSignIn" class="inline-flex items-center justify-center rounded-xl bg-brand-600 px-5 py-3 text-white shadow-soft hover:bg-brand-700 focus:outline-none focus:ring-2 focus:ring-brand-500">Sign in (demo)</button>
<button id="btnSignOut" class="inline-flex items-center justify-center rounded-xl border border-gray-300 bg-white px-5 py-3 text-gray-900 shadow-sm hover:border-brand-500 dark:bg-gray-900 dark:text-gray-100 dark:border-gray-700">Sign out</button>
<span id="stateBadge" class="ml-2 inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs border-gray-300 text-gray-600 dark:border-gray-700 dark:text-gray-300">State: Visitor</span>
</div>
<!-- Quick search within employee portal -->
<form id="empSearch" class="mt-6">
<label class="relative block">
<input id="empQ" type="text" placeholder="Search by model or serial (e.g. A1 or SN-A1-2025…)" class="w-full rounded-xl border border-gray-300 bg-white px-4 py-4 pr-12 text-base shadow-sm focus:outline-none focus:ring-2 focus:ring-brand-500 dark:bg-gray-950 dark:border-gray-800" />
<button class="absolute right-2 top-1/2 -translate-y-1/2 inline-flex items-center justify-center rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm hover:border-brand-500 dark:bg-gray-900 dark:border-gray-700" type="submit" aria-label="Search">
<svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-4.35-4.35M11 18a7 7 0 100-14 7 7 0 000 14z"/></svg>
</button>
</label>
<p class="mt-2 text-xs text-gray-500">Demo behaviour: redirect to /support/index.html?q=…&internal=1</p>
</form>
<div class="mt-6 grid grid-cols-2 gap-3 text-sm">
<a href="#internal-docs" class="rounded-xl border border-gray-200 p-4 hover:border-brand-500 dark:border-gray-800">Restricted manuals</a>
<a href="#internal-fw" class="rounded-xl border border-gray-200 p-4 hover:border-brand-500 dark:border-gray-800">Firmware / tools</a>
<a href="#internal-kb" class="rounded-xl border border-gray-200 p-4 hover:border-brand-500 dark:border-gray-800">Knowledge base</a>
<a href="#internal-video" class="rounded-xl border border-gray-200 p-4 hover:border-brand-500 dark:border-gray-800">Video hub</a>
</div>
</div>
<!-- Right column: Announcement / Bulletins -->
<aside class="space-y-4">
<div class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800">
<div class="flex items-center justify-between">
<h2 class="font-semibold">Service bulletins</h2>
<span class="text-xs rounded-full bg-amber-100 text-amber-700 px-2 py-0.5 dark:bg-amber-900/30 dark:text-amber-300">Internal</span>
</div>
<ul class="mt-4 space-y-3 text-sm">
<li class="flex items-start gap-2">
<span class="mt-1 h-1.5 w-1.5 rounded-full bg-brand-600"></span>
<div>
<div class="font-medium">SB-2025-07: A1 GNSS firmware hotfix</div>
<div class="text-gray-500">Requires hw v2.x+, fixes coldstart TTFF spike. Read before upgrade.</div>
</div>
</li>
<li class="flex items-start gap-2">
<span class="mt-1 h-1.5 w-1.5 rounded-full bg-brand-600"></span>
<div>
<div class="font-medium">KB update: IMUPRO drift troubleshooting</div>
<div class="text-gray-500">New checklist for vibrationinduced bias. Photos added.</div>
</div>
</li>
</ul>
</div>
<div class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800">
<h2 class="font-semibold">My access</h2>
<div class="mt-3 grid grid-cols-2 gap-3 text-sm">
<div class="rounded-xl border border-gray-200 p-4 dark:border-gray-800">
<div class="text-gray-500">Role</div>
<div class="font-medium" id="roleLabel">Visitor</div>
</div>
<div class="rounded-xl border border-gray-200 p-4 dark:border-gray-800">
<div class="text-gray-500">Visibility</div>
<div class="font-medium" id="visLabel">Public only</div>
</div>
</div>
<p class="mt-3 text-xs text-gray-500">Demo only — production uses SSO/2FA + shortlived signed URLs.</p>
</div>
</aside>
</div>
</div>
</section>
<!-- Internal: Documents -->
<section id="internal-docs" class="py-10 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex items-end justify-between gap-4">
<div>
<h2 class="text-xl sm:text-2xl font-semibold">Restricted manuals</h2>
<p class="mt-2 text-gray-600 dark:text-gray-300">Installation, wiring and service docs linked to products.</p>
</div>
<a href="/index.html#support" class="text-sm hover:text-brand-600 dark:hover:text-brand-400">Go to Support</a>
</div>
<div class="mt-6 grid gap-4">
<!-- Row -->
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4 rounded-2xl border border-gray-200 bg-white p-4 shadow-soft dark:bg-gray-900 dark:border-gray-800" data-internal>
<div class="flex min-w-0 flex-1 items-center gap-4">
<div class="flex h-12 w-12 items-center justify-center rounded-xl bg-brand-50 text-brand-700 dark:bg-brand-900/30 dark:text-brand-300">
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6m0 0l-3-3m3 3l3-3M4 18h16"/></svg>
</div>
<div class="min-w-0">
<div class="font-medium truncate">A1 Service Manual (Internal)</div>
<div class="text-xs text-gray-500">PDF · 4.7MB · Updated: 20250722 · SHA256…9ab · Product: A1</div>
</div>
</div>
<div class="flex shrink-0 items-center gap-3">
<span class="inline-flex items-center gap-1 rounded bg-gray-100 px-2 py-1 text-xs text-gray-600 dark:bg-gray-800 dark:text-gray-300"><svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M3 7a2 2 0 012-2h14a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V7z"/><path stroke-linecap="round" stroke-linejoin="round" d="M7 11a5 5 0 1010 0 5 5 0 00-10 0z"/></svg> Internal</span>
<a href="#" class="inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700">Download</a>
</div>
</div>
</div>
</div>
</section>
<!-- Internal: Firmware / Tools -->
<section id="internal-fw" class="py-10 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<h2 class="text-xl sm:text-2xl font-semibold">Firmware & tools</h2>
<p class="mt-2 text-gray-600 dark:text-gray-300">Downloads may require hardware version checks. Read release notes before upgrade.</p>
<div class="mt-6 grid gap-4">
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4 rounded-2xl border border-gray-200 bg-white p-4 shadow-soft dark:bg-gray-900 dark:border-gray-800" data-internal>
<div class="flex min-w-0 flex-1 items-center gap-4">
<div class="flex h-12 w-12 items-center justify-center rounded-xl bg-brand-50 text-brand-700 dark:bg-brand-900/30 dark:text-brand-300">
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M4 4h16v12H4z"/><path stroke-linecap="round" stroke-linejoin="round" d="M4 20h16"/></svg>
</div>
<div class="min-w-0">
<div class="font-medium truncate">A1 Firmware v2.3.1 (Internal)</div>
<div class="text-xs text-gray-500">BIN · 21.0MB · Updated: 20250802 · MD5…1c3 · Compat: A1 hw v2.x+</div>
</div>
</div>
<div class="flex shrink-0 items-center gap-3">
<a href="#" class="inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700">Download</a>
<a href="#" class="inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700">Release notes</a>
</div>
</div>
</div>
</div>
</section>
<!-- Internal: Knowledge Base -->
<section id="internal-kb" class="py-10 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<h2 class="text-xl sm:text-2xl font-semibold">Knowledge base</h2>
<div class="mt-6 grid gap-4 lg:grid-cols-2">
<article class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800" data-internal>
<div class="text-xs text-gray-500">Troubleshooting · Updated Jul 15, 2025</div>
<h3 class="mt-1 font-semibold">A1: Position drift under vibration — checklist</h3>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">Mounting, antenna grounding, EMI check, power ripple limits, and field photos…</p>
<a href="#" class="mt-3 inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700">View</a>
</article>
<article class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800" data-internal>
<div class="text-xs text-gray-500">Howto · Updated Jun 30, 2025</div>
<h3 class="mt-1 font-semibold">IMUPRO: Onsite calibration flow</h3>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">Leveling steps, bias capture, temp compensation hints, and acceptance criteria.</p>
<a href="#" class="mt-3 inline-flex items-center gap-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm hover:border-brand-500 dark:border-gray-700">View</a>
</article>
</div>
</div>
</section>
<!-- Internal: Video Hub -->
<section id="internal-video" class="py-10 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex items-end justify-between gap-4">
<h2 class="text-xl sm:text-2xl font-semibold">Internal videos</h2>
<div class="text-xs text-gray-500">Demo player — replace with HLS in production</div>
</div>
<div class="mt-6 grid gap-6 lg:grid-cols-2">
<div class="rounded-2xl border border-gray-200 bg-white p-3 shadow-soft dark:bg-gray-900 dark:border-gray-800" data-internal>
<div class="aspect-video w-full overflow-hidden rounded-xl bg-gray-100 dark:bg-gray-800">
<video controls preload="metadata" poster="https://images.unsplash.com/photo-1508385082359-f38ae991e8f2?q=80&w=1400&auto=format&fit=crop" class="h-full w-full">
<source src="/media/a1-install-720.mp4" type="video/mp4" />
<source src="/media/a1-install-1080.mp4" type="video/mp4" />
</video>
</div>
<div class="mt-3 flex items-center justify-between">
<div class="text-sm text-gray-600 dark:text-gray-300">A1 internal: wiring pitfalls (3:40)</div>
<a href="#" class="inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-sm border border-gray-300 hover:border-brand-500 dark:border-gray-700">Open</a>
</div>
</div>
<div class="rounded-2xl border border-gray-200 bg-white p-3 shadow-soft dark:bg-gray-900 dark:border-gray-800" data-internal>
<div class="aspect-video w-full overflow-hidden rounded-xl bg-gray-100 dark:bg-gray-800">
<video controls preload="metadata" poster="https://images.unsplash.com/photo-1557778023-3b53d24005d5?q=80&w=1400&auto=format&fit=crop" class="h-full w-full">
<source src="/media/imu-pro-calib-720.mp4" type="video/mp4" />
</video>
</div>
<div class="mt-3 flex items-center justify-between">
<div class="text-sm text-gray-600 dark:text-gray-300">IMUPRO: calibration walkthrough (5:12)</div>
<a href="#" class="inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-sm border border-gray-300 hover:border-brand-500 dark:border-gray-700">Open</a>
</div>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="mt-12 border-t border-gray-200/70 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-10">
<div class="grid gap-8 sm:grid-cols-2 lg:grid-cols-4">
<div>
<div class="flex items-center gap-2">
<span class="inline-flex h-8 w-8 items-center justify-center rounded-lg bg-brand-600 text-white shadow-soft">L</span>
<span class="font-semibold">Leitan GPS</span>
</div>
<p class="mt-3 text-sm text-gray-600 dark:text-gray-300">Internal resources for employees. Demo only.</p>
</div>
<div>
<div class="font-semibold">Links</div>
<ul class="mt-3 space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li><a href="/index.html#support" class="hover:underline">Support & downloads</a></li>
<li><a href="/index.html#catalog" class="hover:underline">Catalog</a></li>
<li><a href="#internal-docs" class="hover:underline">Manuals</a></li>
</ul>
</div>
<div>
<div class="font-semibold">Compliance</div>
<ul class="mt-3 space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li><a href="#" class="hover:underline">Privacy policy</a></li>
<li><a href="#" class="hover:underline">Cookie preferences</a></li>
</ul>
</div>
<div>
<div class="font-semibold">Support</div>
<ul class="mt-3 space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li>support@example.com</li>
<li>MonFri, 09:0018:00</li>
<li>Italy / Singapore</li>
</ul>
</div>
</div>
<div class="mt-8 flex flex-col sm:flex-row items-center justify-between gap-4 text-xs text-gray-500">
<div>© 2025 Leitan Tech. All rights reserved.</div>
<a href="#top" class="inline-flex items-center gap-1 hover:text-brand-600 dark:hover:text-brand-400">Back to top <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M5 15l7-7 7 7"/></svg></a>
</div>
</div>
</footer>
<!-- Scripts -->
<script>
// Theme init
(function() {
const stored = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (stored === 'dark' || (!stored && prefersDark)) {
document.documentElement.classList.add('dark');
}
})();
// Theme toggle
const themeBtn = document.getElementById('themeToggle');
const sun = document.getElementById('iconSun');
const moon = document.getElementById('iconMoon');
function syncIcons() {
const isDark = document.documentElement.classList.contains('dark');
sun.classList.toggle('hidden', !isDark);
moon.classList.toggle('hidden', isDark);
}
themeBtn?.addEventListener('click', () => {
document.documentElement.classList.toggle('dark');
const isDark = document.documentElement.classList.contains('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
syncIcons();
});
syncIcons();
// Demo sign-in/out state
const stateBadge = document.getElementById('stateBadge');
const roleLabel = document.getElementById('roleLabel');
const visLabel = document.getElementById('visLabel');
function setEmployeeState(v) {
if (v) localStorage.setItem('employee','1'); else localStorage.removeItem('employee');
renderEmployeeState();
}
function renderEmployeeState() {
const isEmp = !!localStorage.getItem('employee');
const label = isEmp ? 'Employee' : 'Visitor';
const vis = isEmp ? 'Public + Internal' : 'Public only';
stateBadge.textContent = 'State: ' + label;
roleLabel.textContent = label;
visLabel.textContent = vis;
document.querySelectorAll('[data-internal]')
.forEach(el => el.classList.toggle('opacity-40', !isEmp));
}
document.getElementById('btnSignIn')?.addEventListener('click', () => setEmployeeState(true));
document.getElementById('btnSignOut')?.addEventListener('click', () => setEmployeeState(false));
renderEmployeeState();
// Employee search redirect (demo)
document.getElementById('empSearch')?.addEventListener('submit', function(e) {
e.preventDefault();
const q = (document.getElementById('empQ')?.value || '').trim();
if (!q) return;
const isEmp = !!localStorage.getItem('employee');
const flag = isEmp ? '&internal=1' : '';
window.location.href = '/support/index.html?q=' + encodeURIComponent(q) + flag;
});
</script>
</body>
</html>