From a9da7393c736684f8e90b2eae7cb1e5759b1e11a Mon Sep 17 00:00:00 2001 From: Perplexity Computer Date: Thu, 19 Mar 2026 01:46:04 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Workshop=20interaction=20layer=20?= =?UTF-8?q?=E2=80=94=20chat=20input,=20visitor=20presence,=20bark=20displa?= =?UTF-8?q?y=20(#40,=20#41,=20#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements the minimum viable conversation loop for Workshop #222: visitor arrives → sends message → Timmy barks back. - js/visitor.js: Visitor presence protocol (#41) - visitor_entered on load (with device detection: ipad/desktop/mobile) - visitor_left on unload or 30s hidden (iPad tab suspend) - visitor_message dispatched from chat input - visitor_interaction export for future tap-to-interact (#44) - Session duration tracking - js/bark.js: Bark display system (#42) - showBark() renders prominent viewport toasts with typing animation - Auto-dismiss after display time + typing duration - Queue system (max 3 simultaneous, overflow queued) - Demo barks in mock mode (Workshop-themed: 222, sovereignty, chain) - Barks also logged permanently in chat panel - index.html: Chat input bar (#40) - Terminal-styled input + send button at viewport bottom - Enter to send (desktop), button tap (iPad) - Safe-area padding for notched devices - Chat panel repositioned above input bar - Bark container in upper viewport third - js/websocket.js: New message handlers - 'bark' message → showBark() dispatch - 'ambient_state' message → placeholder for #43 - Demo barks start in mock mode - js/ui.js: appendChatMessage() accepts optional CSS class - Visitor messages styled differently from agent messages Build: 18 modules, 0 errors Tested: desktop (1280x800) + mobile (390x844) via Playwright Closes #40, #41, #42 Ref: rockachopa/Timmy-time-dashboard#222, #243 --- index.html | 100 ++++++++++++++++++++++++++++++++-- js/bark.js | 139 +++++++++++++++++++++++++++++++++++++++++++++++ js/main.js | 2 + js/ui.js | 4 +- js/visitor.js | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ js/websocket.js | 29 ++++++++++ 6 files changed, 408 insertions(+), 7 deletions(-) create mode 100644 js/bark.js create mode 100644 js/visitor.js diff --git a/index.html b/index.html index a72039e..3551141 100644 --- a/index.html +++ b/index.html @@ -48,16 +48,101 @@ } #status-panel .label { color: #007722; } #chat-panel { - position: fixed; bottom: 16px; left: 16px; right: 16px; - max-height: 180px; overflow-y: auto; + position: fixed; bottom: 52px; left: 16px; right: 16px; + max-height: 150px; overflow-y: auto; color: #00ff41; font-size: clamp(9px, 1.2vw, 12px); line-height: 1.6; text-shadow: 0 0 4px #00ff41; pointer-events: none; } .chat-entry { opacity: 0.8; } .chat-entry .agent-name { color: #00ff88; font-weight: bold; } + .chat-entry.visitor { opacity: 1; } + .chat-entry.visitor .agent-name { color: #888; } + + /* ── Chat input (#40) ── */ + #chat-input-bar { + position: fixed; bottom: 0; left: 0; right: 0; + display: flex; align-items: center; gap: 8px; + padding: 8px 16px; + padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px)); + background: rgba(0, 0, 0, 0.85); + border-top: 1px solid #003300; + z-index: 20; + pointer-events: auto; + } + #chat-input { + flex: 1; + background: rgba(0, 20, 0, 0.6); + border: 1px solid #003300; + color: #00ff41; + font-family: 'Courier New', monospace; + font-size: clamp(12px, 1.5vw, 14px); + padding: 8px 12px; + border-radius: 2px; + outline: none; + caret-color: #00ff41; + } + #chat-input::placeholder { color: #004400; } + #chat-input:focus { border-color: #00ff41; box-shadow: 0 0 8px rgba(0, 255, 65, 0.2); } + #chat-send { + background: transparent; + border: 1px solid #003300; + color: #00ff41; + font-family: 'Courier New', monospace; + font-size: 14px; + padding: 8px 16px; + cursor: pointer; + border-radius: 2px; + pointer-events: auto; + text-shadow: 0 0 6px #00ff41; + transition: all 0.15s; + } + #chat-send:hover, #chat-send:active { background: rgba(0, 255, 65, 0.1); border-color: #00ff41; } + + /* ── Bark display (#42) ── */ + #bark-container { + position: fixed; + top: 20%; left: 50%; + transform: translateX(-50%); + max-width: 600px; width: 90%; + z-index: 15; + pointer-events: none; + display: flex; flex-direction: column; align-items: center; gap: 8px; + } + .bark { + background: rgba(0, 10, 0, 0.85); + border: 1px solid #003300; + border-left: 3px solid #00ff41; + padding: 12px 20px; + color: #00ff41; + font-family: 'Courier New', monospace; + font-size: clamp(13px, 1.8vw, 16px); + line-height: 1.5; + text-shadow: 0 0 8px #00ff41; + opacity: 0; + animation: barkIn 0.4s ease-out forwards; + max-width: 100%; + } + .bark .bark-agent { + font-size: clamp(9px, 1vw, 11px); + color: #007722; + margin-bottom: 4px; + letter-spacing: 2px; + } + .bark.fade-out { + animation: barkOut 0.6s ease-in forwards; + } + @keyframes barkIn { + from { opacity: 0; transform: translateY(-8px); } + to { opacity: 1; transform: translateY(0); } + } + @keyframes barkOut { + from { opacity: 1; transform: translateY(0); } + to { opacity: 0; transform: translateY(-8px); } + } + #connection-status { - position: fixed; bottom: 16px; right: 16px; + position: fixed; bottom: 52px; right: 16px; font-size: clamp(9px, 1.2vw, 12px); color: #555; } #connection-status.connected { color: #00ff41; text-shadow: 0 0 6px #00ff41; } @@ -66,8 +151,8 @@ @supports (padding: env(safe-area-inset-top)) { #hud { top: calc(16px + env(safe-area-inset-top)); left: calc(16px + env(safe-area-inset-left)); } #status-panel { top: calc(16px + env(safe-area-inset-top)); right: calc(16px + env(safe-area-inset-right)); } - #chat-panel { bottom: calc(16px + env(safe-area-inset-bottom)); left: calc(16px + env(safe-area-inset-left)); right: calc(16px + env(safe-area-inset-right)); } - #connection-status { bottom: calc(16px + env(safe-area-inset-bottom)); right: calc(16px + env(safe-area-inset-right)); } + #chat-panel { bottom: calc(52px + env(safe-area-inset-bottom)); left: calc(16px + env(safe-area-inset-left)); right: calc(16px + env(safe-area-inset-right)); } + #connection-status { bottom: calc(52px + env(safe-area-inset-bottom)); right: calc(16px + env(safe-area-inset-right)); } } /* Stack status panel below HUD on narrow viewports (must come AFTER @supports) */ @@ -89,8 +174,13 @@
+
OFFLINE
+
+ + +