Перейти к содержанию

Web UI

UI — статический progressive enhancement слой без framework, bundler, CDN и внешних runtime-зависимостей. FastAPI отдаёт три packaged files.

Все рабочие состояния интерфейса на desktop и mobile собраны в галерее реального стенда: там есть Search, Ask с локальной Ollama, loading и ошибка валидации.

Вход
API key и текст пользователя
Выход
Search/Ask request, безопасно созданные DOM nodes
Хранение
API key только в sessionStorage текущей вкладки
Файлы
index.html · app.js · styles.css

DOM-структура

body
├── header.topbar
│   ├── a.brand
│   └── #health.status-pill
├── main.layout
│   ├── section.hero
│   ├── section.workspace
│   │   ├── .search-panel (key, query, mode, submit)
│   │   └── .side-panel (объяснение + rate state)
│   ├── #notice
│   ├── #answer-card
│   └── .results-section
│       └── #results
└── footer

HTML: web/index.html.

JavaScript flow

flowchart TD
    CLICK["click / Ctrl+Enter"] --> VALIDATE["query≥3 + API key"]
    VALIDATE --> FETCH["fetch /api/v1/{mode}"]
    FETCH --> HEADERS["updateRate(headers)"]
    FETCH -->|"!ok"| ERROR["parseError → notice"]
    FETCH -->|"ok"| JSON["response.json"]
    JSON --> DOM["createResult per item"]
    JSON -->|"ask"| ANSWER["answerCard.textContent"]

createResult() использует createElement и textContent, а не innerHTML: текст внешнего документа не интерпретируется как markup. Source link получает target=_blank вместе с rel="noopener noreferrer".

submitQuery() управляет loading state через disabled/aria-busy, очищает старый результат, различает items/sources и всегда восстанавливает кнопку в finally.

API key

Кнопка «Сохранить в сессии» пишет tenderLensApiKey в sessionStorage. Это удобство, а не secret vault: любой JavaScript той же origin мог бы прочитать значение. Поэтому UI не подключает remote scripts, а production должен использовать строгий CSP и TLS.

Accessibility

  • semantic header/main/section/aside/footer;
  • связанные label и form controls;
  • aria-live для health/notice;
  • hidden heading для workspace landmark;
  • keyboard shortcut Ctrl+Enter;
  • focus styles и responsive stacking;
  • цвет не является единственным носителем статуса: рядом есть текст.

CSS

styles.css определяет tokens в :root, двухколоночный workspace, компактные result rows и breakpoints 850px/560px. В UI нет скрытого build step: изменение CSS/JS сразу попадает в image через package data.

Почему не React

Текущий экран имеет одно состояние запроса и небольшой объём DOM. Framework добавил бы Node toolchain, bundle и dependency surface без пропорциональной пользы. При появлении routing, сложных filters, pagination и shared components решение стоит пересмотреть.

Полный generated-список DOM anchors, JS functions и CSS selectors — Frontend API.