This commit is contained in:
Fabien POLLY
2026-01-22 22:52:13 +01:00
parent 10d71122bc
commit c52bb9164f
19 changed files with 1449 additions and 111 deletions

109
config.js Normal file
View File

@@ -0,0 +1,109 @@
/**
* AcidWiki Configuration
* Customize your wiki by changing the values below.
*/
const CONFIG = {
// Project Information
projectName: "ACIDWIKI",
projectSubtitle: "WIKI NODE",
description: "Official Documentation and Wiki Template",
// Versioning Settings
// type: "github" (automatic from API) or "local" (manual)
versioning: {
type: "github",
manualVersion: "v1.0.0",
manualDate: "2026-01-21"
},
// GitHub Repository (for version checking when type is "github")
// Format: "username/repo"
repo: "infinition/Bjorn",
branch: "wiki",
// Theme Settings
themes: [
{ id: "dark", name: "Dark Mode", file: "themes/dark.css", isDark: true },
{ id: "dim", name: "Dim Mode", file: "themes/light.css", isDark: true },
{ id: "electric-blue", name: "Electric Blue", file: "themes/electric-blue.css", isDark: true },
{ id: "cyberpunk", name: "Cyberpunk", file: "themes/cyberpunk.css", isDark: true },
{ id: "forest", name: "Forest", file: "themes/forest.css", isDark: true },
{ id: "monochrome", name: "Monochrome", file: "themes/monochrome.css", isDark: true },
{ id: "retro-hackers", name: "Retro Hackers", file: "themes/retro-hackers.css", isDark: true },
{ id: "retro-hackers-w", name: "Retro Hackers White", file: "themes/retro-hackers-w.css", isDark: false },
{ id: "retro-acid-burn", name: "Retro Acid Burn", file: "themes/retro-acid-burn.css", isDark: true },
{ id: "paper", name: "Paper", file: "themes/paper.css", isDark: false },
{ id: "solarized-light", name: "Solarized Light", file: "themes/solarized-light.css", isDark: false },
{ id: "nord-light", name: "Nord Light", file: "themes/nord-light.css", isDark: false },
{ id: "paper-sepia", name: "Sepia Paper", file: "themes/paper-sepia.css", isDark: false },
{ id: "paper-cool", name: "Cool Paper", file: "themes/paper-cool.css", isDark: false },
{ id: "retro-irc", name: "Retro IRC", file: "themes/retro-irc.css", isDark: false },
{ id: "nature", name: "Nature", file: "themes/nature.css", isDark: false },
{ id: "glassmorphism", name: "Glassmorphism", file: "themes/glassmorphism.css", isDark: true }
],
defaultTheme: "dark",
// Feature Toggles
features: {
showChangelog: true,
showSearch: true,
showSocialBadges: true,
showThemeToggle: true,
pageTransitions: true,
autoCollapseSidebar: false
},
// Custom Navigation Links
// Inserted at the top or bottom of the sidebar
links: {
top: [
{ name: "Main Site", url: "https://example.com", icon: "external-link" }
],
bottom: [
{ name: "Portfolio", url: "https://portfolio.example.com", icon: "briefcase" },
{ name: "Store", url: "https://store.example.com", icon: "shopping-cart" }
]
},
// Footer Customization
footerText: "© 2026 ACIDWIKI - All rights reserved",
// UI Strings (Custom labels for the interface)
ui: {
joinUsTitle: ":: JOIN US ::",
onThisPageTitle: "On this page",
changelogTitle: "Changelog",
searchPlaceholder: "Search (Ctrl+K)...",
lastUpdatedText: "Updated",
readingTimePrefix: "~",
readingTimeSuffix: "min read",
noResultsText: "No results found.",
noSectionsText: "No sections",
fetchingReleasesText: "Fetching GitHub releases...",
checkingVersionText: "checking...",
initializingText: "Initializing...",
themeChangedText: "Theme changed to: ",
menuText: "Menu",
onThisPageMobile: "On this page"
},
// Logo Settings
logoPath: "assets/bjorn.png",
logoPlaceholder: "https://placehold.co/40x40/111214/22c55e?text=A",
// Social Links
// Set to null or empty string to hide the link
social: {
discord: "https://discord.gg/B3ZH9taVfT",
reddit: "https://www.reddit.com/r/Bjorn_CyberViking/",
github: "https://github.com/infinition/Bjorn",
buyMeACoffee: "https://buymeacoffee.com/infinition"
},
// Badge Labels (Optional customization for shields.io)
badges: {
discordLabel: "COMMUNITY",
redditLabel: "r/ACIDWIKI",
githubLabel: "ACIDWIKI"
}
};

View File

@@ -4,8 +4,14 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>BJORN // WIKI NODE</title> <title id="site-title">BJORN // WIKI NODE</title>
<meta name="description" content="Official Documentation and Wiki for BJORN Cyber Viking"> <meta name="description" id="meta-description" content="Official Documentation and Wiki for BJORN Cyber Viking">
<!-- Configuration -->
<script src="config.js"></script>
<!-- Dynamic Theme -->
<link id="theme-link" rel="stylesheet" href="">
<!-- Tailwind CSS (CDN) --> <!-- Tailwind CSS (CDN) -->
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
@@ -31,28 +37,8 @@
<style> <style>
/* --- THEME ENGINE (CSS Variables) --- */ /* --- THEME ENGINE (CSS Variables) --- */
:root { /* Variables are now loaded from themes/*.css */
--bg-body: #0B0C0E;
--bg-sidebar: #111214;
--border-color: #2A2E35;
--text-main: #A0AAB8;
--text-heading: #E2E8F0;
--accent-green: #22c55e;
--accent-dim: rgba(34, 197, 94, 0.1);
--code-bg: #1e1e1e;
}
/* Light Mode Overrides */
html.light {
--bg-body: #F8FAFC;
--bg-sidebar: #FFFFFF;
--border-color: #E2E8F0;
--text-main: #475569;
--text-heading: #1E293B;
--accent-green: #16a34a;
--accent-dim: rgba(22, 163, 74, 0.1);
--code-bg: #f1f5f9;
}
/* Base Settings */ /* Base Settings */
body { body {
@@ -345,7 +331,26 @@
/* TOC & Scroll */ /* TOC & Scroll */
.toc-link.active { .toc-link.active {
color: var(--accent-green); color: var(--accent-green);
border-left-color: var(--accent-green); }
#toc-svg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: visible;
z-index: 10;
}
#toc-path {
transition: d 0.3s cubic-bezier(0.16, 1, 0.3, 1);
opacity: 0;
}
#toc-path.active {
opacity: 1;
} }
#scroll-top-btn { #scroll-top-btn {
@@ -458,6 +463,75 @@
margin-bottom: 20px; margin-bottom: 20px;
} }
} }
/* Toast Notification */
#toast-container {
position: fixed;
bottom: 2rem;
left: 50%;
transform: translateX(-50%) translateY(100px);
background-color: var(--bg-sidebar);
color: var(--accent-green);
border: 1px solid var(--accent-green);
padding: 0.75rem 1.5rem;
border-radius: 9999px;
font-size: 0.875rem;
font-weight: 600;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
z-index: 200;
transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s;
opacity: 0;
pointer-events: none;
display: flex;
align-items: center;
gap: 0.5rem;
}
#toast-container.active {
transform: translateX(-50%) translateY(0);
opacity: 1;
}
/* --- PAGE TRANSITIONS --- */
.content-transition-area {
view-transition-name: content-transition;
}
::view-transition-old(content-transition) {
animation: blur-scale-fade-out 0.3s cubic-bezier(0.455, 0.03, 0.515, 0.955) forwards;
}
::view-transition-new(content-transition) {
animation: blur-scale-fade-in 0.5s cubic-bezier(0.455, 0.03, 0.515, 0.955) forwards;
}
@keyframes blur-scale-fade-out {
from {
filter: blur(0);
transform: scale(1);
opacity: 1;
}
to {
filter: blur(4px);
transform: scale(1.05);
opacity: 0;
}
}
@keyframes blur-scale-fade-in {
from {
filter: blur(4px);
transform: scale(0.95);
opacity: 0;
}
to {
filter: blur(0);
transform: scale(1);
opacity: 1;
}
}
</style> </style>
<script> <script>
@@ -487,6 +561,12 @@
<div id="reading-progress-bar"></div> <div id="reading-progress-bar"></div>
<!-- Toast Notification -->
<div id="toast-container">
<i data-lucide="check-circle" class="w-4 h-4"></i>
<span id="toast-message"></span>
</div>
<!-- Lightbox --> <!-- Lightbox -->
<div id="lightbox" <div id="lightbox"
class="fixed inset-0 z-[100] bg-black/90 backdrop-blur-sm flex items-center justify-center opacity-0 invisible cursor-zoom-out" class="fixed inset-0 z-[100] bg-black/90 backdrop-blur-sm flex items-center justify-center opacity-0 invisible cursor-zoom-out"
@@ -500,23 +580,25 @@
class="md:hidden flex-none bg-hack-sidebar border-b border-hack-border h-16 flex items-center justify-between px-4 z-[60] relative shadow-lg"> class="md:hidden flex-none bg-hack-sidebar border-b border-hack-border h-16 flex items-center justify-between px-4 z-[60] relative shadow-lg">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div class="w-10 h-10"> <div class="w-10 h-10">
<img src="assets/bjorn.png" onerror="this.src='https://placehold.co/40x40/111214/22c55e?text=B'" <img id="mobile-logo" src="assets/bjorn.png"
alt="Bjorn Icon" class="w-full h-full object-contain drop-shadow-[0_0_5px_rgba(34,197,94,0.3)]"> onerror="this.src='https://placehold.co/40x40/111214/22c55e?text=B'" alt="Logo"
class="w-full h-full object-contain drop-shadow-[0_0_5px_rgba(34,197,94,0.3)]">
</div> </div>
<span class="font-bold text-hack-heading tracking-wide flex items-center gap-2"> <span class="font-bold text-hack-heading tracking-wide flex items-center gap-2">
BJORN <span class="version-display text-hack-green text-[10px] font-mono opacity-80 pt-1">...</span> <span id="mobile-project-name">BJORN</span> <span
class="version-display text-hack-green text-[10px] font-mono opacity-80 pt-1">...</span>
</span> </span>
</div> </div>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<button id="theme-toggle-mobile" <button id="theme-toggle-mobile"
class="text-gray-300 dark:text-gray-200 hover:text-hack-green p-2 transition-colors"> class="text-gray-300 dark:text-gray-200 hover:text-hack-green p-2 transition-colors"
<i data-lucide="sun" class="w-5 h-5 hidden dark:block"></i> title="Switch Theme">
<i data-lucide="moon" class="w-5 h-5 block dark:hidden"></i> <i data-lucide="palette" class="w-5 h-5"></i>
</button> </button>
<button id="menu-btn" <button id="menu-btn"
class="flex items-center gap-2 px-3 py-1.5 rounded bg-hack-bg border border-hack-border text-hack-heading active:bg-hack-greenDim transition-colors"> class="flex items-center gap-2 px-3 py-1.5 rounded bg-hack-bg border border-hack-border text-hack-heading active:bg-hack-greenDim transition-colors">
<span class="text-xs font-mono font-bold uppercase tracking-wider">Menu</span> <span id="label-menu" class="text-xs font-mono font-bold uppercase tracking-wider">Menu</span>
<i data-lucide="menu" class="w-5 h-5 text-hack-green"></i> <i data-lucide="menu" class="w-5 h-5 text-hack-green"></i>
</button> </button>
</div> </div>
@@ -539,12 +621,13 @@
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div class="w-12 h-12 shrink-0"> <div class="w-12 h-12 shrink-0">
<img src="assets/bjorn.png" onerror="this.src='https://placehold.co/48x48/111214/22c55e?text=B'" <img id="sidebar-logo" src="assets/bjorn.png"
alt="Bjorn Icon" onerror="this.src='https://placehold.co/48x48/111214/22c55e?text=B'" alt="Logo"
class="w-full h-full object-contain drop-shadow-[0_0_8px_rgba(34,197,94,0.4)]"> class="w-full h-full object-contain drop-shadow-[0_0_8px_rgba(34,197,94,0.4)]">
</div> </div>
<div> <div>
<h1 class="font-bold text-hack-heading leading-none text-lg">BJORN</h1> <h1 id="sidebar-project-name" class="font-bold text-hack-heading leading-none text-lg">BJORN
</h1>
<p class="version-display text-[10px] text-gray-500 font-mono mt-1 flex items-center gap-2"> <p class="version-display text-[10px] text-gray-500 font-mono mt-1 flex items-center gap-2">
<span class="version-loading">checking...</span> <span class="version-loading">checking...</span>
</p> </p>
@@ -565,6 +648,7 @@
</div> </div>
<div class="flex-1 overflow-y-auto flex flex-col" role="navigation" aria-label="Main Navigation"> <div class="flex-1 overflow-y-auto flex flex-col" role="navigation" aria-label="Main Navigation">
<div id="custom-links-top" class="px-3 pt-2 space-y-1"></div>
<div class="px-3 pt-4"> <div class="px-3 pt-4">
<div class="nav-group mb-1"> <div class="nav-group mb-1">
<button id="btn-versions" <button id="btn-versions"
@@ -572,7 +656,7 @@
onclick="toggleVersionsPage(this)" tabindex="0"> onclick="toggleVersionsPage(this)" tabindex="0">
<div <div
class="flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest font-mono text-hack-green"> class="flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest font-mono text-hack-green">
<i data-lucide="history" class="w-3 h-3"></i> Changelog <i data-lucide="history" class="w-3 h-3"></i> <span id="label-changelog">Changelog</span>
</div> </div>
<i data-lucide="chevron-right" <i data-lucide="chevron-right"
class="w-3 h-3 opacity-0 group-hover:opacity-100 transition-opacity"></i> class="w-3 h-3 opacity-0 group-hover:opacity-100 transition-opacity"></i>
@@ -585,55 +669,39 @@
<div <div
class="w-4 h-4 border-2 border-hack-green border-t-transparent rounded-full animate-spin mx-auto mb-2"> class="w-4 h-4 border-2 border-hack-green border-t-transparent rounded-full animate-spin mx-auto mb-2">
</div> </div>
Initializing... <span id="label-initializing">Initializing...</span>
</div> </div>
</nav> </nav>
<div id="custom-links-bottom" class="px-3 pb-4 space-y-1"></div>
<div id="social-section" class="p-4 border-t border-hack-border bg-hack-bg/30 flex-none">
<div id="search-results-msg" class="hidden px-4 py-2 text-xs text-red-400 text-center italic"> <div id="search-results-msg" class="hidden px-4 py-2 text-xs text-red-400 text-center italic">
No results found. No results found.
</div> </div>
</div>
<div class="p-4 border-t border-hack-border bg-hack-bg/30 flex-none">
<div class="text-center"> <div class="text-center">
<strong class="text-gray-500 text-sm block mb-3 font-mono tracking-wide">:: JOIN US ::</strong> <strong id="label-join-us" class="text-gray-500 text-sm block mb-3 font-mono tracking-wide">:: JOIN
<div class="flex flex-col"> US ::</strong>
<div id="social-links" class="flex flex-col">
<a href="https://discord.gg/B3ZH9taVfT" target="_blank" <!-- Social links will be injected by JS -->
class="hover:opacity-80 transition-opacity block">
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscord.com%2Fapi%2Finvites%2FB3ZH9taVfT%3Fwith_counts%3Dtrue&query=%24.approximate_member_count&logo=discord&logoColor=white&style=for-the-badge&label=BJORN&color=5865F2&labelColor=2A2E35"
alt="Discord BJORN" class="w-full badge-sm" />
</a>
<a href="https://www.reddit.com/r/Bjorn_CyberViking/" target="_blank"
class="hover:opacity-80 transition-opacity block">
<img src="https://img.shields.io/reddit/subreddit-subscribers/Bjorn_CyberViking?style=for-the-badge&logo=reddit&label=r/Bjorn&color=FF4500&labelColor=2A2E35&logoColor=white"
alt="Reddit" class="w-full badge-sm" />
</a>
<a href="https://github.com/infinition/Bjorn" target="_blank"
class="hover:opacity-80 transition-opacity block">
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.github.com%2Frepos%2Finfinition%2FBjorn&query=%24.stargazers_count&style=for-the-badge&logo=github&color=0B0C0E&labelColor=2A2E35&label=BJORN&logoColor=white"
alt="GitHub BJORN" class="w-full badge-sm" />
</a>
<a href="https://buymeacoffee.com/infinition" target="_blank"
class="hover:opacity-80 transition-opacity block pt-2 border-t border-hack-border/30 mt-1">
<img src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black"
alt="Buy Me A Coffee" class="w-full badge-sm" />
</a>
</div> </div>
</div> </div>
</div> </div>
<div id="sidebar-footer"
class="p-4 border-t border-hack-border bg-hack-bg/50 text-[10px] text-gray-500 font-mono text-center">
<!-- Footer text will be injected by JS -->
</div>
</div>
</aside> </aside>
<!-- Mobile Sidebar (Right - TOC) --> <!-- Mobile Sidebar (Right - TOC) -->
<aside id="mobile-toc-sidebar" <aside id="mobile-toc-sidebar"
class="sidebar-mobile fixed top-0 bottom-0 right-0 z-[70] w-[280px] bg-hack-sidebar border-l border-hack-border transform translate-x-full md:hidden flex flex-col shadow-2xl transition-transform duration-300"> class="sidebar-mobile fixed top-0 bottom-0 right-0 z-[70] w-[280px] bg-hack-sidebar border-l border-hack-border transform translate-x-full md:hidden flex flex-col shadow-2xl transition-transform duration-300">
<div class="p-4 border-b border-hack-border flex justify-between items-center bg-hack-bg/50"> <div class="p-4 border-b border-hack-border flex justify-between items-center bg-hack-bg/50">
<span class="text-xs font-bold text-gray-500 uppercase tracking-widest font-mono">Table of Contents</span> <span id="label-mobile-toc"
class="text-xs font-bold text-gray-500 uppercase tracking-widest font-mono">Table of Contents</span>
<button id="close-toc-btn" class="text-gray-400 hover:text-white"> <button id="close-toc-btn" class="text-gray-400 hover:text-white">
<i data-lucide="x" class="w-5 h-5"></i> <i data-lucide="x" class="w-5 h-5"></i>
</button> </button>
@@ -646,7 +714,7 @@
<div class="flex-1 flex flex-col h-full overflow-hidden relative"> <div class="flex-1 flex flex-col h-full overflow-hidden relative">
<main class="flex-1 overflow-y-auto bg-hack-bg scroll-smooth relative w-full" id="scroll-container"> <main class="flex-1 overflow-y-auto bg-hack-bg scroll-smooth relative w-full" id="scroll-container">
<div class="max-w-6xl mx-auto px-5 py-8 md:py-12 md:px-10 flex gap-10"> <div class="max-w-6xl mx-auto px-5 py-8 md:py-12 md:px-10 flex gap-10">
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0 content-transition-area">
<div <div
class="flex flex-col md:flex-row md:items-center justify-between mb-6 gap-2 border-b border-hack-border/50 pb-4"> class="flex flex-col md:flex-row md:items-center justify-between mb-6 gap-2 border-b border-hack-border/50 pb-4">
<div class="flex items-center gap-2 text-xs font-mono text-gray-500 overflow-x-auto whitespace-nowrap pb-2 md:pb-0" <div class="flex items-center gap-2 text-xs font-mono text-gray-500 overflow-x-auto whitespace-nowrap pb-2 md:pb-0"
@@ -661,9 +729,8 @@
<button id="theme-toggle-desktop" <button id="theme-toggle-desktop"
class="text-gray-500 hover:text-hack-green transition-colors hidden md:block bg-hack-sidebar border border-hack-border rounded p-1.5" class="text-gray-500 hover:text-hack-green transition-colors hidden md:block bg-hack-sidebar border border-hack-border rounded p-1.5"
title="Toggle Theme"> title="Switch Theme">
<i data-lucide="sun" class="w-4 h-4 hidden dark:block"></i> <i data-lucide="palette" class="w-4 h-4"></i>
<i data-lucide="moon" class="w-4 h-4 block dark:hidden"></i>
</button> </button>
</div> </div>
</div> </div>
@@ -677,11 +744,17 @@
<aside class="hidden xl:block w-64 shrink-0"> <aside class="hidden xl:block w-64 shrink-0">
<div class="sticky top-6"> <div class="sticky top-6">
<h4 <h4 id="label-on-this-page"
class="text-xs font-bold text-gray-500 uppercase tracking-widest mb-4 border-b border-hack-border pb-2"> class="text-xs font-bold text-gray-500 uppercase tracking-widest mb-4 border-b border-hack-border pb-2">
On this page</h4> On this page</h4>
<div class="relative">
<svg id="toc-svg">
<path id="toc-path" fill="none" stroke="var(--accent-green)" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
<ul id="toc-container" class="space-y-2 text-xs border-l border-hack-border pl-3"></ul> <ul id="toc-container" class="space-y-2 text-xs border-l border-hack-border pl-3"></ul>
</div> </div>
</div>
</aside> </aside>
</div> </div>
</main> </main>
@@ -719,44 +792,202 @@
contentCache: {}, contentCache: {},
searchIndex: [], searchIndex: [],
expandedSections: new Set(), expandedSections: new Set(),
repo: "infinition/Bjorn", // YOUR REPO repo: CONFIG.repo,
branch: "wiki" branch: CONFIG.branch
}; };
// --- 1.5 INITIALIZE CONFIG ---
function applyConfig() {
document.getElementById('site-title').innerText = `${CONFIG.projectName} // ${CONFIG.projectSubtitle}`;
document.getElementById('meta-description').setAttribute('content', CONFIG.description);
const mobileLogo = document.getElementById('mobile-logo');
mobileLogo.src = CONFIG.logoPath;
mobileLogo.onerror = () => mobileLogo.src = CONFIG.logoPlaceholder;
const sidebarLogo = document.getElementById('sidebar-logo');
sidebarLogo.src = CONFIG.logoPath;
sidebarLogo.onerror = () => sidebarLogo.src = CONFIG.logoPlaceholder;
document.getElementById('mobile-project-name').innerText = CONFIG.projectName;
document.getElementById('sidebar-project-name').innerText = CONFIG.projectName;
// UI Strings
document.getElementById('search-input').placeholder = CONFIG.ui.searchPlaceholder;
document.getElementById('label-changelog').innerText = CONFIG.ui.changelogTitle;
document.getElementById('label-initializing').innerText = CONFIG.ui.initializingText;
document.getElementById('label-join-us').innerText = CONFIG.ui.joinUsTitle;
document.getElementById('label-on-this-page').innerText = CONFIG.ui.onThisPageTitle;
document.getElementById('label-mobile-toc').innerText = CONFIG.ui.onThisPageMobile || CONFIG.ui.onThisPageTitle;
document.getElementById('search-results-msg').innerText = CONFIG.ui.noResultsText;
document.getElementById('label-menu').innerText = CONFIG.ui.menuText || "Menu";
const versionLoading = document.querySelector('.version-loading');
if (versionLoading) versionLoading.innerText = CONFIG.ui.checkingVersionText;
// Feature Toggles
const changelogBtn = document.getElementById('btn-versions');
if (changelogBtn) {
changelogBtn.style.display = CONFIG.features.showChangelog ? 'flex' : 'none';
}
const searchContainer = document.getElementById('search-input').parentElement;
if (searchContainer) {
searchContainer.style.display = CONFIG.features.showSearch ? 'block' : 'none';
}
const socialSection = document.getElementById('social-section');
if (socialSection) {
socialSection.style.display = CONFIG.features.showSocialBadges ? 'block' : 'none';
}
const themeToggles = [
document.getElementById('theme-toggle-mobile'),
document.getElementById('theme-toggle-desktop')
];
themeToggles.forEach(btn => {
if (btn) btn.style.display = CONFIG.features.showThemeToggle ? 'block' : 'none';
});
renderCustomLinks();
renderFooter();
renderSocialLinks();
}
function renderCustomLinks() {
const render = (containerId, links) => {
const container = document.getElementById(containerId);
if (!container) return;
container.innerHTML = '';
if (!links || links.length === 0) return;
links.forEach(link => {
container.innerHTML += `
<a href="${link.url}" target="_blank" class="flex items-center gap-2 px-2 py-1.5 text-xs text-gray-400 hover:text-hack-green hover:bg-hack-bg rounded transition-colors group">
<i data-lucide="${link.icon || 'link'}" class="w-3.5 h-3.5"></i>
<span>${link.name}</span>
</a>`;
});
lucide.createIcons();
};
render('custom-links-top', CONFIG.links.top);
render('custom-links-bottom', CONFIG.links.bottom);
}
function renderFooter() {
const footer = document.getElementById('sidebar-footer');
if (footer) {
footer.innerText = CONFIG.footerText || "";
footer.style.display = CONFIG.footerText ? 'block' : 'none';
}
}
// --- 1.6 TOAST SYSTEM ---
let toastTimeout;
function showToast(message) {
const toast = document.getElementById('toast-container');
const msgSpan = document.getElementById('toast-message');
clearTimeout(toastTimeout);
msgSpan.innerText = message;
toast.classList.add('active');
toastTimeout = setTimeout(() => {
toast.classList.remove('active');
}, 3000);
}
function renderSocialLinks() {
const container = document.getElementById('social-links');
container.innerHTML = '';
if (CONFIG.social.discord) {
const inviteCode = CONFIG.social.discord.split('/').pop();
container.innerHTML += `
<a href="${CONFIG.social.discord}" target="_blank" class="hover:opacity-80 transition-opacity block">
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscord.com%2Fapi%2Finvites%2F${inviteCode}%3Fwith_counts%3Dtrue&query=%24.approximate_member_count&logo=discord&logoColor=white&style=for-the-badge&label=${CONFIG.badges.discordLabel}&color=5865F2&labelColor=2A2E35"
alt="Discord" class="w-full badge-sm" />
</a>`;
}
if (CONFIG.social.reddit) {
const subreddit = CONFIG.social.reddit.split('/r/').pop().replace(/\/$/, '');
container.innerHTML += `
<a href="${CONFIG.social.reddit}" target="_blank" class="hover:opacity-80 transition-opacity block">
<img src="https://img.shields.io/reddit/subreddit-subscribers/${subreddit}?style=for-the-badge&logo=reddit&label=${CONFIG.badges.redditLabel}&color=FF4500&labelColor=2A2E35&logoColor=white"
alt="Reddit" class="w-full badge-sm" />
</a>`;
}
if (CONFIG.social.github) {
const repoPath = CONFIG.social.github.replace('https://github.com/', '');
container.innerHTML += `
<a href="${CONFIG.social.github}" target="_blank" class="hover:opacity-80 transition-opacity block">
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.github.com%2Frepos%2F${repoPath}&query=%24.stargazers_count&style=for-the-badge&logo=github&color=0B0C0E&labelColor=2A2E35&label=${CONFIG.badges.githubLabel}&logoColor=white"
alt="GitHub" class="w-full badge-sm" />
</a>`;
}
if (CONFIG.social.buyMeACoffee) {
container.innerHTML += `
<a href="${CONFIG.social.buyMeACoffee}" target="_blank" class="hover:opacity-80 transition-opacity block pt-2 border-t border-hack-border/30 mt-1">
<img src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black"
alt="Buy Me A Coffee" class="w-full badge-sm" />
</a>`;
}
}
// --- 2. THEME ENGINE --- // --- 2. THEME ENGINE ---
function initTheme() { function initTheme() {
const savedTheme = localStorage.getItem('theme') || 'dark'; const savedThemeId = localStorage.getItem('theme-id') || CONFIG.defaultTheme;
const html = document.documentElement; applyTheme(savedThemeId);
if (savedTheme === 'light') {
html.classList.remove('dark');
html.classList.add('light');
} else {
html.classList.add('dark');
html.classList.remove('light');
}
} }
function toggleTheme() { function applyTheme(themeId) {
const theme = CONFIG.themes.find(t => t.id === themeId) || CONFIG.themes[0];
const html = document.documentElement; const html = document.documentElement;
const isDark = html.classList.contains('dark'); const themeLink = document.getElementById('theme-link');
if (isDark) {
html.classList.remove('dark'); themeLink.href = theme.file;
html.classList.add('light');
localStorage.setItem('theme', 'light'); if (theme.isDark) {
} else {
html.classList.remove('light');
html.classList.add('dark'); html.classList.add('dark');
localStorage.setItem('theme', 'dark'); html.classList.remove('light');
} else {
html.classList.add('light');
html.classList.remove('dark');
} }
localStorage.setItem('theme-id', theme.id);
lucide.createIcons(); lucide.createIcons();
// Notify user (except on initial load)
if (STATE && STATE.wikiData && Object.keys(STATE.wikiData).length > 0) {
showToast(`${CONFIG.ui.themeChangedText}${theme.name}`);
}
} }
document.getElementById('theme-toggle-desktop').onclick = toggleTheme; function cycleTheme() {
document.getElementById('theme-toggle-mobile').onclick = toggleTheme; const currentThemeId = localStorage.getItem('theme-id') || CONFIG.defaultTheme;
const currentIndex = CONFIG.themes.findIndex(t => t.id === currentThemeId);
const nextIndex = (currentIndex + 1) % CONFIG.themes.length;
const nextTheme = CONFIG.themes[nextIndex];
applyTheme(nextTheme.id);
}
document.getElementById('theme-toggle-desktop').onclick = cycleTheme;
document.getElementById('theme-toggle-mobile').onclick = cycleTheme;
initTheme(); initTheme();
// --- 3. FETCH DATA (GitHub API) --- // --- 3. FETCH DATA (GitHub API) ---
async function fetchLatestVersion() { async function fetchLatestVersion() {
if (CONFIG.versioning.type === 'local') {
updateVersionUI(CONFIG.versioning.manualVersion, true);
return;
}
const CACHE_KEY = 'bjorn_ver_data'; const CACHE_KEY = 'bjorn_ver_data';
const now = Date.now(); const now = Date.now();
const ONE_HOUR = 3600 * 1000; const ONE_HOUR = 3600 * 1000;
@@ -912,6 +1143,14 @@
// --- 5. CONTENT LOADER (PERSISTENT CACHE OPTIMIZED) --- // --- 5. CONTENT LOADER (PERSISTENT CACHE OPTIMIZED) ---
async function loadContent(folder, title, filename, pushHistory = true) { async function loadContent(folder, title, filename, pushHistory = true) {
if (CONFIG.features.pageTransitions && document.startViewTransition) {
document.startViewTransition(() => performLoadContent(folder, title, filename, pushHistory));
} else {
performLoadContent(folder, title, filename, pushHistory);
}
}
async function performLoadContent(folder, title, filename, pushHistory = true) {
const viewer = document.getElementById('markdown-viewer'); const viewer = document.getElementById('markdown-viewer');
const pageNav = document.getElementById('page-nav'); const pageNav = document.getElementById('page-nav');
const scrollContainer = document.getElementById('scroll-container'); const scrollContainer = document.getElementById('scroll-container');
@@ -989,7 +1228,7 @@
viewer.innerHTML = cleanHTML; viewer.innerHTML = cleanHTML;
const wordCount = text.replace(/[#*`]/g, '').split(/\s+/).length; const wordCount = text.replace(/[#*`]/g, '').split(/\s+/).length;
document.getElementById('reading-time').textContent = `~${Math.ceil(wordCount / 200)} min read`; document.getElementById('reading-time').textContent = `${CONFIG.ui.readingTimePrefix}${Math.ceil(wordCount / 200)} ${CONFIG.ui.readingTimeSuffix}`;
fetchLastUpdated(folder, filename); fetchLastUpdated(folder, filename);
enhanceMarkdownContent(); enhanceMarkdownContent();
@@ -1001,7 +1240,11 @@
window.history.pushState({ folder, title, filename }, "", newUrl); window.history.pushState({ folder, title, filename }, "", newUrl);
} }
if (CONFIG.features.autoCollapseSidebar) {
STATE.expandedSections = new Set([folder]); STATE.expandedSections = new Set([folder]);
} else {
STATE.expandedSections.add(folder);
}
renderSidebar(); renderSidebar();
if (window.location.hash) { if (window.location.hash) {
const el = document.getElementById(window.location.hash.substring(1)); const el = document.getElementById(window.location.hash.substring(1));
@@ -1028,6 +1271,11 @@
} }
async function fetchLastUpdated(folder, filename) { async function fetchLastUpdated(folder, filename) {
if (CONFIG.versioning.type === 'local') {
document.getElementById('last-updated').textContent = `${CONFIG.ui.lastUpdatedText}: ${CONFIG.versioning.manualDate}`;
return;
}
const CACHE_KEY = `bjorn_upd_${folder}_${filename}`; const CACHE_KEY = `bjorn_upd_${folder}_${filename}`;
const now = Date.now(); const now = Date.now();
@@ -1035,7 +1283,7 @@
if (cached) { if (cached) {
const data = JSON.parse(cached); const data = JSON.parse(cached);
if (now - data.ts < 86400000) { if (now - data.ts < 86400000) {
document.getElementById('last-updated').textContent = `Updated: ${data.date}`; document.getElementById('last-updated').textContent = `${CONFIG.ui.lastUpdatedText}: ${data.date}`;
return; return;
} }
} }
@@ -1047,7 +1295,7 @@
const data = await res.json(); const data = await res.json();
if (data.length > 0) { if (data.length > 0) {
const date = new Date(data[0].commit.committer.date).toLocaleDateString(); const date = new Date(data[0].commit.committer.date).toLocaleDateString();
document.getElementById('last-updated').textContent = `Updated: ${date}`; document.getElementById('last-updated').textContent = `${CONFIG.ui.lastUpdatedText}: ${date}`;
localStorage.setItem(CACHE_KEY, JSON.stringify({ ts: now, date })); localStorage.setItem(CACHE_KEY, JSON.stringify({ ts: now, date }));
} }
} }
@@ -1080,7 +1328,7 @@
} }
function enhanceMarkdownContent() { function enhanceMarkdownContent() {
document.querySelectorAll('#markdown-viewer h2, #markdown-viewer h3').forEach(h => { document.querySelectorAll('#markdown-viewer h1, #markdown-viewer h2, #markdown-viewer h3').forEach(h => {
if (!h.id) h.id = h.textContent.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, ''); if (!h.id) h.id = h.textContent.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
const anchor = document.createElement('a'); const anchor = document.createElement('a');
@@ -1187,18 +1435,23 @@
function generateTOC() { function generateTOC() {
const desktopToc = document.getElementById('toc-container'); const desktopToc = document.getElementById('toc-container');
const mobileToc = document.getElementById('mobile-toc-list'); const mobileToc = document.getElementById('mobile-toc-list');
const headings = document.querySelectorAll('#markdown-viewer h2, #markdown-viewer h3'); const headings = document.querySelectorAll('#markdown-viewer h1, #markdown-viewer h2, #markdown-viewer h3');
const createTOCItem = (h, isMobile) => { const createTOCItem = (h, isMobile) => {
const li = document.createElement('li'); const li = document.createElement('li');
const link = document.createElement('a'); const link = document.createElement('a');
link.textContent = h.childNodes[0].textContent; link.textContent = h.childNodes[0].textContent;
link.href = `#${h.id}`; link.href = `#${h.id}`;
// Different styling for desktop vs mobile
// Indentation based on tag
let indentClass = '';
if (h.tagName === 'H2') indentClass = 'ml-3';
if (h.tagName === 'H3') indentClass = 'ml-6';
if (isMobile) { if (isMobile) {
link.className = `block py-2 text-gray-400 hover:text-hack-green border-l-2 border-transparent pl-3 transition-colors ${h.tagName === 'H3' ? 'ml-4 text-xs' : 'font-medium'}`; link.className = `block py-2 text-gray-400 hover:text-hack-green border-l-2 border-transparent pl-3 transition-colors ${indentClass} ${h.tagName !== 'H1' ? 'text-xs' : 'font-medium'}`;
} else { } else {
link.className = `toc-link block py-1 pl-2 border-l-2 border-transparent hover:text-hack-green transition-colors truncate ${h.tagName === 'H3' ? 'ml-3 opacity-80' : ''}`; link.className = `toc-link block py-1 pl-2 border-l-2 border-transparent hover:text-hack-green transition-colors truncate ${indentClass} ${h.tagName !== 'H1' ? 'opacity-80' : ''}`;
} }
link.onclick = (e) => { link.onclick = (e) => {
@@ -1216,8 +1469,8 @@
mobileToc.innerHTML = ''; mobileToc.innerHTML = '';
if (headings.length === 0) { if (headings.length === 0) {
desktopToc.innerHTML = '<li class="text-gray-600 italic">No sections</li>'; desktopToc.innerHTML = `<li class="text-gray-600 italic">${CONFIG.ui.noSectionsText}</li>`;
mobileToc.innerHTML = '<li class="text-gray-600 italic text-center py-4">No sections available for this page.</li>'; mobileToc.innerHTML = `<li class="text-gray-600 italic text-center py-4">${CONFIG.ui.noSectionsText}</li>`;
return; return;
} }
@@ -1225,6 +1478,86 @@
desktopToc.appendChild(createTOCItem(h, false)); desktopToc.appendChild(createTOCItem(h, false));
mobileToc.appendChild(createTOCItem(h, true)); mobileToc.appendChild(createTOCItem(h, true));
}); });
// Initial active state update
setTimeout(updateTOCActiveState, 100);
}
function updateTOCActiveState() {
const scrollContainer = document.getElementById('scroll-container');
const headings = Array.from(document.querySelectorAll('#markdown-viewer h1, #markdown-viewer h2, #markdown-viewer h3'));
const tocLinks = Array.from(document.querySelectorAll('.toc-link'));
const path = document.getElementById('toc-path');
if (!headings.length || !tocLinks.length || !path) return;
const containerRect = scrollContainer.getBoundingClientRect();
const buffer = 10; // Very small buffer for precision
// Find headings that are visible in the viewport
let activeHeadings = headings.filter(h => {
const rect = h.getBoundingClientRect();
const relativeTop = rect.top - containerRect.top;
const relativeBottom = rect.bottom - containerRect.top;
return (relativeTop < containerRect.height - buffer) && (relativeBottom > buffer);
});
// Fallback: if no heading is in view, use the last one that passed the top
if (activeHeadings.length === 0) {
const scrollPos = scrollContainer.scrollTop;
for (let i = headings.length - 1; i >= 0; i--) {
if (headings[i].offsetTop <= scrollPos + 100) {
activeHeadings.push(headings[i]);
break;
}
}
}
if (activeHeadings.length === 0) activeHeadings.push(headings[0]);
const activeIds = new Set(activeHeadings.map(h => h.id));
const activeLinks = [];
tocLinks.forEach(link => {
const id = link.getAttribute('href').substring(1);
if (activeIds.has(id)) {
link.classList.add('active');
activeLinks.push(link);
} else {
link.classList.remove('active');
}
});
if (activeLinks.length > 0) {
let d = "";
let lastIndex = -2;
activeLinks.forEach((link, index) => {
const id = link.getAttribute('href').substring(1);
const heading = document.getElementById(id);
const linkIndex = tocLinks.indexOf(link);
// X position based on indentation (relative to TOC container left border)
let x = -1; // Default for H1 (aligned with the left border)
if (heading.tagName === 'H2') x = 11; // H2 indented with ml-3 (12px)
else if (heading.tagName === 'H3') x = 23; // H3 indented with ml-6 (24px)
const yTop = link.offsetTop;
const yBottom = yTop + link.offsetHeight;
// If not contiguous with previous active link, start a new path segment
if (linkIndex !== lastIndex + 1) {
d += ` M ${x} ${yTop} L ${x} ${yBottom}`;
} else {
d += ` L ${x} ${yTop} L ${x} ${yBottom}`;
}
lastIndex = linkIndex;
});
path.setAttribute('d', d);
path.classList.add('active');
} else {
path.classList.remove('active');
}
} }
// --- 6. SIDEBAR --- // --- 6. SIDEBAR ---
@@ -1331,13 +1664,21 @@
// --- 8. CHANGELOG --- // --- 8. CHANGELOG ---
async function toggleVersionsPage(btn, pushHistory = true) { async function toggleVersionsPage(btn, pushHistory = true) {
if (CONFIG.features.pageTransitions && document.startViewTransition) {
document.startViewTransition(() => performToggleVersionsPage(btn, pushHistory));
} else {
performToggleVersionsPage(btn, pushHistory);
}
}
async function performToggleVersionsPage(btn, pushHistory = true) {
const viewer = document.getElementById('markdown-viewer'); const viewer = document.getElementById('markdown-viewer');
document.getElementById('breadcrumbs').innerHTML = `<span class="hover:text-hack-heading cursor-pointer" onclick="loadDefault()">Bjorn</span> <span>/</span> <span class="text-hack-green font-bold">Changelog</span>`; document.getElementById('breadcrumbs').innerHTML = `<span class="hover:text-hack-heading cursor-pointer" onclick="loadDefault()">${CONFIG.projectName}</span> <span>/</span> <span class="text-hack-green font-bold">${CONFIG.ui.changelogTitle}</span>`;
document.getElementById('page-nav').innerHTML = ''; document.getElementById('page-nav').innerHTML = '';
document.getElementById('reading-time').innerHTML = ''; document.getElementById('reading-time').innerHTML = '';
document.getElementById('last-updated').innerHTML = ''; document.getElementById('last-updated').innerHTML = '';
viewer.innerHTML = `<h1>Changelog</h1><div id="versions-list" class="space-y-4 mt-6"><div class="animate-pulse text-hack-green">Fetching GitHub releases...</div></div>`; viewer.innerHTML = `<h1>${CONFIG.ui.changelogTitle}</h1><div id="versions-list" class="space-y-4 mt-6"><div class="animate-pulse text-hack-green">${CONFIG.ui.fetchingReleasesText}</div></div>`;
if (pushHistory) window.history.pushState({ page: 'versions' }, "", "?page=changelog"); if (pushHistory) window.history.pushState({ page: 'versions' }, "", "?page=changelog");
try { try {
@@ -1462,6 +1803,8 @@
if (scrollTop > 300) scrollBtn.classList.remove('hidden'); if (scrollTop > 300) scrollBtn.classList.remove('hidden');
else scrollBtn.classList.add('hidden'); else scrollBtn.classList.add('hidden');
updateTOCActiveState();
}); });
} }
if (scrollBtn) { if (scrollBtn) {
@@ -1553,6 +1896,7 @@
// INIT // INIT
window.onload = () => { window.onload = () => {
applyConfig();
initUI(); initUI();
fetchLatestVersion(); fetchLatestVersion();
initWiki(); initWiki();

35
themes/cyberpunk.css Normal file
View File

@@ -0,0 +1,35 @@
:root {
--bg-body: #0D0221;
--bg-sidebar: #190033;
--border-color: #FF007F;
--text-main: #E0E0E0;
--text-heading: #00FFFF;
--accent-green: #FF007F;
--accent-dim: rgba(255, 0, 127, 0.1);
--code-bg: #1A0033;
}
/* Override scrollbar and other elements to use neon pink */
::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, #FF007F, var(--border-color)) !important;
}
.text-hack-green {
color: #FF007F !important;
}
.bg-hack-greenDim {
background-color: rgba(255, 0, 127, 0.1) !important;
}
.border-hack-green {
border-color: #FF007F !important;
}
.markdown-body a {
color: #00FFFF !important;
}
.markdown-body a:hover {
border-bottom-color: #00FFFF !important;
}

15
themes/dark.css Normal file
View File

@@ -0,0 +1,15 @@
:root {
--bg-body: #0B0C0E;
--bg-sidebar: #111214;
--border-color: #2A2E35;
--text-main: #A0AAB8;
--text-heading: #E2E8F0;
--accent-green: #22c55e;
--accent-dim: rgba(34, 197, 94, 0.1);
--code-bg: #1e1e1e;
}
/* Compatibility with tailwind colors if needed */
.dark {
--accent-green: #22c55e;
}

28
themes/electric-blue.css Normal file
View File

@@ -0,0 +1,28 @@
:root {
--bg-body: #050A15;
--bg-sidebar: #0A1225;
--border-color: #1E2D4A;
--text-main: #94A3B8;
--text-heading: #F8FAFC;
--accent-green: #38BDF8;
/* Electric Blue */
--accent-dim: rgba(56, 189, 248, 0.1);
--code-bg: #0F172A;
}
/* Override scrollbar and other elements to use blue */
::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, #38BDF8, var(--border-color)) !important;
}
.text-hack-green {
color: #38BDF8 !important;
}
.bg-hack-greenDim {
background-color: rgba(56, 189, 248, 0.1) !important;
}
.border-hack-green {
border-color: #38BDF8 !important;
}

27
themes/forest.css Normal file
View File

@@ -0,0 +1,27 @@
:root {
--bg-body: #1B261B;
--bg-sidebar: #243024;
--border-color: #3E523E;
--text-main: #D1D5D1;
--text-heading: #A7C957;
--accent-green: #6A994E;
--accent-dim: rgba(106, 153, 78, 0.1);
--code-bg: #2D3A2D;
}
/* Override scrollbar and other elements */
::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, #6A994E, var(--border-color)) !important;
}
.text-hack-green {
color: #6A994E !important;
}
.bg-hack-greenDim {
background-color: rgba(106, 153, 78, 0.1) !important;
}
.border-hack-green {
border-color: #6A994E !important;
}

55
themes/glassmorphism.css Normal file
View File

@@ -0,0 +1,55 @@
:root {
--bg-body: #0f172a;
--bg-sidebar: rgba(30, 41, 59, 0.7);
--border-color: rgba(255, 255, 255, 0.1);
--text-main: #e2e8f0;
--text-heading: #f8fafc;
--accent-green: #38bdf8;
--accent-dim: rgba(56, 189, 248, 0.1);
--code-bg: rgba(15, 23, 42, 0.8);
}
/* Glassmorphism theme specific overrides */
body {
background: radial-gradient(circle at top left, #1e293b, #0f172a);
background-attachment: fixed;
}
#sidebar,
#mobile-toc-sidebar {
background: rgba(30, 41, 59, 0.6) !important;
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-right: 1px solid rgba(255, 255, 255, 0.1);
}
#markdown-viewer {
background: rgba(30, 41, 59, 0.4);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 2rem;
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
}
.nav-link.active {
background: rgba(56, 189, 248, 0.2) !important;
border-left: 4px solid #38bdf8 !important;
color: #38bdf8 !important;
box-shadow: 0 0 15px rgba(56, 189, 248, 0.3);
}
.markdown-body a {
color: #38bdf8;
text-shadow: 0 0 8px rgba(56, 189, 248, 0.5);
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.1) !important;
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.2) !important;
}

32
themes/light.css Normal file
View File

@@ -0,0 +1,32 @@
:root {
--bg-body: #1E293B;
/* Slate 800 */
--bg-sidebar: #0F172A;
/* Slate 900 */
--border-color: #334155;
/* Slate 700 */
--text-main: #94A3B8;
/* Slate 400 */
--text-heading: #F1F5F9;
/* Slate 100 */
--accent-green: #10B981;
/* Emerald 500 */
--accent-dim: rgba(16, 185, 129, 0.1);
--code-bg: #020617;
/* Slate 950 */
}
/* Compatibility with tailwind colors if needed */
.dark {
--accent-green: #10B981;
}
/* Specific overrides for Dim mode to ensure readability */
.markdown-body blockquote {
background: rgba(16, 185, 129, 0.05) !important;
border-left-color: #10B981 !important;
}
.text-hack-green {
color: #10B981 !important;
}

27
themes/monochrome.css Normal file
View File

@@ -0,0 +1,27 @@
:root {
--bg-body: #121212;
--bg-sidebar: #1E1E1E;
--border-color: #333333;
--text-main: #BBBBBB;
--text-heading: #FFFFFF;
--accent-green: #FFFFFF;
--accent-dim: rgba(255, 255, 255, 0.1);
--code-bg: #000000;
}
/* Override scrollbar and other elements */
::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, #FFFFFF, var(--border-color)) !important;
}
.text-hack-green {
color: #FFFFFF !important;
}
.bg-hack-greenDim {
background-color: rgba(255, 255, 255, 0.1) !important;
}
.border-hack-green {
border-color: #FFFFFF !important;
}

52
themes/nature.css Normal file
View File

@@ -0,0 +1,52 @@
:root {
--bg-body: #f7f3e9;
--bg-sidebar: #e8e1d1;
--border-color: #d1c7b1;
--text-main: #3e442b;
--text-heading: #2d3319;
--accent-green: #606c38;
--accent-dim: rgba(96, 108, 56, 0.1);
--code-bg: #fefae0;
}
/* Nature theme specific overrides */
body {
background-color: var(--bg-body);
color: var(--text-main);
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3 {
color: #283618;
font-weight: 700;
}
.markdown-body a {
color: #bc6c25;
}
.markdown-body a:hover {
border-bottom-color: #dda15e;
}
#sidebar,
#mobile-toc-sidebar {
background-color: #e8e1d1 !important;
border-right: 1px solid #d1c7b1;
}
.nav-link.active {
background-color: rgba(96, 108, 56, 0.15) !important;
border-left-color: #606c38 !important;
color: #283618 !important;
}
::-webkit-scrollbar-thumb {
background: #dda15e !important;
}
.markdown-body blockquote {
background: #fefae0;
border-left-color: #606c38;
}

25
themes/nord-light.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--bg-body: #eceff4;
--bg-sidebar: #e5e9f0;
--border-color: #d8dee9;
--text-main: #4c566a;
--text-heading: #2e3440;
--accent-green: #88c0d0;
--accent-dim: rgba(136, 192, 208, 0.1);
--code-bg: #d8dee9;
}
/* Nord Light specific overrides */
.markdown-body a {
color: #5e81ac;
}
.nav-link.active {
background-color: rgba(136, 192, 208, 0.1) !important;
border-left-color: #88c0d0 !important;
color: #5e81ac !important;
}
::-webkit-scrollbar-thumb {
background: #d8dee9 !important;
}

25
themes/paper-cool.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--bg-body: #e8f1f2;
--bg-sidebar: #d1e3e5;
--border-color: #b8d0d2;
--text-main: #2d4a4d;
--text-heading: #1a3033;
--accent-green: #0081a7;
--accent-dim: rgba(0, 129, 167, 0.1);
--code-bg: #d9e8ea;
}
/* Cool Paper specific overrides */
.markdown-body a {
color: #0081a7;
}
.nav-link.active {
background-color: rgba(0, 129, 167, 0.1) !important;
border-left-color: #0081a7 !important;
color: #2d4a4d !important;
}
::-webkit-scrollbar-thumb {
background: #b8d0d2 !important;
}

25
themes/paper-sepia.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--bg-body: #e3d5b8;
--bg-sidebar: #d4c3a1;
--border-color: #c4b28f;
--text-main: #4a3a2a;
--text-heading: #2d241a;
--accent-green: #8b5e34;
--accent-dim: rgba(139, 94, 52, 0.1);
--code-bg: #dcd0b0;
}
/* Sepia Paper specific overrides */
.markdown-body a {
color: #8b5e34;
}
.nav-link.active {
background-color: rgba(139, 94, 52, 0.1) !important;
border-left-color: #8b5e34 !important;
color: #4a3a2a !important;
}
::-webkit-scrollbar-thumb {
background: #c4b28f !important;
}

54
themes/paper.css Normal file
View File

@@ -0,0 +1,54 @@
:root {
--bg-body: #fdfcf0;
--bg-sidebar: #f4f1ea;
--border-color: #e6e2d3;
--text-main: #444444;
--text-heading: #222222;
--accent-green: #d4a373;
--accent-dim: rgba(212, 163, 115, 0.1);
--code-bg: #f8f5ed;
}
/* Light theme specific overrides */
body {
background-color: var(--bg-body);
color: var(--text-main);
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3 {
color: var(--text-heading);
}
.markdown-body a {
color: #bc6c25;
}
.markdown-body a:hover {
border-bottom-color: #bc6c25;
}
#sidebar,
#mobile-toc-sidebar {
background-color: var(--bg-sidebar) !important;
border-color: var(--border-color);
}
.nav-link:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.nav-link.active {
background-color: var(--accent-dim) !important;
border-left-color: var(--accent-green) !important;
color: #bc6c25 !important;
}
::-webkit-scrollbar-thumb {
background: var(--border-color) !important;
}
::-webkit-scrollbar-thumb:hover {
background: var(--accent-green) !important;
}

106
themes/retro-acid-burn.css Normal file
View File

@@ -0,0 +1,106 @@
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap');
:root {
--bg-body: #000000;
--bg-sidebar: #050505;
--border-color: #00ff41;
--text-main: #00ff41;
--text-heading: #d4ff00;
--accent-green: #00ff41;
--accent-dim: rgba(0, 255, 65, 0.1);
--code-bg: #0a0a0a;
/* Acid Burn Specific */
--acid-yellow: #d4ff00;
--acid-green: #00ff41;
}
/* --- PHOSPHOR GLOW --- */
body {
font-family: 'JetBrains Mono', monospace !important;
background-color: #000 !important;
color: var(--text-main) !important;
text-shadow: 0 0 5px rgba(0, 255, 65, 0.5);
}
/* --- SCANLINES (Static but intense) --- */
body::after {
content: " ";
display: block;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%);
z-index: 9999;
background-size: 100% 4px;
pointer-events: none;
opacity: 0.3;
}
/* --- TYPOGRAPHY --- */
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--acid-yellow) !important;
text-shadow: 0 0 10px var(--acid-yellow);
text-transform: uppercase;
letter-spacing: 2px;
}
.markdown-body h1 {
border-bottom-color: var(--acid-yellow) !important;
}
.markdown-body strong {
color: #fff !important;
text-shadow: 0 0 8px #fff;
}
.markdown-body a {
color: var(--acid-yellow) !important;
text-decoration: underline;
text-underline-offset: 4px;
}
.markdown-body a:hover {
color: #fff !important;
text-shadow: 0 0 10px var(--acid-yellow);
}
/* --- UI OVERRIDES --- */
#sidebar,
#mobile-toc-sidebar {
background-color: #050505 !important;
border-right: 2px solid var(--accent-green);
}
.nav-link.active {
background-color: rgba(0, 255, 65, 0.2) !important;
border-left: 4px solid var(--accent-green) !important;
color: #fff !important;
}
.nav-link:hover {
color: #fff !important;
background-color: rgba(0, 255, 65, 0.1);
}
::-webkit-scrollbar-thumb {
background: var(--accent-green) !important;
box-shadow: 0 0 10px var(--accent-green);
}
/* --- CODE BLOCKS --- */
.markdown-body pre {
border: 1px solid var(--accent-green) !important;
box-shadow: 0 0 15px rgba(0, 255, 65, 0.2);
}
.markdown-body code {
color: var(--acid-yellow) !important;
}

130
themes/retro-hackers-w.css Normal file
View File

@@ -0,0 +1,130 @@
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&family=JetBrains+Mono:wght@400;700&display=swap');
:root {
--bg-body: #050505;
--bg-sidebar: rgba(5, 5, 5, 0.8);
--border-color: #13aff0;
--text-main: #80ff80;
--text-heading: #13aff0;
--accent-green: #0f0;
--accent-dim: rgba(0, 255, 0, 0.1);
--code-bg: #000;
/* Hacker Specific */
--neon-blue: #13aff0;
--neon-orange: #FF6B00;
--neon-purple: #bd00ff;
}
/* --- THE 3D GRID --- */
body::before {
content: "";
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) perspective(600px) rotateX(60deg);
width: 300vw;
height: 300vh;
background-image:
linear-gradient(rgba(0, 243, 255, 0.3) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 243, 255, 0.3) 1px, transparent 1px);
background-size: 60px 60px;
animation: grid-scroll 11s linear infinite;
z-index: -1;
pointer-events: none;
-webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 80%);
mask-image: linear-gradient(to top, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 80%);
}
@keyframes grid-scroll {
0% {
background-position: 0 0;
}
100% {
background-position: 0 60px;
}
}
/* --- SCANLINES --- */
body::after {
content: " ";
display: block;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background:
linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.1) 50%),
linear-gradient(90deg, rgba(255, 0, 0, 0.02), rgba(0, 255, 0, 0.01), rgba(0, 0, 255, 0.02));
z-index: 9999;
background-size: 100% 3px, 3px 100%;
pointer-events: none;
opacity: 0.4;
}
/* --- TYPOGRAPHY --- */
body {
font-family: 'JetBrains Mono', monospace !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Cinzel', serif !important;
text-transform: uppercase;
text-shadow: 0 0 10px var(--neon-blue);
}
.markdown-body h1 {
color: var(--neon-blue) !important;
border-bottom-color: var(--neon-blue) !important;
}
.markdown-body h2 {
color: var(--neon-orange) !important;
text-shadow: 0 0 10px var(--neon-orange);
}
.markdown-body h3 {
color: var(--neon-purple) !important;
text-shadow: 0 0 10px var(--neon-purple);
}
.markdown-body strong {
color: #fff !important;
text-shadow: 0 0 8px rgba(255, 255, 255, 0.8);
}
.markdown-body a {
color: var(--neon-purple) !important;
border-bottom: 1px dashed var(--neon-purple);
}
.markdown-body a:hover {
color: #fff !important;
text-shadow: 0 0 5px var(--neon-purple);
border-bottom-style: solid;
}
/* --- UI OVERRIDES --- */
#sidebar,
#mobile-toc-sidebar {
background-color: var(--bg-sidebar) !important;
backdrop-filter: blur(10px);
}
.nav-link.active {
background-color: rgba(19, 175, 240, 0.2) !important;
border-left-color: var(--neon-blue) !important;
color: var(--neon-blue) !important;
}
::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, var(--neon-blue), #000) !important;
border: 1px solid var(--neon-blue);
}

149
themes/retro-hackers.css Normal file
View File

@@ -0,0 +1,149 @@
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&family=JetBrains+Mono:wght@400;700&display=swap');
:root {
--bg-body: #050505;
--bg-sidebar: rgba(5, 5, 5, 0.8);
--border-color: #13aff0;
--text-main: #80ff80;
--text-heading: #13aff0;
--accent-green: #0f0;
--accent-dim: rgba(0, 255, 0, 0.1);
--code-bg: #000;
/* Hacker Specific */
--neon-blue: #13aff0;
--neon-orange: #FF6B00;
--neon-purple: #bd00ff;
}
/* --- THE 3D GRID --- */
body::before {
content: "";
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) perspective(600px) rotateX(60deg);
width: 300vw;
height: 300vh;
background-image:
linear-gradient(rgba(0, 243, 255, 0.5) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 243, 255, 0.5) 1px, transparent 1px);
background-size: 60px 60px;
animation: grid-scroll 11s linear infinite;
z-index: -1;
pointer-events: none;
-webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 80%);
mask-image: linear-gradient(to top, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 80%);
}
@keyframes grid-scroll {
0% {
background-position: 0 0;
}
100% {
background-position: 0 60px;
}
}
/* --- TRANSPARENCY OVERRIDES --- */
#scroll-container,
main,
.bg-hack-bg,
.bg-hack-sidebar,
#markdown-viewer {
background-color: transparent !important;
}
/* Sidebar needs some background for readability but should be semi-transparent */
#sidebar,
#mobile-toc-sidebar {
background-color: rgba(5, 5, 5, 0.85) !important;
backdrop-filter: blur(8px);
border-right: 1px solid var(--neon-blue);
}
/* Content area readability - using a very subtle overlay if needed, but keeping it transparent as requested */
#markdown-viewer {
padding: 2rem;
border-radius: 12px;
border: 1px solid rgba(19, 175, 240, 0.1);
}
/* --- SCANLINES --- */
body::after {
content: " ";
display: block;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background:
linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.15) 50%),
linear-gradient(90deg, rgba(255, 0, 0, 0.03), rgba(0, 255, 0, 0.01), rgba(0, 0, 255, 0.03));
z-index: 9999;
background-size: 100% 3px, 3px 100%;
pointer-events: none;
opacity: 0.6;
}
/* --- TYPOGRAPHY --- */
body {
font-family: 'JetBrains Mono', monospace !important;
background-color: #050505 !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Cinzel', serif !important;
text-transform: uppercase;
text-shadow: 0 0 10px var(--neon-blue);
}
.markdown-body h1 {
color: var(--neon-blue) !important;
border-bottom-color: var(--neon-blue) !important;
}
.markdown-body h2 {
color: var(--neon-orange) !important;
text-shadow: 0 0 10px var(--neon-orange);
}
.markdown-body h3 {
color: var(--neon-purple) !important;
text-shadow: 0 0 10px var(--neon-purple);
}
.markdown-body strong {
color: #fff !important;
text-shadow: 0 0 8px rgba(255, 255, 255, 0.8);
}
.markdown-body a {
color: var(--neon-purple) !important;
border-bottom: 1px dashed var(--neon-purple);
}
.markdown-body a:hover {
color: #fff !important;
text-shadow: 0 0 5px var(--neon-purple);
border-bottom-style: solid;
}
/* --- UI OVERRIDES --- */
.nav-link.active {
background-color: rgba(19, 175, 240, 0.2) !important;
border-left-color: var(--neon-blue) !important;
color: var(--neon-blue) !important;
}
::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, var(--neon-blue), #000) !important;
border: 1px solid var(--neon-blue);
}

70
themes/retro-irc.css Normal file
View File

@@ -0,0 +1,70 @@
:root {
--bg-body: #ffffff;
--bg-sidebar: #f0f0f0;
--border-color: #c0c0c0;
--text-main: #000000;
--text-heading: #000080;
--accent-green: #008000;
--accent-dim: rgba(0, 128, 0, 0.1);
--code-bg: #ffffff;
}
/* Retro IRC specific overrides */
body {
font-family: "Fixedsys", "Courier New", monospace !important;
background-color: var(--bg-body);
color: var(--text-main);
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3 {
color: #000080;
font-weight: bold;
border-bottom: 2px solid #000080;
}
.markdown-body a {
color: #0000ff;
text-decoration: underline;
}
.markdown-body a:hover {
color: #ff0000;
}
#sidebar,
#mobile-toc-sidebar {
background-color: #c0c0c0 !important;
border-right: 2px solid #808080;
}
.nav-link {
color: #000 !important;
border: 1px solid transparent;
}
.nav-link:hover {
background-color: #000080 !important;
color: #fff !important;
}
.nav-link.active {
background-color: #000080 !important;
color: #fff !important;
border-left: 4px solid #ff0000 !important;
}
::-webkit-scrollbar-thumb {
background: #808080 !important;
border: 1px solid #ffffff;
}
.markdown-body pre {
border: 1px solid #808080 !important;
background-color: #f0f0f0 !important;
}
.markdown-body code {
color: #800000 !important;
}

View File

@@ -0,0 +1,30 @@
:root {
--bg-body: #fdf6e3;
--bg-sidebar: #eee8d5;
--border-color: #d5c4a1;
--text-main: #657b83;
--text-heading: #073642;
--accent-green: #859900;
--accent-dim: rgba(133, 153, 0, 0.1);
--code-bg: #eee8d5;
}
/* Solarized Light specific overrides */
.markdown-body a {
color: #268bd2;
}
.markdown-body blockquote {
background: #eee8d5;
border-left-color: #859900;
}
.nav-link.active {
background-color: rgba(133, 153, 0, 0.1) !important;
border-left-color: #859900 !important;
color: #859900 !important;
}
::-webkit-scrollbar-thumb {
background: #93a1a1 !important;
}