From c152cacb9006afe2e422c27dd989cf03a34da222 Mon Sep 17 00:00:00 2001 From: ARCHITECT Date: Sat, 17 Jan 2026 23:28:09 +0000 Subject: [PATCH] Add PIN lock screen and block search engines DECK and HST frontends: - Add 4-digit PIN lock screen (default: 1234) - PIN stored in sessionStorage (persists during browser session) - Keypad with keyboard support - Add meta robots noindex/nofollow tags - Created robots.txt to disallow all crawlers Security note: This is client-side only, not cryptographically secure, but sufficient to prevent casual access and search engine indexing. Co-Authored-By: Claude Opus 4.5 --- deck-frontend/deck-v4.6.html | 182 +++++++++++++++++++++++++++++++++- hst-frontend/index.html | 184 ++++++++++++++++++++++++++++++++++- 2 files changed, 363 insertions(+), 3 deletions(-) diff --git a/deck-frontend/deck-v4.6.html b/deck-frontend/deck-v4.6.html index fac38f7..c549352 100644 --- a/deck-frontend/deck-v4.6.html +++ b/deck-frontend/deck-v4.6.html @@ -5,6 +5,8 @@ deck + + +
+ +
+
+
+
+
+
+
+ + + + + + + + + + + + +
+
+ @@ -730,6 +810,91 @@ body { * EventBus pattern for module decoupling */ +// ============================================================================= +// 0. LOCK SCREEN +// ============================================================================= +const Lock = { + PIN: "1234", // PIN code - can be changed + entered: "", + + init() { + if (sessionStorage.getItem("deck_unlocked") === "true") { + this.unlock(); + return true; + } + this.bind(); + return false; + }, + + bind() { + const keypad = document.querySelector(".lock-keypad"); + if (!keypad) return; + + keypad.addEventListener("click", (e) => { + const key = e.target.closest(".lock-key"); + if (!key) return; + + const value = key.dataset.key; + if (value === "back") { + this.entered = this.entered.slice(0, -1); + } else if (value && this.entered.length < 4) { + this.entered += value; + } + + this.updateDots(); + + if (this.entered.length === 4) { + setTimeout(() => this.check(), 150); + } + }); + + // Keyboard support + document.addEventListener("keydown", (e) => { + if (document.getElementById("lock-screen")?.classList.contains("hidden")) return; + + if (e.key >= "0" && e.key <= "9" && this.entered.length < 4) { + this.entered += e.key; + this.updateDots(); + if (this.entered.length === 4) setTimeout(() => this.check(), 150); + } else if (e.key === "Backspace") { + this.entered = this.entered.slice(0, -1); + this.updateDots(); + } + }); + }, + + updateDots() { + const dots = document.querySelectorAll(".lock-dot"); + dots.forEach((dot, i) => { + dot.classList.toggle("filled", i < this.entered.length); + dot.classList.remove("error"); + }); + }, + + check() { + if (this.entered === this.PIN) { + sessionStorage.setItem("deck_unlocked", "true"); + this.unlock(); + } else { + this.showError(); + } + }, + + showError() { + const dots = document.querySelectorAll(".lock-dot"); + dots.forEach(dot => dot.classList.add("error")); + setTimeout(() => { + this.entered = ""; + this.updateDots(); + }, 500); + }, + + unlock() { + const screen = document.getElementById("lock-screen"); + if (screen) screen.classList.add("hidden"); + } +}; + // ============================================================================= // 1. CONFIG // ============================================================================= @@ -1678,7 +1843,22 @@ const App = { } }; -document.addEventListener("DOMContentLoaded", () => App.init()); +document.addEventListener("DOMContentLoaded", () => { + const unlocked = Lock.init(); + if (unlocked) { + App.init(); + } else { + // Watch for unlock to init app + const observer = new MutationObserver((mutations) => { + const screen = document.getElementById("lock-screen"); + if (screen?.classList.contains("hidden")) { + observer.disconnect(); + App.init(); + } + }); + observer.observe(document.getElementById("lock-screen"), { attributes: true }); + } +}); diff --git a/hst-frontend/index.html b/hst-frontend/index.html index bc5eccd..102f425 100644 --- a/hst-frontend/index.html +++ b/hst-frontend/index.html @@ -4,7 +4,9 @@ hst - + + + +
+ +
+
+
+
+
+
+
+ + + + + + + + + + + + +
+
+ @@ -713,6 +793,91 @@ body { * EventBus pattern for module decoupling */ +// ============================================================================= +// 0. LOCK SCREEN +// ============================================================================= +const Lock = { + PIN: "1234", // PIN code - can be changed + entered: "", + + init() { + if (sessionStorage.getItem("hst_unlocked") === "true") { + this.unlock(); + return true; + } + this.bind(); + return false; + }, + + bind() { + const keypad = document.querySelector(".lock-keypad"); + if (!keypad) return; + + keypad.addEventListener("click", (e) => { + const key = e.target.closest(".lock-key"); + if (!key) return; + + const value = key.dataset.key; + if (value === "back") { + this.entered = this.entered.slice(0, -1); + } else if (value && this.entered.length < 4) { + this.entered += value; + } + + this.updateDots(); + + if (this.entered.length === 4) { + setTimeout(() => this.check(), 150); + } + }); + + // Keyboard support + document.addEventListener("keydown", (e) => { + if (document.getElementById("lock-screen")?.classList.contains("hidden")) return; + + if (e.key >= "0" && e.key <= "9" && this.entered.length < 4) { + this.entered += e.key; + this.updateDots(); + if (this.entered.length === 4) setTimeout(() => this.check(), 150); + } else if (e.key === "Backspace") { + this.entered = this.entered.slice(0, -1); + this.updateDots(); + } + }); + }, + + updateDots() { + const dots = document.querySelectorAll(".lock-dot"); + dots.forEach((dot, i) => { + dot.classList.toggle("filled", i < this.entered.length); + dot.classList.remove("error"); + }); + }, + + check() { + if (this.entered === this.PIN) { + sessionStorage.setItem("hst_unlocked", "true"); + this.unlock(); + } else { + this.showError(); + } + }, + + showError() { + const dots = document.querySelectorAll(".lock-dot"); + dots.forEach(dot => dot.classList.add("error")); + setTimeout(() => { + this.entered = ""; + this.updateDots(); + }, 500); + }, + + unlock() { + const screen = document.getElementById("lock-screen"); + if (screen) screen.classList.add("hidden"); + } +}; + // ============================================================================= // 1. CONFIG // ============================================================================= @@ -1645,7 +1810,22 @@ const App = { } }; -document.addEventListener("DOMContentLoaded", () => App.init()); +document.addEventListener("DOMContentLoaded", () => { + const unlocked = Lock.init(); + if (unlocked) { + App.init(); + } else { + // Watch for unlock to init app + const observer = new MutationObserver((mutations) => { + const screen = document.getElementById("lock-screen"); + if (screen?.classList.contains("hidden")) { + observer.disconnect(); + App.init(); + } + }); + observer.observe(document.getElementById("lock-screen"), { attributes: true }); + } +});