diff --git a/README.md b/README.md index defbf08..d8c44bc 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The repository also contains the original standalone | --- | --- | --- | | `backend/` | FastAPI service: credentials in memory, Confluence/model upstreams, authoritative tool history, container lifecycle, artifact downloads, serves the frontend | [backend/README.md](backend/README.md) | | `agent/` | Container image: pinned pi SDK bridge, Python supervisor, local tools, artifact exporter | [agent/README.md](agent/README.md) | -| `frontend/` | Static UI (vendored marked + DOMPurify), same-origin mock server for UI development | [frontend/README.md](frontend/README.md) | +| `frontend/` | Static UI (vendored marked, DOMPurify and thinking-orbs engine), same-origin mock server for UI development | [frontend/README.md](frontend/README.md) | | `tests/integration/` | Integration-stage tests connecting the real components | this file | | `deploy/`, `scripts/`, `Makefile` | Deployment configuration and entry points | this file | diff --git a/frontend/README.md b/frontend/README.md index b2bd569..a684c5d 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -8,17 +8,21 @@ Minimalist, secure Web UI for Confluence Research, designed to operate against t frontend/ ├── index.html # Main HTML entrypoint (clean white minimalist theme) ├── css/ -│ └── style.css # Responsive styling, accessible components, gear animation +│ └── style.css # Responsive styling, accessible components, thinking-orb and logo styles ├── js/ │ ├── app.js # State transitions, keyboard handling, memory credentials, staleness guards │ ├── api.js # Relative /api/v1/... fetch boundary with UTF-8 byte validation │ ├── render.js # marked.js + DOMPurify, fail-safe render, bounded sectioning -│ └── history.js # Sources, lazy bounded history serialization, artifacts listing +│ ├── history.js # Sources, lazy bounded history serialization, artifacts listing +│ ├── orb.js # Vanilla canvas driver for the vendored thinking-orbs engine (loading view) +│ └── logo.js # Book logo playback: CSS cover flip on page open and brand hover ├── vendor/ # Pinned vendor libraries & licenses (locally served) │ ├── marked.min.js │ ├── marked.LICENSE │ ├── purify.min.js -│ └── dompurify.LICENSE +│ ├── dompurify.LICENSE +│ ├── thinking-orbs.engine.js # Framework-free engine build of thinking-orbs 0.3.1 +│ └── thinking-orbs.LICENSE ├── dev/ │ ├── mock-server.js # Zero-dependency same-origin mock server & scenario runner │ ├── scenario-toolbar.js # External dev toolbar script (CSP compliant, no inline scripts) diff --git a/frontend/css/style.css b/frontend/css/style.css index 1445e67..5c3c222 100644 --- a/frontend/css/style.css +++ b/frontend/css/style.css @@ -89,6 +89,106 @@ body { letter-spacing: -0.01em; } +/* Book logo: pure CSS line art on a 24-unit grid (1em = 24 units). + The front cover swings open around its left edge (js/logo.js toggles + .book-open on page load and while the brand is hovered). */ +.book { + --book-line: calc(1.6em / 24); + position: relative; + display: inline-block; + width: 1em; + height: 1em; + font-size: 24px; + flex-shrink: 0; + color: var(--color-text-primary); + perspective: 4em; + perspective-origin: 50% 50%; +} + +.book-page, +.book-cover, +.book-edge, +.book-label { + position: absolute; + box-sizing: border-box; + border: var(--book-line) solid currentColor; +} + +/* Inner page revealed while the cover is open */ +.book-page { + left: calc(4em / 24); + top: calc(2em / 24); + width: calc(16em / 24); + height: calc(17em / 24); + border-radius: calc(3em / 24); + background: var(--color-bg-primary); +} + +.book-page::after { + content: ""; + position: absolute; + left: calc(3em / 24); + right: calc(3em / 24); + top: calc(3em / 24); + bottom: calc(2em / 24); + background: repeating-linear-gradient( + to bottom, + currentColor 0, + currentColor calc(1.2em / 24), + transparent calc(1.2em / 24), + transparent calc(3.2em / 24) + ); +} + +/* Page block seen along the bottom */ +.book-edge { + left: calc(4em / 24); + top: calc(18em / 24); + width: calc(16em / 24); + height: calc(4em / 24); + border-top: 0; + border-radius: 0 0 calc(3em / 24) calc(3em / 24); +} + +/* Front cover, hinged on its left edge */ +.book-cover { + left: calc(4em / 24); + top: calc(2em / 24); + width: calc(16em / 24); + height: calc(17em / 24); + border-radius: calc(3em / 24); + background: var(--color-bg-primary); + transform-origin: left center; + transform: rotateY(0deg); + will-change: transform; +} + +.book-label { + left: calc(3em / 24); + top: calc(3em / 24); + width: calc(10em / 24); + height: calc(3.5em / 24); + border-width: calc(1.2em / 24); + border-radius: calc(1.2em / 24); +} + +.book-open .book-cover { + animation: book-flip 1.2s ease-in-out infinite; +} + +@keyframes book-flip { + 0% { transform: rotateY(0deg); } + 35% { transform: rotateY(-62deg); } + 60% { transform: rotateY(-62deg); } + 100% { transform: rotateY(0deg); } +} + +@media (prefers-reduced-motion: reduce) { + .book-open .book-cover { + animation: none; + } +} + .key-btn { position: relative; background: transparent; @@ -282,27 +382,12 @@ body { margin-bottom: 20px; } -.gear-spinner { - width: 48px; - height: 48px; - color: var(--color-accent); - stroke-width: 2px; - animation: spin 1.8s cubic-bezier(0.4, 0, 0.2, 1) infinite; -} - -@keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: reduce) { - .gear-spinner { - animation: none; - } +/* thinking-orbs canvas (js/orb.js); reduced motion renders a static frame */ +.thinking-orb { + display: block; + width: 64px; + height: 64px; + margin: 0 auto; } .loading-status { diff --git a/frontend/index.html b/frontend/index.html index 0d0e1b0..882d301 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -12,11 +12,12 @@