From 686263ca6a5fcbe4c205aac8a7697061bea5791f Mon Sep 17 00:00:00 2001 From: Fabien POLLY Date: Fri, 23 Jan 2026 11:51:48 +0100 Subject: [PATCH] fixes --- index.html | 450 +++++++++++++++++++++++++++++++++++++++++--------- manifest.json | 35 ++++ sw.js | 69 ++++++++ 3 files changed, 474 insertions(+), 80 deletions(-) create mode 100644 manifest.json create mode 100644 sw.js diff --git a/index.html b/index.html index 2b58b61..2aca8c3 100644 --- a/index.html +++ b/index.html @@ -8,6 +8,32 @@ BJORN // WIKI NODE + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -68,34 +94,128 @@ background: var(--accent-green); } - /* Utility Classes using vars */ + /* --- GLASSMORPHISM & UI --- */ .bg-hack-sidebar { background-color: var(--bg-sidebar); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); } - .bg-hack-bg { - background-color: var(--bg-body); + .sidebar-mobile { + transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); } - .border-hack-border { + /* --- SEARCH MODAL --- */ + #search-modal { + transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); + } + + #search-modal.hidden { + opacity: 0; + visibility: hidden; + transform: scale(0.95); + } + + #search-modal:not(.hidden) { + opacity: 1; + visibility: visible; + transform: scale(1); + } + + .search-result-item { + transition: all 0.2s; + border: 1px solid transparent; + } + + .search-result-item:hover { + background-color: var(--accent-dim); border-color: var(--border-color); + transform: translateX(4px); } - .text-hack-heading { - color: var(--text-heading); + .search-result-item.active { + background-color: var(--accent-dim); + border-color: var(--accent-green); + transform: translateX(4px); } - .text-hack-green { - color: var(--accent-green); + /* --- MICRO-INTERACTIONS --- */ + .nav-link, + .section-header, + .copy-btn, + .toc-link, + .search-result-item, + #menu-btn, + #theme-toggle-desktop, + #theme-toggle-mobile, + .badge-sm, + .pagination-card, + #toc-btn-mobile, + #toc-btn-desktop { + position: relative; + overflow: hidden; } - .bg-hack-greenDim { + .nav-link::after, + .section-header::after, + .copy-btn::after, + .search-result-item::after, + #menu-btn::after, + #theme-toggle-desktop::after, + #theme-toggle-mobile::after, + .badge-sm::after, + .pagination-card::after, + #toc-btn-mobile::after, + #toc-btn-desktop::after { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(circle at var(--x, 50%) var(--y, 50%), rgba(34, 197, 94, 0.2) 0%, transparent 70%); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + } + + .nav-link:hover::after, + .section-header:hover::after, + .copy-btn:hover::after, + .search-result-item:hover::after, + #menu-btn:hover::after, + #theme-toggle-desktop:hover::after, + #theme-toggle-mobile:hover::after, + .badge-sm:hover::after, + .pagination-card:hover::after, + #toc-btn-mobile:hover::after, + #toc-btn-desktop:hover::after { + opacity: 1; + } + + #page-nav button { + transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); + } + + #page-nav button:hover { + transform: translateY(-4px); + box-shadow: 0 10px 20px -5px rgba(0, 0, 0, 0.3); background-color: var(--accent-dim); } - /* Sidebar Animations */ - .sidebar-mobile { - transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); + /* --- SKELETON SCREENS --- */ + .skeleton { + background: linear-gradient(90deg, var(--bg-sidebar) 25%, var(--border-color) 50%, var(--bg-sidebar) 75%); + background-size: 200% 100%; + animation: skeleton-loading 1.5s infinite; + border-radius: 4px; + } + + @keyframes skeleton-loading { + 0% { + background-position: 200% 0; + } + + 100% { + background-position: -200% 0; + } } /* --- MARKDOWN STYLES --- */ @@ -682,23 +802,27 @@ -
+
+
- -
+
- - +
+ Search... + Ctrl+K +
@@ -790,12 +913,12 @@
@@ -859,11 +988,44 @@ + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..2eb31c6 --- /dev/null +++ b/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "BJORN WIKI", + "short_name": "BjornWiki", + "description": "Official Documentation and Wiki for BJORN Cyber Viking", + "start_url": "./index.html", + "display": "standalone", + "background_color": "#0B0C0E", + "theme_color": "#22c55e", + "orientation": "any", + "icons": [ + { + "src": "assets/bjorn.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "assets/bjorn.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "shortcuts": [ + { + "name": "Search Wiki", + "url": "./index.html?search=true", + "icons": [ + { + "src": "assets/bjorn.png", + "sizes": "192x192" + } + ] + } + ] +} \ No newline at end of file diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..714590d --- /dev/null +++ b/sw.js @@ -0,0 +1,69 @@ +const CACHE_NAME = 'bjorn-wiki-v2'; +const STATIC_ASSETS = [ + './', + './index.html', + './config.js', + './manifest.json', + './assets/bjorn.png', + 'https://cdn.tailwindcss.com', + 'https://unpkg.com/lucide@latest', + 'https://cdn.jsdelivr.net/npm/marked/marked.min.js', + 'https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js', + 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css', + 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js', + 'https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@400;500;600&display=swap' +]; + +// Install Event - Cache Static Assets +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => { + console.log('[SW] Caching static assets'); + return cache.addAll(STATIC_ASSETS); + }) + ); + self.skipWaiting(); +}); + +// Activate Event - Clean up old caches +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((cacheNames) => { + return Promise.all( + cacheNames.map((cacheName) => { + if (cacheName !== CACHE_NAME) { + console.log('[SW] Deleting old cache:', cacheName); + return caches.delete(cacheName); + } + }) + ); + }) + ); + self.clients.claim(); +}); + +// Fetch Event - Stale-While-Revalidate Strategy +self.addEventListener('fetch', (event) => { + // Skip non-GET requests + if (event.request.method !== 'GET') return; + + // Strategy: Stale-While-Revalidate for most assets + event.respondWith( + caches.open(CACHE_NAME).then((cache) => { + return cache.match(event.request).then((response) => { + const fetchPromise = fetch(event.request).then((networkResponse) => { + // Cache the new response + if (networkResponse.ok) { + cache.put(event.request, networkResponse.clone()); + } + return networkResponse; + }).catch(() => { + // If network fails, we already returned the cached response if it exists + }); + + return response || fetchPromise; + }); + }) + ); +}); +