428 lines
28 KiB
HTML
428 lines
28 KiB
HTML
|
<!doctype html>
|
|||
|
<html lang="en" class="scroll-smooth">
|
|||
|
<head>
|
|||
|
<meta charset="utf-8" />
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|||
|
<title>A1 — Product Resources · Leitan GPS</title>
|
|||
|
<meta name="description" content="Model A1 resources: brief intro, key specifications, manuals & documents, software & firmware, knowledge base articles, and videos." />
|
|||
|
<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 id="top" 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" class="hover:text-brand-600 dark:hover:text-brand-400">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>
|
|||
|
|
|||
|
<!-- Breadcrumb & Context -->
|
|||
|
<div class="bg-gray-50/70 dark:bg-gray-900/30 border-b border-gray-200/70 dark:border-gray-800">
|
|||
|
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-3 text-sm text-gray-600 dark:text-gray-300">
|
|||
|
<nav class="flex items-center gap-2" aria-label="Breadcrumb">
|
|||
|
<a href="/index.html" class="hover:underline">Home</a>
|
|||
|
<span>/</span>
|
|||
|
<a href="/index.html#support" class="hover:underline">Support</a>
|
|||
|
<span>/</span>
|
|||
|
<span id="crumbModel" class="font-medium">A1</span>
|
|||
|
<span class="ml-auto inline-flex items-center gap-2"><span id="empState" class="rounded-full border border-gray-300 px-2 py-0.5 text-[11px] text-gray-600 dark:border-gray-700 dark:text-gray-300">Mode: Visitor</span></span>
|
|||
|
</nav>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- Hero: Product summary -->
|
|||
|
<section class="relative">
|
|||
|
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|||
|
<div class="grid lg:grid-cols-[1.1fr_0.9fr] gap-10 py-10 lg:py-14 items-center">
|
|||
|
<div>
|
|||
|
<h1 class="text-3xl sm:text-4xl font-bold tracking-tight"><span id="modelName">A1</span> — Multi‑GNSS Positioning Unit</h1>
|
|||
|
<div class="mt-2 flex flex-wrap items-center gap-2 text-sm">
|
|||
|
<span class="inline-flex items-center gap-1 rounded-full bg-brand-50 px-2.5 py-1 text-brand-700 dark:bg-brand-900/30 dark:text-brand-300">Positioning unit</span>
|
|||
|
<span class="inline-flex items-center gap-1 rounded-full bg-gray-100 px-2.5 py-1 text-gray-700 dark:bg-gray-800 dark:text-gray-300">CE</span>
|
|||
|
<span class="inline-flex items-center gap-1 rounded-full bg-gray-100 px-2.5 py-1 text-gray-700 dark:bg-gray-800 dark:text-gray-300">RoHS</span>
|
|||
|
</div>
|
|||
|
<p class="mt-4 text-gray-600 dark:text-gray-300 max-w-2xl">A rugged, multi‑frequency GNSS receiver for construction machinery. Millimetre‑level positioning with CAN/RS485 interfaces, designed for dusty, high‑vibration environments.</p>
|
|||
|
|
|||
|
<!-- Quick specs badges -->
|
|||
|
<dl class="mt-6 grid gap-3 sm:grid-cols-3 text-sm">
|
|||
|
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Accuracy</dt><dd class="font-medium">RTK cm‑level</dd></div>
|
|||
|
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Interfaces</dt><dd class="font-medium">CAN / RS485</dd></div>
|
|||
|
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Ingress</dt><dd class="font-medium">IP67</dd></div>
|
|||
|
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Power</dt><dd class="font-medium">9–36 V DC</dd></div>
|
|||
|
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Constellations</dt><dd class="font-medium">GPS/GLONASS/Galileo/BeiDou</dd></div>
|
|||
|
<div class="rounded-xl border border-gray-200 p-3 dark:border-gray-800"><dt class="text-gray-500">Update rate</dt><dd class="font-medium">Up to 20 Hz</dd></div>
|
|||
|
</dl>
|
|||
|
|
|||
|
<!-- CTAs -->
|
|||
|
<div class="mt-6 flex flex-wrap gap-3">
|
|||
|
<a href="#documents" 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">Manuals</a>
|
|||
|
<a href="#software" 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">Software / Firmware</a>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="relative">
|
|||
|
<div class="relative rounded-2xl border border-gray-200 bg-white p-3 shadow-soft dark:bg-gray-900 dark:border-gray-800">
|
|||
|
<div class="aspect-video w-full overflow-hidden rounded-xl bg-gray-100 dark:bg-gray-800">
|
|||
|
<img src="https://images.pexels.com/photos/280140/pexels-photo-280140.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=1600" alt="Construction cranes — Pexels" class="h-full w-full object-cover"/>
|
|||
|
</div>
|
|||
|
<div class="mt-3 flex items-center justify-between">
|
|||
|
<div class="text-sm text-gray-600 dark:text-gray-300">Field install preview</div>
|
|||
|
<a href="https://www.pexels.com/video/time-lapse-video-of-an-excavator-5342014/" target="_blank" rel="noopener" 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">
|
|||
|
<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="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.26a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/></svg>
|
|||
|
Watch on Pexels
|
|||
|
</a>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
|
|||
|
<!-- Specs table -->
|
|||
|
<section id="specs" class="py-6">
|
|||
|
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|||
|
<h2 class="text-xl sm:text-2xl font-semibold">Technical specifications</h2>
|
|||
|
<div class="mt-4 grid gap-6 lg:grid-cols-2">
|
|||
|
<div class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800">
|
|||
|
<dl class="grid grid-cols-[160px_1fr] gap-x-6 gap-y-3 text-sm">
|
|||
|
<dt class="text-gray-500">Positioning</dt><dd>RTK, SBAS, PPP (option)</dd>
|
|||
|
<dt class="text-gray-500">Update rate</dt><dd>1/5/10/20 Hz</dd>
|
|||
|
<dt class="text-gray-500">Latency</dt><dd>< 20 ms</dd>
|
|||
|
<dt class="text-gray-500">Interfaces</dt><dd>CAN 2.0B, RS485, UART, Ethernet (option)</dd>
|
|||
|
<dt class="text-gray-500">I/O</dt><dd>2× DI, 1× DO, 1× PPS</dd>
|
|||
|
<dt class="text-gray-500">Power</dt><dd>9–36 V DC, < 5 W</dd>
|
|||
|
<dt class="text-gray-500">Ingress</dt><dd>IP67, MIL‑STD‑810 vibration</dd>
|
|||
|
<dt class="text-gray-500">Operating temp</dt><dd>−30…+70 ℃</dd>
|
|||
|
</dl>
|
|||
|
</div>
|
|||
|
<div class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800">
|
|||
|
<dl class="grid grid-cols-[160px_1fr] gap-x-6 gap-y-3 text-sm">
|
|||
|
<dt class="text-gray-500">Antenna</dt><dd>External, 3.3–5 V bias</dd>
|
|||
|
<dt class="text-gray-500">Mounting</dt><dd>DIN rail / plate</dd>
|
|||
|
<dt class="text-gray-500">Dimensions</dt><dd>120×90×45 mm</dd>
|
|||
|
<dt class="text-gray-500">Weight</dt><dd>450 g</dd>
|
|||
|
<dt class="text-gray-500">Certifications</dt><dd>CE, RoHS</dd>
|
|||
|
<dt class="text-gray-500">SKU</dt><dd>A1‑EU‑BASE</dd>
|
|||
|
<dt class="text-gray-500">Compatibility</dt><dd>AX‑5 antenna, IMU‑PRO</dd>
|
|||
|
</dl>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
|
|||
|
<!-- Divider & Local nav -->
|
|||
|
<div class="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">
|
|||
|
<nav class="flex flex-wrap gap-4 py-4 text-sm">
|
|||
|
<a href="#documents" class="rounded-lg border border-gray-300 px-3 py-1.5 hover:border-brand-500 dark:border-gray-700">Documents</a>
|
|||
|
<a href="#software" class="rounded-lg border border-gray-300 px-3 py-1.5 hover:border-brand-500 dark:border-gray-700">Software & firmware</a>
|
|||
|
<a href="#kb" class="rounded-lg border border-gray-300 px-3 py-1.5 hover:border-brand-500 dark:border-gray-700">Knowledge base</a>
|
|||
|
<a href="#videos" class="rounded-lg border border-gray-300 px-3 py-1.5 hover:border-brand-500 dark:border-gray-700">Videos</a>
|
|||
|
</nav>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- Documents -->
|
|||
|
<section id="documents" class="py-10">
|
|||
|
<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">Manuals & documents</h2>
|
|||
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">Searchable by language and version. Internal items are marked and require employee access.</p>
|
|||
|
</div>
|
|||
|
<div class="flex items-center gap-2 text-sm">
|
|||
|
<select id="docLang" class="rounded-lg border border-gray-300 bg-white px-2.5 py-1.5 dark:bg-gray-950 dark:border-gray-800"><option value="">All languages</option><option value="en">English</option><option value="zh">中文</option><option value="it">Italiano</option></select>
|
|||
|
<select id="docVer" class="rounded-lg border border-gray-300 bg-white px-2.5 py-1.5 dark:bg-gray-950 dark:border-gray-800"><option value="">Latest & history</option><option value="latest">Latest only</option></select>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div id="docList" class="mt-6 grid gap-4"></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
|
|||
|
<!-- Software / Firmware -->
|
|||
|
<section id="software" 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">Software & firmware</h2>
|
|||
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">Platform filters and compatibility hints. Firmware downloads may require confirmation.</p>
|
|||
|
</div>
|
|||
|
<div class="flex items-center gap-2 text-sm">
|
|||
|
<select id="swPlatform" class="rounded-lg border border-gray-300 bg-white px-2.5 py-1.5 dark:bg-gray-950 dark:border-gray-800"><option value="">All platforms</option><option value="win">Windows</option><option value="mac">macOS</option><option value="linux">Linux</option><option value="all">All</option></select>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div id="swList" class="mt-6 grid gap-4"></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
|
|||
|
<!-- Knowledge base -->
|
|||
|
<section id="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 id="kbList" class="mt-6 grid gap-4 lg:grid-cols-2"></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
|
|||
|
<!-- Videos -->
|
|||
|
<section id="videos" 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">Videos</h2>
|
|||
|
<div class="text-xs text-gray-500">Demo player — replace with HLS in production</div>
|
|||
|
</div>
|
|||
|
<div id="videoList" class="mt-6 grid gap-6 lg:grid-cols-2"></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">This is a static prototype page for product resources.</p>
|
|||
|
</div>
|
|||
|
<div>
|
|||
|
<div class="font-semibold">Product</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>
|
|||
|
</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>Mon–Fri, 09:00–18: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');
|
|||
|
})();
|
|||
|
const themeBtn = document.getElementById('themeToggle');
|
|||
|
const sun = document.getElementById('iconSun');
|
|||
|
const moon = document.getElementById('iconMoon');
|
|||
|
function syncIcons(){ const d=document.documentElement.classList.contains('dark'); sun?.classList.toggle('hidden',!d); moon?.classList.toggle('hidden',d); }
|
|||
|
themeBtn?.addEventListener('click',()=>{ document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark')?'dark':'light'); syncIcons(); });
|
|||
|
syncIcons();
|
|||
|
|
|||
|
// Parse query and employee mode
|
|||
|
const params = new URLSearchParams(location.search);
|
|||
|
const q = params.get('q') || '';
|
|||
|
const modelParam = params.get('model') || '';
|
|||
|
const isEmp = !!localStorage.getItem('employee');
|
|||
|
document.getElementById('empState').textContent = 'Mode: ' + (isEmp ? 'Employee' : 'Visitor');
|
|||
|
|
|||
|
// Demo mapping: if serial like SN-A1-… -> A1
|
|||
|
function resolveModel(input){
|
|||
|
if (!input) return 'A1';
|
|||
|
const s = input.toUpperCase();
|
|||
|
if (s.startsWith('SN-A1')) return 'A1';
|
|||
|
if (['A1','A1-PRO'].includes(s)) return 'A1';
|
|||
|
return 'A1';
|
|||
|
}
|
|||
|
const model = modelParam || resolveModel(q);
|
|||
|
document.getElementById('crumbModel').textContent = model;
|
|||
|
document.getElementById('modelName').textContent = model;
|
|||
|
|
|||
|
// Demo data (normally fetched from /data/*.json)
|
|||
|
const DOCS = [
|
|||
|
{ id:'doc-001', productId:'A1', title:'A1 Wiring & Installation', type:'manual', version:'v1.8', lang:'en', size:'2.3MB', updatedAt:'2025-07-08', checksum:'SHA256-…d9c', url:'#', visibility:'public' },
|
|||
|
{ id:'doc-002', productId:'A1', title:'A1 Service Manual', type:'service', version:'v1.7', lang:'en', size:'4.7MB', updatedAt:'2025-07-22', checksum:'SHA256-…9ab', url:'#', visibility:'internal' },
|
|||
|
{ id:'doc-003', productId:'A1', title:'Declaration of Conformity (DoC)', type:'certificate', version:'2025', lang:'en', size:'0.6MB', updatedAt:'2025-06-02', checksum:'SHA256-…123', url:'#', visibility:'public' }
|
|||
|
];
|
|||
|
const SW = [
|
|||
|
{ id:'sw-101', productId:'A1', title:'A1 Config Tool', kind:'software', version:'v2.2.0', platform:'win', size:'18.4MB', updatedAt:'2025-06-20', checksum:'SHA256-…6a5', notesUrl:'#', compat:'A1 hw v2.x+', url:'#', visibility:'public', risk:false },
|
|||
|
{ id:'sw-102', productId:'A1', title:'A1 Firmware', kind:'firmware', version:'v2.3.1', platform:'all', size:'21.0MB', updatedAt:'2025-08-02', checksum:'MD5-…1c3', notesUrl:'#', compat:'A1 hw v2.x+', url:'#', visibility:'internal', risk:true }
|
|||
|
];
|
|||
|
const KB = [
|
|||
|
{ id:'kb-301', productId:'A1', title:'Position drift under vibration — checklist', summary:'Mounting, antenna grounding, EMI, power ripple limits, and field photos…', tags:['Troubleshooting','Installation'], url:'#', visibility:'internal' },
|
|||
|
{ id:'kb-302', productId:'A1', title:'Quick start — first fix in 60s', summary:'A minimal path to first RTK fix with recommended antenna placement.', tags:['Quickstart'], url:'#', visibility:'public' }
|
|||
|
];
|
|||
|
const VIDS = [
|
|||
|
{ id:'vid-501', productId:'A1', title:'A1 quick install (2:13)', duration:'02:13', poster:'https://images.pexels.com/photos/14452156/pexels-photo-14452156.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=1600', sources:[{src:'/media/a1-install-720.mp4',label:'720p'},{src:'/media/a1-install-1080.mp4',label:'1080p'}], visibility:'public' },
|
|||
|
{ id:'vid-502', productId:'A1', title:'Internal: wiring pitfalls (3:40)', duration:'03:40', poster:'https://images.pexels.com/photos/159306/pexels-photo-159306.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=1600', sources:[{src:'/media/a1-internal-720.mp4',label:'720p'}], visibility:'internal' }
|
|||
|
];
|
|||
|
|
|||
|
// Render helpers
|
|||
|
function badgeInternal(v){ return v==='internal' ? '<span class="inline-flex items-center gap-1 rounded bg-gray-100 px-2 py-1 text-[11px] text-gray-600 dark:bg-gray-800 dark:text-gray-300">\uD83D\uDD12 Internal</span>' : ''; }
|
|||
|
function lockIfNoAccess(v){ return v==='internal' && !isEmp ? 'opacity-40 pointer-events-none' : ''; }
|
|||
|
|
|||
|
function renderDocs(){
|
|||
|
const lang = document.getElementById('docLang').value;
|
|||
|
const latestOnly = document.getElementById('docVer').value==='latest';
|
|||
|
let items = DOCS.filter(d=>d.productId===model && (!lang || d.lang===lang));
|
|||
|
if (latestOnly){
|
|||
|
const byType = {};
|
|||
|
for (const d of items){ if (!byType[d.type] || new Date(d.updatedAt) > new Date(byType[d.type].updatedAt)) byType[d.type] = d; }
|
|||
|
items = Object.values(byType);
|
|||
|
}
|
|||
|
document.getElementById('docList').innerHTML = items.map(d=>`
|
|||
|
<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 ${lockIfNoAccess(d.visibility)}">
|
|||
|
<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">${d.title} (${d.version.toUpperCase()} · ${d.lang.toUpperCase()})</div>
|
|||
|
<div class="text-xs text-gray-500">${d.type} · ${d.size} · Updated: ${d.updatedAt} · ${d.checksum}</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="flex shrink-0 items-center gap-3">
|
|||
|
${badgeInternal(d.visibility)}
|
|||
|
<a href="${d.url}" 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>
|
|||
|
<button 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" onclick="alert('Version history — demo');">Version history</button>
|
|||
|
</div>
|
|||
|
</div>`).join('');
|
|||
|
}
|
|||
|
|
|||
|
function renderSW(){
|
|||
|
const plat = document.getElementById('swPlatform').value;
|
|||
|
const items = SW.filter(s=>s.productId===model && (!plat || s.platform===plat || s.platform==='all'));
|
|||
|
document.getElementById('swList').innerHTML = items.map(s=>`
|
|||
|
<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 ${lockIfNoAccess(s.visibility)}">
|
|||
|
<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 ${s.kind==='firmware'?'bg-amber-50 text-amber-700 dark:bg-amber-900/20 dark:text-amber-300':'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">${s.title} (${s.version}) — ${s.kind}</div>
|
|||
|
<div class="text-xs text-gray-500">${s.platform.toUpperCase()} · ${s.size} · Updated: ${s.updatedAt} · ${s.checksum} · Compat: ${s.compat}</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="flex shrink-0 items-center gap-3">
|
|||
|
${badgeInternal(s.visibility)}
|
|||
|
<a href="${s.notesUrl}" 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>
|
|||
|
<button 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" onclick="${s.kind==='firmware'?'confirmFirmware()':'void 0'};">Download</button>
|
|||
|
</div>
|
|||
|
</div>`).join('');
|
|||
|
}
|
|||
|
|
|||
|
function renderKB(){
|
|||
|
const items = KB.filter(k=>k.productId===model);
|
|||
|
document.getElementById('kbList').innerHTML = items.map(k=>`
|
|||
|
<article class="rounded-2xl border border-gray-200 bg-white p-6 shadow-soft dark:bg-gray-900 dark:border-gray-800 ${lockIfNoAccess(k.visibility)}">
|
|||
|
<div class="text-xs text-gray-500">${k.tags.join(' · ')}</div>
|
|||
|
<h3 class="mt-1 font-semibold">${k.title}</h3>
|
|||
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">${k.summary}</p>
|
|||
|
<div class="mt-3 flex items-center gap-3">
|
|||
|
${badgeInternal(k.visibility)}
|
|||
|
<a href="${k.url}" 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">View</a>
|
|||
|
</div>
|
|||
|
</article>`).join('');
|
|||
|
}
|
|||
|
|
|||
|
function renderVideos(){
|
|||
|
const items = VIDS.filter(v=>v.productId===model);
|
|||
|
document.getElementById('videoList').innerHTML = items.map(v=>`
|
|||
|
<div class="rounded-2xl border border-gray-200 bg-white p-3 shadow-soft dark:bg-gray-900 dark:border-gray-800 ${lockIfNoAccess(v.visibility)}">
|
|||
|
<div class="aspect-video w-full overflow-hidden rounded-xl bg-gray-100 dark:bg-gray-800">
|
|||
|
<video controls preload="metadata" poster="${v.poster}" class="h-full w-full">
|
|||
|
${v.sources.map(s=>`<source src="${s.src}" type="video/mp4" />`).join('')}
|
|||
|
</video>
|
|||
|
</div>
|
|||
|
<div class="mt-3 flex items-center justify-between">
|
|||
|
<div class="text-sm text-gray-600 dark:text-gray-300">${v.title}</div>
|
|||
|
${badgeInternal(v.visibility)}
|
|||
|
</div>
|
|||
|
</div>`).join('');
|
|||
|
}
|
|||
|
|
|||
|
function confirmFirmware(){
|
|||
|
const ok = confirm('Firmware download — confirm you have read compatibility and rollback instructions.');
|
|||
|
if (!ok) return; alert('Download started (demo)');
|
|||
|
}
|
|||
|
|
|||
|
document.getElementById('docLang').addEventListener('change', renderDocs);
|
|||
|
document.getElementById('docVer').addEventListener('change', renderDocs);
|
|||
|
document.getElementById('swPlatform').addEventListener('change', renderSW);
|
|||
|
|
|||
|
// initial render
|
|||
|
renderDocs(); renderSW(); renderKB(); renderVideos();
|
|||
|
</script>
|
|||
|
</body>
|
|||
|
</html>
|