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
+
+
+
+
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 });
+ }
+});