@agentwhy/cli 0.0.0-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +181 -0
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/dist/adapter/claude-code/contract/assumptions.js +208 -0
- package/dist/adapter/claude-code/contract/denials.js +15 -0
- package/dist/adapter/claude-code/contract/entry-points.js +15 -0
- package/dist/adapter/claude-code/contract/fields.js +73 -0
- package/dist/adapter/claude-code/contract/hooks.js +96 -0
- package/dist/adapter/claude-code/contract/identifiers.js +15 -0
- package/dist/adapter/claude-code/contract/layout.js +29 -0
- package/dist/adapter/claude-code/contract/line-types.js +26 -0
- package/dist/adapter/claude-code/contract/projects.js +23 -0
- package/dist/adapter/claude-code/contract/recognition.js +14 -0
- package/dist/adapter/claude-code/contract/session-title.js +20 -0
- package/dist/adapter/claude-code/contract/settings.js +27 -0
- package/dist/adapter/claude-code/contract/task-notifications.js +33 -0
- package/dist/adapter/claude-code/contract/tools.js +37 -0
- package/dist/adapter/claude-code/contract/version.js +51 -0
- package/dist/adapter/claude-code/discovery/claude-code-project-catalogue.js +129 -0
- package/dist/adapter/claude-code/discovery/claude-code-recognition.js +46 -0
- package/dist/adapter/claude-code/discovery/claude-code-session-catalogue.js +100 -0
- package/dist/adapter/claude-code/discovery/claude-code-session-discovery.js +61 -0
- package/dist/adapter/claude-code/discovery/claude-code-session-titles.js +28 -0
- package/dist/adapter/claude-code/discovery/discovered-session.js +1 -0
- package/dist/adapter/claude-code/discovery/session-entries.js +41 -0
- package/dist/adapter/claude-code/discovery/transcript-tail.js +81 -0
- package/dist/adapter/claude-code/events/claude-code-session-source.js +197 -0
- package/dist/adapter/claude-code/events/delegation-index.js +15 -0
- package/dist/adapter/claude-code/events/transcript-scan.js +179 -0
- package/dist/adapter/claude-code/hooks/hook-output.js +42 -0
- package/dist/adapter/claude-code/hooks/pre-tool-use-input.js +23 -0
- package/dist/adapter/claude-code/hooks/stop-input.js +25 -0
- package/dist/adapter/claude-code/hooks/subagent-stop-input.js +26 -0
- package/dist/adapter/claude-code/policy/deny-rules.js +46 -0
- package/dist/adapter/claude-code/probe/claude-code-probe.js +86 -0
- package/dist/adapter/claude-code/probe/collectors/agent-tool-input-key-collector.js +24 -0
- package/dist/adapter/claude-code/probe/collectors/denial-kind-collector.js +20 -0
- package/dist/adapter/claude-code/probe/collectors/denied-call-collector.js +11 -0
- package/dist/adapter/claude-code/probe/collectors/identifier-collector.js +19 -0
- package/dist/adapter/claude-code/probe/collectors/line-collector.js +1 -0
- package/dist/adapter/claude-code/probe/collectors/line-type-collector.js +29 -0
- package/dist/adapter/claude-code/probe/collectors/sidechain-collector.js +20 -0
- package/dist/adapter/claude-code/probe/collectors/task-notification-collector.js +51 -0
- package/dist/adapter/claude-code/probe/collectors/tool-result-reference-collector.js +31 -0
- package/dist/adapter/claude-code/probe/collectors/tool-use-collector.js +24 -0
- package/dist/adapter/claude-code/probe/collectors/tool-version-collector.js +14 -0
- package/dist/adapter/claude-code/probe/collectors/top-level-key-collector.js +14 -0
- package/dist/adapter/claude-code/probe/collectors/unknown-line-type-key-collector.js +24 -0
- package/dist/adapter/claude-code/probe/collectors/working-directory-collector.js +28 -0
- package/dist/adapter/claude-code/probe/doctor-report.js +1 -0
- package/dist/adapter/claude-code/probe/meta-tally.js +42 -0
- package/dist/adapter/claude-code/probe/session-probe.js +1 -0
- package/dist/adapter/claude-code/probe/session-tally.js +41 -0
- package/dist/adapter/claude-code/probe/transcript-line.js +30 -0
- package/dist/adapter/claude-code/probe/transcript-tally.js +74 -0
- package/dist/adapter/claude-code/settings/deny-entries.js +65 -0
- package/dist/adapter/claude-code/settings/hook-entries.js +303 -0
- package/dist/adapter/codex/contract/actions.js +69 -0
- package/dist/adapter/codex/contract/assumptions.js +55 -0
- package/dist/adapter/codex/contract/capabilities.js +24 -0
- package/dist/adapter/codex/contract/delegations.js +30 -0
- package/dist/adapter/codex/contract/deliveries.js +25 -0
- package/dist/adapter/codex/contract/envelope.js +33 -0
- package/dist/adapter/codex/contract/hook-refusals.js +14 -0
- package/dist/adapter/codex/contract/hooks.js +46 -0
- package/dist/adapter/codex/contract/messages.js +47 -0
- package/dist/adapter/codex/contract/permissions.js +27 -0
- package/dist/adapter/codex/contract/reviews.js +13 -0
- package/dist/adapter/codex/contract/session.js +31 -0
- package/dist/adapter/codex/contract/turns.js +23 -0
- package/dist/adapter/codex/contract/version.js +15 -0
- package/dist/adapter/codex/discovery/codex-conversations.js +44 -0
- package/dist/adapter/codex/discovery/codex-project-catalogue.js +49 -0
- package/dist/adapter/codex/discovery/codex-recognition.js +20 -0
- package/dist/adapter/codex/discovery/codex-session-catalogue.js +28 -0
- package/dist/adapter/codex/discovery/codex-session-discovery.js +115 -0
- package/dist/adapter/codex/discovery/codex-session-index.js +21 -0
- package/dist/adapter/codex/discovery/codex-session-titles.js +135 -0
- package/dist/adapter/codex/discovery/session-header.js +86 -0
- package/dist/adapter/codex/discovery/session-owners.js +11 -0
- package/dist/adapter/codex/discovery/session-roots.js +49 -0
- package/dist/adapter/codex/events/action-items.js +138 -0
- package/dist/adapter/codex/events/capability-records.js +26 -0
- package/dist/adapter/codex/events/codex-session-source.js +121 -0
- package/dist/adapter/codex/events/hook-refusals.js +27 -0
- package/dist/adapter/codex/events/rollout-scan.js +614 -0
- package/dist/adapter/codex/events/turn-permissions.js +60 -0
- package/dist/adapter/codex/hooks/pre-tool-use-input.js +24 -0
- package/dist/adapter/codex/hooks/stop-refusals.js +57 -0
- package/dist/adapter/codex/probe/codex-doctor-report.js +1 -0
- package/dist/adapter/codex/probe/codex-probe.js +268 -0
- package/dist/adapter/codex/settings/codex-hooks.js +83 -0
- package/dist/cli/cli-command.js +1 -0
- package/dist/cli/command-router.js +42 -0
- package/dist/cli/commands/check-cli-command.js +128 -0
- package/dist/cli/commands/codex-stop-cli-command.js +27 -0
- package/dist/cli/commands/doctor-arguments.js +32 -0
- package/dist/cli/commands/doctor-cli-command.js +31 -0
- package/dist/cli/commands/doctor-usage.js +14 -0
- package/dist/cli/commands/init-cli-command.js +123 -0
- package/dist/cli/commands/menu-cli-command.js +58 -0
- package/dist/cli/commands/notify-cli-command.js +158 -0
- package/dist/cli/commands/refuse-cli-command.js +79 -0
- package/dist/cli/commands/report-arguments.js +62 -0
- package/dist/cli/commands/report-cli-command.js +36 -0
- package/dist/cli/commands/report-usage.js +41 -0
- package/dist/cli/commands/sessions-cli-command.js +184 -0
- package/dist/cli/commands/start-cli-command.js +83 -0
- package/dist/cli/commands/watch-cli-command.js +142 -0
- package/dist/cli/exit-codes.js +13 -0
- package/dist/cli/project-switches.js +46 -0
- package/dist/cli.js +80 -0
- package/dist/composition-root.js +411 -0
- package/dist/core/access/command-line.js +454 -0
- package/dist/core/access/listing.js +58 -0
- package/dist/core/access/path-shape.js +59 -0
- package/dist/core/access/path-tokens.js +37 -0
- package/dist/core/access/protected-access.js +310 -0
- package/dist/core/access/protected-values.js +102 -0
- package/dist/core/access/recorded-effect.js +67 -0
- package/dist/core/access/returns.js +173 -0
- package/dist/core/access/search-output.js +34 -0
- package/dist/core/access/search-reach.js +268 -0
- package/dist/core/access/uses.js +143 -0
- package/dist/core/access/words-before.js +52 -0
- package/dist/core/agent.js +1 -0
- package/dist/core/capability.js +11 -0
- package/dist/core/combined-project-catalogue.js +36 -0
- package/dist/core/combined-session-catalogue.js +25 -0
- package/dist/core/completeness.js +10 -0
- package/dist/core/context.js +1 -0
- package/dist/core/correlation/correlate.js +329 -0
- package/dist/core/delegation.js +1 -0
- package/dist/core/detector/prompt-signals.js +78 -0
- package/dist/core/entry-point.js +1 -0
- package/dist/core/event.js +1 -0
- package/dist/core/evidence.js +9 -0
- package/dist/core/late-message.js +32 -0
- package/dist/core/message.js +1 -0
- package/dist/core/nearest-project.js +28 -0
- package/dist/core/policy/default-policy.js +32 -0
- package/dist/core/policy/glob.js +56 -0
- package/dist/core/policy/parse-policy.js +70 -0
- package/dist/core/policy/policy.js +20 -0
- package/dist/core/policy/resolve-policy.js +16 -0
- package/dist/core/project-catalogue.js +1 -0
- package/dist/core/project-root.js +133 -0
- package/dist/core/provider-titles.js +10 -0
- package/dist/core/redaction/entropy.js +46 -0
- package/dist/core/redaction/redacted.js +4 -0
- package/dist/core/redaction/redactor.js +339 -0
- package/dist/core/redaction/secret-patterns.js +22 -0
- package/dist/core/redaction/value-shapes.js +81 -0
- package/dist/core/redaction/value-trace.js +110 -0
- package/dist/core/review.js +1 -0
- package/dist/core/session-catalogue.js +19 -0
- package/dist/core/session-filter.js +42 -0
- package/dist/core/session-format.js +27 -0
- package/dist/core/session-model.js +1 -0
- package/dist/core/session-reader.js +22 -0
- package/dist/core/session-records.js +1 -0
- package/dist/core/session-source.js +1 -0
- package/dist/core/session-titles.js +21 -0
- package/dist/core/turn.js +1 -0
- package/dist/doctor/codex-doctor.js +14 -0
- package/dist/doctor/doctor-use-case.js +1 -0
- package/dist/doctor/format-selecting-doctor.js +28 -0
- package/dist/doctor/render/attention/attention-rule.js +1 -0
- package/dist/doctor/render/attention/doctor-attention-rules.js +28 -0
- package/dist/doctor/render/attention/rules/damaged-meta-files-rule.js +8 -0
- package/dist/doctor/render/attention/rules/damaged-transcripts-rule.js +9 -0
- package/dist/doctor/render/attention/rules/incomplete-subagent-pairs-rule.js +6 -0
- package/dist/doctor/render/attention/rules/missing-main-transcript-rule.js +5 -0
- package/dist/doctor/render/attention/rules/missing-spilled-results-rule.js +6 -0
- package/dist/doctor/render/attention/rules/multiple-working-directories-rule.js +15 -0
- package/dist/doctor/render/attention/rules/unknown-denial-kinds-rule.js +5 -0
- package/dist/doctor/render/attention/rules/unknown-line-types-rule.js +6 -0
- package/dist/doctor/render/attention/rules/unrecognised-entries-rule.js +6 -0
- package/dist/doctor/render/attention/rules/unusable-directories-rule.js +12 -0
- package/dist/doctor/render/attention/transcript-scopes.js +6 -0
- package/dist/doctor/render/codex-text-doctor-renderer.js +97 -0
- package/dist/doctor/render/doctor-renderers.js +1 -0
- package/dist/doctor/render/json-doctor-renderer.js +7 -0
- package/dist/doctor/render/output-format.js +1 -0
- package/dist/doctor/render/text-doctor-renderer.js +124 -0
- package/dist/doctor/session-doctor.js +16 -0
- package/dist/infrastructure/clack-asker.js +24 -0
- package/dist/infrastructure/clack-chooser.js +40 -0
- package/dist/infrastructure/clack-multi-chooser.js +31 -0
- package/dist/infrastructure/file-alert-store.js +120 -0
- package/dist/infrastructure/file-checked-store.js +55 -0
- package/dist/infrastructure/file-mark-store.js +67 -0
- package/dist/infrastructure/file-onboarding-store.js +93 -0
- package/dist/infrastructure/folder-window.js +26 -0
- package/dist/infrastructure/node-agentwhy-invocation.js +99 -0
- package/dist/infrastructure/node-browser.js +40 -0
- package/dist/infrastructure/node-file-system.js +111 -0
- package/dist/infrastructure/node-local-server.js +115 -0
- package/dist/infrastructure/node-text-input.js +26 -0
- package/dist/infrastructure/os-notifier.js +21 -0
- package/dist/infrastructure/osascript-folder-chooser.js +53 -0
- package/dist/infrastructure/powershell-folder-chooser.js +78 -0
- package/dist/infrastructure/real-directory.js +18 -0
- package/dist/infrastructure/stream-printer.js +11 -0
- package/dist/infrastructure/terminal-banner.js +19 -0
- package/dist/ports/agentwhy-invocation.js +1 -0
- package/dist/ports/alert-store.js +1 -0
- package/dist/ports/asker.js +1 -0
- package/dist/ports/browser.js +1 -0
- package/dist/ports/checked-store.js +1 -0
- package/dist/ports/chooser.js +1 -0
- package/dist/ports/directory-reader.js +1 -0
- package/dist/ports/file-access-error.js +11 -0
- package/dist/ports/file-reader.js +1 -0
- package/dist/ports/file-tail-reader.js +1 -0
- package/dist/ports/file-writer.js +1 -0
- package/dist/ports/folder-chooser.js +1 -0
- package/dist/ports/local-server.js +1 -0
- package/dist/ports/mark-store.js +10 -0
- package/dist/ports/multi-chooser.js +1 -0
- package/dist/ports/notifier.js +1 -0
- package/dist/ports/onboarding-store.js +1 -0
- package/dist/ports/printer.js +1 -0
- package/dist/ports/text-input.js +1 -0
- package/dist/refuse/command-reach.js +135 -0
- package/dist/refuse/command-refusal.js +88 -0
- package/dist/refuse/render/codex-stop-words.js +21 -0
- package/dist/refuse/render/refusal-words.js +34 -0
- package/dist/report/build-report.js +1037 -0
- package/dist/report/check/actions-digest.js +73 -0
- package/dist/report/check/check-lines.js +83 -0
- package/dist/report/check/mark-request.js +90 -0
- package/dist/report/check/marks.js +84 -0
- package/dist/report/check/render/text-digest-renderer.js +332 -0
- package/dist/report/check/session-actions.js +90 -0
- package/dist/report/check/session-check.js +91 -0
- package/dist/report/choose-policy.js +61 -0
- package/dist/report/flow-reads.js +18 -0
- package/dist/report/private-files/tell-lists.js +84 -0
- package/dist/report/project-rules.js +33 -0
- package/dist/report/render/home-relative.js +18 -0
- package/dist/report/render/html-head.js +26 -0
- package/dist/report/render/html-report-components.js +48 -0
- package/dist/report/render/html-report-styles.js +500 -0
- package/dist/report/render/html-sidebar.js +42 -0
- package/dist/report/render/path-tail.js +14 -0
- package/dist/report/render/report-copy.js +1177 -0
- package/dist/report/render/report-page/advanced-view.js +167 -0
- package/dist/report/render/report-page/file-story.js +114 -0
- package/dist/report/render/report-page/files-view.js +381 -0
- package/dist/report/render/report-page/files.js +77 -0
- package/dist/report/render/report-page/fix-wizard-script.js +269 -0
- package/dist/report/render/report-page/fix-wizard.js +310 -0
- package/dist/report/render/report-page/helpers-view.js +383 -0
- package/dist/report/render/report-page/helpers.js +51 -0
- package/dist/report/render/report-page/item-names.js +63 -0
- package/dist/report/render/report-page/protect-patterns.js +13 -0
- package/dist/report/render/report-page/providers.js +208 -0
- package/dist/report/render/report-page/record-view.js +367 -0
- package/dist/report/render/report-page/report-page-renderer.js +129 -0
- package/dist/report/render/report-page/report-views.js +31 -0
- package/dist/report/render/report-page/story-window.js +356 -0
- package/dist/report/render/report-page/times.js +25 -0
- package/dist/report/render/report-page/to-do-view.js +299 -0
- package/dist/report/render/report-page/to-do.js +152 -0
- package/dist/report/render/report-page.js +1 -0
- package/dist/report/render/session-view.js +250 -0
- package/dist/report/render/text-report-renderer.js +981 -0
- package/dist/report/render/ui/add-file-popup.js +122 -0
- package/dist/report/render/ui/app-sidebar.js +78 -0
- package/dist/report/render/ui/ask-panel.js +80 -0
- package/dist/report/render/ui/avatar.js +19 -0
- package/dist/report/render/ui/backdrop.js +29 -0
- package/dist/report/render/ui/brand-mark.js +4 -0
- package/dist/report/render/ui/button.js +67 -0
- package/dist/report/render/ui/callout.js +20 -0
- package/dist/report/render/ui/chat-example.js +17 -0
- package/dist/report/render/ui/checklist.js +50 -0
- package/dist/report/render/ui/confirm-dialog.js +34 -0
- package/dist/report/render/ui/data-table.js +49 -0
- package/dist/report/render/ui/drawer.js +25 -0
- package/dist/report/render/ui/file-chip.js +37 -0
- package/dist/report/render/ui/fold-line.js +22 -0
- package/dist/report/render/ui/guide-card.js +25 -0
- package/dist/report/render/ui/hero.js +37 -0
- package/dist/report/render/ui/labelled-select.js +10 -0
- package/dist/report/render/ui/live-script.js +222 -0
- package/dist/report/render/ui/local-date.js +58 -0
- package/dist/report/render/ui/mode-icon.js +6 -0
- package/dist/report/render/ui/page-shell.js +101 -0
- package/dist/report/render/ui/pill-tabs.js +47 -0
- package/dist/report/render/ui/popup.js +77 -0
- package/dist/report/render/ui/progress.js +35 -0
- package/dist/report/render/ui/project-list.js +284 -0
- package/dist/report/render/ui/scope-choice.js +19 -0
- package/dist/report/render/ui/stats.js +21 -0
- package/dist/report/render/ui/status-icon.js +30 -0
- package/dist/report/render/ui/status-look.js +21 -0
- package/dist/report/render/ui/switch.js +11 -0
- package/dist/report/render/ui/tag.js +19 -0
- package/dist/report/render/ui/task-list.js +56 -0
- package/dist/report/render/ui/tokens.js +46 -0
- package/dist/report/render/ui/update-notice.js +146 -0
- package/dist/report/render/ui/words/app-words.js +163 -0
- package/dist/report/render/ui/words/conversations-words.js +457 -0
- package/dist/report/render/ui/words/month-words.js +59 -0
- package/dist/report/render/ui/words/onboarding-words.js +446 -0
- package/dist/report/render/ui/words/projects-words.js +217 -0
- package/dist/report/render/ui/words/report-words.js +2099 -0
- package/dist/report/render/ui/words/settings-words.js +611 -0
- package/dist/report/render/ui/words/to-fix-words.js +287 -0
- package/dist/report/report-model.js +2 -0
- package/dist/report/report-use-case.js +1 -0
- package/dist/report/rule-names.js +20 -0
- package/dist/report/session-report.js +163 -0
- package/dist/report/start/app-nav.js +37 -0
- package/dist/report/start/conversations/calendar-view.js +104 -0
- package/dist/report/start/conversations/conversation-columns.js +187 -0
- package/dist/report/start/conversations/conversations-renderer.js +54 -0
- package/dist/report/start/conversations/empty-week.js +120 -0
- package/dist/report/start/conversations/files-window.js +166 -0
- package/dist/report/start/conversations/period-section.js +280 -0
- package/dist/report/start/conversations/periods-script.js +440 -0
- package/dist/report/start/conversations/periods.js +110 -0
- package/dist/report/start/conversations/week-view.js +30 -0
- package/dist/report/start/conversations/weeks.js +17 -0
- package/dist/report/start/month/month-renderer.js +50 -0
- package/dist/report/start/month/month-view.js +135 -0
- package/dist/report/start/month/months.js +17 -0
- package/dist/report/start/onboarding/done.js +171 -0
- package/dist/report/start/onboarding/finish-onboarding.js +93 -0
- package/dist/report/start/onboarding/intro.js +100 -0
- package/dist/report/start/onboarding/onboarding-changes.js +40 -0
- package/dist/report/start/onboarding/onboarding-renderer.js +195 -0
- package/dist/report/start/onboarding/onboarding-script.js +400 -0
- package/dist/report/start/onboarding/onboarding-view.js +98 -0
- package/dist/report/start/onboarding/project-step.js +210 -0
- package/dist/report/start/onboarding/steps.js +239 -0
- package/dist/report/start/onboarding/welcome.js +66 -0
- package/dist/report/start/page-notice.js +10 -0
- package/dist/report/start/projects/index-projects.js +43 -0
- package/dist/report/start/projects/moved-page.js +82 -0
- package/dist/report/start/projects/project-switch.js +138 -0
- package/dist/report/start/projects/projects-window.js +67 -0
- package/dist/report/start/projects/temporary-space.js +18 -0
- package/dist/report/start/render/air-datepicker-vendor.js +27 -0
- package/dist/report/start/render/session-status.js +41 -0
- package/dist/report/start/render/start-words.js +84 -0
- package/dist/report/start/repository.js +28 -0
- package/dist/report/start/serve/index-handler.js +372 -0
- package/dist/report/start/serve/onboarding-request.js +50 -0
- package/dist/report/start/serve/settings-request.js +1 -0
- package/dist/report/start/serve/settings-setup.js +193 -0
- package/dist/report/start/session-index.js +1 -0
- package/dist/report/start/session-start.js +974 -0
- package/dist/report/start/settings/alerts-tab.js +104 -0
- package/dist/report/start/settings/files-tab.js +169 -0
- package/dist/report/start/settings/general-tab.js +71 -0
- package/dist/report/start/settings/settings-renderer.js +254 -0
- package/dist/report/start/settings/settings-script.js +161 -0
- package/dist/report/start/settings/settings-view.js +240 -0
- package/dist/report/start/settings/settings-windows.js +334 -0
- package/dist/report/start/settings-files.js +43 -0
- package/dist/report/start/to-fix/done-list.js +45 -0
- package/dist/report/start/to-fix/file-window.js +110 -0
- package/dist/report/start/to-fix/to-fix-list.js +70 -0
- package/dist/report/start/to-fix/to-fix-renderer.js +237 -0
- package/dist/report/start/to-fix/to-fix-script.js +94 -0
- package/dist/report/start/to-fix/to-fix-view.js +124 -0
- package/dist/report/watch/agent-alert.js +72 -0
- package/dist/report/watch/notice-choices.js +35 -0
- package/dist/report/watch/notice-settings.js +65 -0
- package/dist/report/watch/preferences.js +100 -0
- package/dist/report/watch/render/instruction-words.js +54 -0
- package/dist/report/watch/render/notice-words.js +182 -0
- package/dist/report/watch/subagent-watch.js +345 -0
- package/dist/report/watch/watch-notice.js +1 -0
- package/dist/setup/behind.js +18 -0
- package/dist/setup/codex-mirror.js +171 -0
- package/dist/setup/not-a-project.js +19 -0
- package/dist/setup/project-setup.js +644 -0
- package/dist/setup/protected-patterns.js +30 -0
- package/dist/shared/colour.js +23 -0
- package/dist/shared/compare.js +4 -0
- package/dist/shared/content-version.js +13 -0
- package/dist/shared/counter.js +11 -0
- package/dist/shared/file-stamp.js +4 -0
- package/dist/shared/json.js +13 -0
- package/dist/shared/label.js +13 -0
- package/dist/shared/package-name.js +6 -0
- package/dist/shared/plain-invocation.js +44 -0
- package/dist/shared/plain-version.js +21 -0
- package/dist/shared/printable.js +25 -0
- package/dist/shared/renderer.js +1 -0
- package/dist/shared/sentence.js +20 -0
- package/dist/shared/terminal-logo.js +41 -0
- package/dist/shared/text-table.js +15 -0
- package/dist/shared/wrap.js +29 -0
- package/package.json +70 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../html-report-components.js';
|
|
2
|
+
import { inLanguages, labelAttributes, LANGS, translator } from '../report-copy.js';
|
|
3
|
+
import { closeButton, pill } from './button.js';
|
|
4
|
+
import { CLOSES, popup } from './popup.js';
|
|
5
|
+
/**
|
|
6
|
+
* "Add a private file" (`for-people-who-build-with-ai.md` F35, F36; guidelines §9.2): two large cards, *Choose a file* and
|
|
7
|
+
* *Choose a folder*, then "Or type the name". Settings opens it, and the onboarding's step 2
|
|
8
|
+
* (`.ai/specs/2026-09-24-onboarding.md` W12), which is why it is in the kit.
|
|
9
|
+
*
|
|
10
|
+
* A picked file gives its name and nothing else: the page never reads its contents - no `FileReader`, no upload;
|
|
11
|
+
* `files[0].name` and, for a folder, the first segment of `webkitRelativePath` are all the script touches. The name
|
|
12
|
+
* becomes the pattern a deny rule will hold - a file anywhere by that name, or a folder's contents - and is handed to
|
|
13
|
+
* the page as an `add-file` event on the window, `{ name, kind, pattern }`. What happens then is the page's: Settings
|
|
14
|
+
* asks to confirm, the onboarding adds a row. A name that cannot be written exactly is refused here, in words (R46).
|
|
15
|
+
*
|
|
16
|
+
* Its words are Settings' (`set.add.*`): one popup, one set of words, whichever page opens it.
|
|
17
|
+
*/
|
|
18
|
+
export function addFilePopup(id) {
|
|
19
|
+
const title = id + '-title';
|
|
20
|
+
const placeholder = (lang) => e(translator(lang)('set.add.placeholder'));
|
|
21
|
+
const pick = (kind, glyph) => '<button type="button" class="af-pick" data-af-pick="' + kind + '">' +
|
|
22
|
+
'<span class="af-pick-mark" aria-hidden="true">' + glyph + '</span>' +
|
|
23
|
+
'<span class="af-pick-name">' + inLanguages((t) => t('set.add.' + kind)) + '</span>' +
|
|
24
|
+
'<span class="af-pick-eg">' + inLanguages((t) => t('set.add.' + kind + '.eg')) + '</span></button>';
|
|
25
|
+
return popup({
|
|
26
|
+
id,
|
|
27
|
+
size: 'pick',
|
|
28
|
+
labelledBy: title,
|
|
29
|
+
body: '<div class="af" data-af>' +
|
|
30
|
+
'<div class="af-head"><h3 class="af-title" id="' + title + '">' + inLanguages((t) => t('set.add.title')) + '</h3>' +
|
|
31
|
+
closeButton(labelAttributes((t) => t('app.close')) + CLOSES, 'sm') + '</div>' +
|
|
32
|
+
'<p class="af-lead">' + inLanguages((t) => t('set.add.lead')) + '</p>' +
|
|
33
|
+
'<div class="af-picks js-only">' + pick('file', '▤') + pick('folder', '▦') + '</div>' +
|
|
34
|
+
'<input type="file" class="af-file" data-af-file="file" hidden tabindex="-1" aria-hidden="true">' +
|
|
35
|
+
'<input type="file" class="af-file" data-af-file="folder" webkitdirectory directory hidden tabindex="-1" aria-hidden="true">' +
|
|
36
|
+
'<div class="af-type-label">' + inLanguages((t) => t('set.add.type')) + '</div>' +
|
|
37
|
+
'<form class="af-type" data-af-type>' +
|
|
38
|
+
'<input class="af-type-input" name="name" autocomplete="off" placeholder="' + placeholder('en') + '"' +
|
|
39
|
+
LANGS.map((lang) => ' data-placeholder-' + lang + '="' + placeholder(lang) + '"').join('') +
|
|
40
|
+
labelAttributes((t) => e(t('set.add.type'))) + '>' +
|
|
41
|
+
pill({ label: inLanguages((t) => t('set.add.go')), tone: 'light', size: 'task', attributes: ' data-af-type-go', button: true }) +
|
|
42
|
+
'</form>' +
|
|
43
|
+
'<p class="af-cannot" data-af-cannot hidden>' + inLanguages((t) => t('set.add.cannot')) + '</p></div>',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export const ADD_FILE_POPUP_STYLE = String.raw `
|
|
47
|
+
.af{padding:28px}
|
|
48
|
+
.af-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:8px}
|
|
49
|
+
.af-title{margin:0;font-size:22px;line-height:1.25;font-weight:650}
|
|
50
|
+
.af-lead{margin:0 0 20px;font-size:15px;line-height:1.55;color:var(--text-2)}
|
|
51
|
+
.af-picks{grid-template-columns:1fr 1fr;gap:12px;margin-bottom:22px}
|
|
52
|
+
.js .af-picks{display:grid}
|
|
53
|
+
.af-pick{display:flex;flex-direction:column;align-items:center;gap:10px;padding:22px 16px;border-radius:14px;background:var(--panel);border:1px solid var(--white-12);color:inherit;font:inherit;cursor:pointer;text-align:center}
|
|
54
|
+
.af-pick:hover{border-color:var(--coral)}
|
|
55
|
+
.af-pick-mark{width:44px;height:44px;border-radius:12px;background:var(--coral-12);color:var(--coral-text);display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700}
|
|
56
|
+
.af-pick-name{font-size:15.5px;font-weight:600}
|
|
57
|
+
.af-pick-eg{font-size:13px;color:var(--text-2)}
|
|
58
|
+
.af-type-label{font-size:13px;color:var(--text-3);margin-bottom:8px}
|
|
59
|
+
.af-type{display:flex;gap:10px}
|
|
60
|
+
.af-type-input{flex:1;min-width:0;background:var(--panel);border:1px solid var(--white-12);border-radius:999px;padding:10px 16px;color:var(--text);font:inherit;font-size:14px;outline:none}
|
|
61
|
+
.af-type-input:focus-visible{border-color:var(--coral-50)}
|
|
62
|
+
.af-type .pill{padding:10px 20px}
|
|
63
|
+
.af-cannot{margin:14px 0 0;font-size:14px;line-height:1.5;color:var(--coral-text)}
|
|
64
|
+
@media (max-width:640px){.js .af-picks{grid-template-columns:1fr}}
|
|
65
|
+
`;
|
|
66
|
+
/**
|
|
67
|
+
* A name becomes the pattern (F36): a file anywhere by that name, or a folder's contents. A picked name holding a
|
|
68
|
+
* wildcard would protect other files than the one picked, and a bracket cannot be written in a deny rule at all (R46),
|
|
69
|
+
* so such a name is refused here, in words, rather than escaped by a guess. A typed name with a slash or a wildcard is
|
|
70
|
+
* taken as the pattern it already is.
|
|
71
|
+
*/
|
|
72
|
+
export const ADD_FILE_POPUP_SCRIPT = String.raw `
|
|
73
|
+
(() => {
|
|
74
|
+
document.querySelectorAll('[data-af]').forEach((root) => {
|
|
75
|
+
const window_ = root.closest('dialog');
|
|
76
|
+
const cannot = root.querySelector('[data-af-cannot]');
|
|
77
|
+
if (!window_) return;
|
|
78
|
+
const hand = (name, kind) => {
|
|
79
|
+
if (/[()]/.test(name) || (kind !== 'pattern' && /[*?[\]{}]/.test(name))) {
|
|
80
|
+
if (cannot) cannot.hidden = false;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (cannot) cannot.hidden = true;
|
|
84
|
+
const pattern = kind === 'file' ? '**/' + name : kind === 'folder' ? '**/' + name + '/**' : name;
|
|
85
|
+
window_.dispatchEvent(new CustomEvent('add-file', { detail: { name, kind, pattern } }));
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
root.addEventListener('click', (event) => {
|
|
89
|
+
const pick = event.target.closest('[data-af-pick]');
|
|
90
|
+
if (pick) {
|
|
91
|
+
const input = root.querySelector('[data-af-file="' + pick.dataset.afPick + '"]');
|
|
92
|
+
if (input) input.click();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (event.target.closest('[data-af-type-go]')) {
|
|
96
|
+
const form = event.target.closest('form');
|
|
97
|
+
if (form) form.requestSubmit();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
root.querySelectorAll('[data-af-file]').forEach((input) => input.addEventListener('change', () => {
|
|
102
|
+
const first = input.files && input.files[0];
|
|
103
|
+
if (!first) return;
|
|
104
|
+
const name = input.dataset.afFile === 'folder' ? (first.webkitRelativePath || '').split('/')[0] : first.name;
|
|
105
|
+
input.value = '';
|
|
106
|
+
if (name) hand(name, input.dataset.afFile);
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
const typed = root.querySelector('[data-af-type]');
|
|
110
|
+
if (typed) typed.addEventListener('submit', (event) => {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
const field = typed.querySelector('input');
|
|
113
|
+
const text = field.value.trim();
|
|
114
|
+
if (text === '') return;
|
|
115
|
+
field.value = '';
|
|
116
|
+
const folder = /^[^/*?[\]]+\/$/.test(text);
|
|
117
|
+
const plain = /^[^/*?[\]]+$/.test(text);
|
|
118
|
+
hand(folder ? text.slice(0, -1) : text, folder ? 'folder' : plain ? 'file' : 'pattern');
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
})();
|
|
122
|
+
`;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../html-report-components.js';
|
|
2
|
+
import { BRAND_MARK } from './brand-mark.js';
|
|
3
|
+
import { opens } from './popup.js';
|
|
4
|
+
import { DEFAULT_LANG, inLanguages, LANG_NAMES, LANGS, labelAttributes } from '../report-copy.js';
|
|
5
|
+
/**
|
|
6
|
+
* The column every page of the new design carries (design file *agentwhy Sessions v2*): the mark and wordmark, the
|
|
7
|
+
* project, the pages, and the one standing fact about where the work happens. The mark is the knot the reports
|
|
8
|
+
* already carry (`BRAND_MARK`), kept at the maintainer's request over the design file's wordmark alone.
|
|
9
|
+
*/
|
|
10
|
+
export function appSidebar(spec) {
|
|
11
|
+
const link = spec.project !== undefined && spec.projectsWindow !== undefined;
|
|
12
|
+
return '<aside class="sb">' +
|
|
13
|
+
'<a class="sb-brand" href="' + spec.home + '" aria-label="agentwhy">' + BRAND_MARK + '<span class="sb-word">agent<span class="sb-why">why</span></span></a>' +
|
|
14
|
+
// One line for the name, as every other row of the column is one line: a long folder name ends in an ellipsis and
|
|
15
|
+
// is whole on hover, rather than breaking at a hyphen over two lines of heavier type than the items under it. The
|
|
16
|
+
// place under it is cut the same way, and the tooltip holds it whole, since it says which folder this is.
|
|
17
|
+
(spec.showProject === false ? '' :
|
|
18
|
+
(link ? '<a class="sb-project sb-project-link"' + opens(spec.projectsWindow) : '<div class="sb-project"') +
|
|
19
|
+
(spec.project === undefined ? '' : ' title="' + e(spec.place ?? spec.project) + '"') + '>' +
|
|
20
|
+
'<span class="sb-project-mark" aria-hidden="true">' + (spec.project === undefined ? '↗' : e(initial(spec.project))) + '</span>' +
|
|
21
|
+
'<span class="sb-project-text"><span class="sb-project-label">' +
|
|
22
|
+
inLanguages((t) => t(spec.project === undefined ? 'app.shared' : 'app.project')) + '</span>' +
|
|
23
|
+
(spec.project === undefined ? '' : '<span class="sb-project-name">' + e(spec.project) + '</span>') +
|
|
24
|
+
(spec.project === undefined || spec.place === undefined ? '' : '<span class="sb-project-place">' + e(spec.place) + '</span>') +
|
|
25
|
+
'</span>' + (link ? '<span class="sb-project-go" aria-hidden="true">›</span></a>' : '</div>')) +
|
|
26
|
+
'<nav class="sb-nav"' + labelAttributes((t) => t('app.nav')) + '>' + spec.items.map(item).join('') + '</nav>' +
|
|
27
|
+
'<div class="sb-foot">' +
|
|
28
|
+
'<select class="sb-lang js-only" id="lang"' + labelAttributes((t) => t('app.lang')) + '>' +
|
|
29
|
+
LANGS.map((lang) => '<option value="' + lang + '"' + (lang === DEFAULT_LANG ? ' selected' : '') + '>' + LANG_NAMES[lang] + '</option>').join('') +
|
|
30
|
+
'</select>' +
|
|
31
|
+
'<div class="sb-local"><span class="sb-dot" aria-hidden="true"></span><span>' + inLanguages((t) => t('app.local')) + '</span></div>' +
|
|
32
|
+
'</div></aside>';
|
|
33
|
+
}
|
|
34
|
+
/** The first letter or digit of a folder's name, for its mark: `test-project` is T, `_scratch` is S. */
|
|
35
|
+
export function initial(name) {
|
|
36
|
+
return (/[\p{L}\p{N}]/u.exec(name)?.[0] ?? '·').toUpperCase();
|
|
37
|
+
}
|
|
38
|
+
function item(nav) {
|
|
39
|
+
const count = nav.count === undefined || nav.count === 0 ? '' :
|
|
40
|
+
'<span class="sb-count' + (nav.countTone === 'coral' ? ' sb-count-coral' : '') + '">' + nav.count + '</span>';
|
|
41
|
+
return '<a class="sb-item' + (nav.active === true ? ' sb-active' : '') + '" href="' + nav.href + '"' +
|
|
42
|
+
(nav.active === true ? ' aria-current="page"' : '') + '><span>' + inLanguages((t) => t(nav.name)) + '</span>' + count + '</a>';
|
|
43
|
+
}
|
|
44
|
+
export const APP_SIDEBAR_STYLE = String.raw `
|
|
45
|
+
.sb{flex:none;width:232px;display:flex;flex-direction:column;border-right:1px solid var(--white-07);padding:22px 14px;position:sticky;top:0;height:100vh;z-index:1}
|
|
46
|
+
.sb-brand{display:flex;align-items:center;gap:9px;padding:0 10px 22px;color:var(--coral)}
|
|
47
|
+
.sb-brand:hover{color:var(--coral)}
|
|
48
|
+
.sb-brand .brand-mark{width:24px;height:24px;flex:none}
|
|
49
|
+
.sb-word{font-size:21px;font-weight:650;letter-spacing:-0.02em;color:var(--text)}
|
|
50
|
+
.sb-why{color:var(--coral)}
|
|
51
|
+
.sb-project{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:12px;background:var(--card);border:1px solid var(--white-09);margin-bottom:22px}
|
|
52
|
+
.sb-project-link{color:inherit;transition:background .15s,border-color .15s}
|
|
53
|
+
.sb-project-link:hover{color:inherit;background:var(--raised);border-color:var(--white-16)}
|
|
54
|
+
.sb-project-go{margin-left:auto;flex:none;align-self:center;color:var(--text-3);font-size:18px;line-height:1}
|
|
55
|
+
.sb-project-link:hover .sb-project-go{color:var(--text)}
|
|
56
|
+
.sb-project-mark{flex:none;width:30px;height:30px;border-radius:9px;display:flex;align-items:center;justify-content:center;background:var(--white-06);border:1px solid var(--white-10);color:var(--text);font-size:13px;font-weight:650}
|
|
57
|
+
.sb-project-text{min-width:0;display:flex;flex-direction:column;gap:1px}
|
|
58
|
+
.sb-project-label{font-size:12px;font-weight:600;color:var(--text-3)}
|
|
59
|
+
.sb-project-name{font-size:14px;font-weight:600;line-height:1.35;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
60
|
+
.sb-project-place{font-family:var(--mono);font-size:12.5px;line-height:1.4;color:var(--text-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
61
|
+
.sb-nav{display:flex;flex-direction:column;gap:4px}
|
|
62
|
+
.sb-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 12px;border-radius:10px;border:1px solid transparent;color:var(--text-2);font-size:15px;font-weight:500}
|
|
63
|
+
.sb-item:hover{color:var(--text);background:var(--white-02)}
|
|
64
|
+
.sb-active{background:var(--coral-08);border-color:var(--coral-30);color:var(--text)}
|
|
65
|
+
.sb-active:hover{background:var(--coral-08)}
|
|
66
|
+
.sb-count{font-size:12.5px;font-weight:600;border-radius:999px;padding:2px 8px;color:var(--text-2);background:var(--white-06)}
|
|
67
|
+
.sb-count-coral{color:var(--on-coral);background:var(--coral)}
|
|
68
|
+
.sb-foot{margin-top:auto;display:flex;flex-direction:column;gap:14px}
|
|
69
|
+
.sb-lang{align-self:flex-start;margin:0 10px;background:var(--card);color:var(--text-2);border:1px solid var(--white-10);border-radius:8px;padding:5px 8px;font:inherit;font-size:13px}
|
|
70
|
+
.sb-local{padding:16px 10px 0;border-top:1px solid var(--white-07);display:flex;gap:10px;font-size:13px;line-height:1.5;color:var(--text-2)}
|
|
71
|
+
.sb-dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--mint);margin-top:6px}
|
|
72
|
+
@media (max-width:860px){
|
|
73
|
+
.sb{position:static;width:auto;height:auto;border-right:0;border-bottom:1px solid var(--white-07);padding:16px}
|
|
74
|
+
.sb-brand{padding:0 4px 14px}.sb-project{margin-bottom:12px}
|
|
75
|
+
.sb-nav{flex-direction:row;overflow-x:auto;gap:6px}.sb-item{white-space:nowrap}
|
|
76
|
+
.sb-foot{flex-direction:row;align-items:center;justify-content:space-between;margin-top:12px}.sb-local{border-top:0;padding:0}.sb-lang{margin:0}
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { textButton } from './button.js';
|
|
2
|
+
/**
|
|
3
|
+
* The questions and their answers. Its trigger (`askTrigger`) may sit elsewhere - a window's foot - and names it by id.
|
|
4
|
+
* `open` has no trigger at all: the questions are always there (`askCard`).
|
|
5
|
+
*/
|
|
6
|
+
export function askPanel(questions, id, open = false) {
|
|
7
|
+
return '<div class="ak-box' + (open ? ' ak-open' : '') + '" id="' + id + '" data-ask>' +
|
|
8
|
+
'<div class="ak-answer" data-ask-answer hidden></div>' +
|
|
9
|
+
'<div class="ak-questions js-only">' + questions.map((each, at) => '<button type="button" class="ak-q" data-ask-q="' + at + '">' + each.question + '</button>').join('') + '</div>' +
|
|
10
|
+
'<dl class="ak-all">' + questions.map((each, at) => '<dt>' + each.question + '</dt><dd data-ask-a="' + at + '">' + each.answer + '</dd>').join('') + '</dl>' +
|
|
11
|
+
'</div>';
|
|
12
|
+
}
|
|
13
|
+
/** "✦ I'm stuck": opens and closes the panel it names. With no script the panel is always open, so it has nothing to do. */
|
|
14
|
+
export function askTrigger(label, id) {
|
|
15
|
+
return textButton(label, ' aria-expanded="false" aria-controls="' + id + '" data-ask-toggle', 'ak-trigger js-only');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* "✦ Not sure what to pick? Ask me." (spec §7.1): the same questions and written answers, always open, in a coral card
|
|
19
|
+
* under a view's content (Settings, one card per tab).
|
|
20
|
+
*/
|
|
21
|
+
export function askCard(title, questions, id) {
|
|
22
|
+
return '<section class="ak-card"><div class="ak-card-head"><span class="ak-card-mark" aria-hidden="true">✦</span>' +
|
|
23
|
+
'<span class="ak-card-title">' + title + '</span></div>' + askPanel(questions, id, true) + '</section>';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A written answer laid out to be read at a glance: the short answer first, in bold, then one point per line. The lines
|
|
27
|
+
* of `text` are split on a newline; a single line stays as it is.
|
|
28
|
+
*/
|
|
29
|
+
export function writtenAnswer(text) {
|
|
30
|
+
const [lead = '', ...points] = text.split('\n');
|
|
31
|
+
if (points.length === 0)
|
|
32
|
+
return lead;
|
|
33
|
+
return '<strong class="ak-lead">' + lead + '</strong>' + points.map((point) => '<span class="ak-point">' + point + '</span>').join('');
|
|
34
|
+
}
|
|
35
|
+
export const ASK_PANEL_STYLE = String.raw `
|
|
36
|
+
.ak-trigger{color:var(--coral-text)}.ak-trigger:hover{color:var(--coral-link-hover)}
|
|
37
|
+
.ak-box{margin-top:22px;padding:16px;border-radius:14px;background:var(--panel);border:1px solid var(--white-08)}
|
|
38
|
+
.js .ak-box:not(.ak-open){display:none}
|
|
39
|
+
.js .ak-all{display:none}
|
|
40
|
+
.ak-answer{font-size:15px;line-height:1.55;color:var(--text);margin-bottom:14px}
|
|
41
|
+
.ak-questions{display:flex;gap:8px;flex-wrap:wrap}
|
|
42
|
+
.js .ak-questions.js-only{display:flex}
|
|
43
|
+
.ak-q{background:transparent;border:1px solid var(--white-12);color:var(--text-soft);border-radius:999px;padding:6px 12px;font:inherit;font-size:13px;cursor:pointer}
|
|
44
|
+
.ak-q:hover,.ak-q[aria-pressed="true"]{border-color:var(--coral-60)}
|
|
45
|
+
.ak-all{margin:0}.ak-all dt{font-size:14px;font-weight:600;margin-top:12px}.ak-all dt:first-child{margin-top:0}
|
|
46
|
+
.ak-all dd{margin:4px 0 0;font-size:14.5px;line-height:1.55;color:var(--text-2)}
|
|
47
|
+
.ak-lead{display:block;font-weight:650;color:var(--text)}
|
|
48
|
+
.ak-point{display:block;position:relative;padding-left:16px;margin-top:6px}
|
|
49
|
+
.ak-point:before{content:"";position:absolute;left:3px;top:.6em;width:5px;height:5px;border-radius:50%;background:var(--coral-text)}
|
|
50
|
+
.ak-card{border-radius:14px;background:var(--coral-06);border:1px solid var(--coral-30);padding:16px 20px;margin:24px 0}
|
|
51
|
+
.ak-card-head{display:flex;align-items:center;gap:12px;margin-bottom:12px}
|
|
52
|
+
.ak-card-mark{flex:none;width:32px;height:32px;border-radius:50%;background:var(--coral-14);color:var(--coral-text);display:flex;align-items:center;justify-content:center;font-size:14px}
|
|
53
|
+
.ak-card-title{font-size:15.5px;font-weight:600}
|
|
54
|
+
.ak-card .ak-box{margin:0;padding:0;background:none;border:0}
|
|
55
|
+
.ak-card .ak-answer{background:var(--panel);border:1px solid var(--white-08);border-radius:12px;padding:14px 16px;margin-bottom:12px}
|
|
56
|
+
.ak-card .ak-q{border-color:var(--white-14);padding:7px 13px;font-size:13.5px}
|
|
57
|
+
`;
|
|
58
|
+
/** Opens and closes the box, and shows the chosen question's answer, copied from the page's own answers. */
|
|
59
|
+
export const ASK_PANEL_SCRIPT = String.raw `
|
|
60
|
+
document.addEventListener('click', (event) => {
|
|
61
|
+
const toggle = event.target.closest('[data-ask-toggle]');
|
|
62
|
+
if (toggle) {
|
|
63
|
+
const panel = document.getElementById(toggle.getAttribute('aria-controls'));
|
|
64
|
+
if (!panel) return;
|
|
65
|
+
const open = !panel.classList.contains('ak-open');
|
|
66
|
+
panel.classList.toggle('ak-open', open);
|
|
67
|
+
toggle.setAttribute('aria-expanded', String(open));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const question = event.target.closest('[data-ask-q]');
|
|
71
|
+
if (!question) return;
|
|
72
|
+
const panel = question.closest('[data-ask]');
|
|
73
|
+
const at = question.getAttribute('data-ask-q');
|
|
74
|
+
const answer = panel.querySelector('[data-ask-a="' + at + '"]');
|
|
75
|
+
const slot = panel.querySelector('[data-ask-answer]');
|
|
76
|
+
panel.querySelectorAll('[data-ask-q]').forEach((each) => each.setAttribute('aria-pressed', String(each === question)));
|
|
77
|
+
slot.innerHTML = answer ? answer.innerHTML : '';
|
|
78
|
+
slot.hidden = !answer;
|
|
79
|
+
});
|
|
80
|
+
`;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../html-report-components.js';
|
|
2
|
+
/** Initials come from the page's own naming (`AI`, `H` and an ordinal), never from transcript text; escaped anyway. */
|
|
3
|
+
export function avatar(initials, tone, size = 42) {
|
|
4
|
+
return '<span class="av av-' + tone + ' av-' + size + '" aria-hidden="true">' + e(initials) + '</span>';
|
|
5
|
+
}
|
|
6
|
+
/** Several readers of one file, overlapping (Advanced, "Read by"). */
|
|
7
|
+
export function avatarGroup(avatars) {
|
|
8
|
+
return '<span class="avg">' + avatars.map((each) => avatar(each.initials, each.tone, 30)).join('') + '</span>';
|
|
9
|
+
}
|
|
10
|
+
export const AVATAR_STYLE = String.raw `
|
|
11
|
+
.av{flex:none;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700}
|
|
12
|
+
.av-42{width:42px;height:42px;font-size:14px}.av-40{width:40px;height:40px;font-size:12.5px}.av-30{width:30px;height:30px;font-size:11px}
|
|
13
|
+
.av-coral{background:var(--coral-16);color:var(--coral-text)}
|
|
14
|
+
.av-alert{background:var(--coral);color:var(--on-coral)}
|
|
15
|
+
.av-mint{background:var(--mint-14);color:var(--mint)}
|
|
16
|
+
.av-grey{background:var(--raised-2);color:var(--text-2)}
|
|
17
|
+
.av-40{border:1px solid var(--white-10)}.av-40.av-alert{border-color:var(--coral)}
|
|
18
|
+
.avg{display:flex}.avg .av{margin-right:-6px;border:2px solid var(--card)}
|
|
19
|
+
`;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The page's background: the warm glow of the design files at the top, and the still field of points the index has
|
|
3
|
+
* always had behind it, kept at the maintainer's request (2026-09-23) over the guidelines' "no dots". It says
|
|
4
|
+
* nothing and takes no pointer; it is written into the page, so a page with no script is the page that was designed.
|
|
5
|
+
*
|
|
6
|
+
* `bd-mint` on it turns a mint glow on over the warm one: the onboarding's Done, whose one message is that all is well
|
|
7
|
+
* (`.ai/specs/2026-09-24-onboarding.md` W2, W17). A page's script sets it; without one the glow stays warm.
|
|
8
|
+
*/
|
|
9
|
+
export function backdrop() {
|
|
10
|
+
return '<div class="bd" aria-hidden="true">' + stars(65) + '</div>';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The field of points itself, `count` of them spread over the box that holds them: the page's, and a wide window's,
|
|
14
|
+
* which carries the page's sky with it (`popup.ts`; the maintainer, 2026-09-25). Always the same points, so a page
|
|
15
|
+
* written twice is the same page.
|
|
16
|
+
*/
|
|
17
|
+
export function stars(count) {
|
|
18
|
+
return Array.from({ length: count }, (_unused, at) => '<i class="bd-star' + (at % 17 === 0 ? ' bd-cross' : '') + '" style="left:' + ((at * 47.37 + 8) % 100).toFixed(2) +
|
|
19
|
+
'%;top:' + ((at * 29.83 + 3) % 100).toFixed(2) + '%;opacity:' + (0.12 + (at % 5) * 0.055).toFixed(3) + '"></i>').join('');
|
|
20
|
+
}
|
|
21
|
+
export const BACKDROP_STYLE = String.raw `
|
|
22
|
+
.bd{position:fixed;inset:0;pointer-events:none;z-index:0;overflow:hidden;background:radial-gradient(1200px 520px at 60% -120px,var(--glow) 0%,var(--glow-mid) 55%,var(--bg) 100%)}
|
|
23
|
+
.bd:after{content:"";position:absolute;inset:0;opacity:0;transition:opacity .8s ease;background:radial-gradient(1100px 560px at 50% -140px,var(--glow-mint) 0%,transparent 70%),radial-gradient(900px 600px at 50% 38%,var(--mint-16),transparent 65%)}
|
|
24
|
+
.bd-mint:after{opacity:1}
|
|
25
|
+
.bd-star{position:absolute;width:2px;height:2px;border-radius:50%;background:var(--star);box-shadow:0 0 6px var(--star-glow);opacity:.3}
|
|
26
|
+
.bd-cross{width:3px;height:3px;opacity:.5}
|
|
27
|
+
.bd-cross:after,.bd-cross:before{content:"";position:absolute;background:var(--star-cross)}
|
|
28
|
+
.bd-cross:after{height:7px;width:1px;left:1px;top:-2px}.bd-cross:before{width:7px;height:1px;left:-2px;top:1px}
|
|
29
|
+
`;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** The knot every page carries beside the wordmark, drawn in the current colour. */
|
|
2
|
+
export const BRAND_MARK = '<svg class="brand-mark" viewBox="-3 -2 46 44" fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" aria-hidden="true">' +
|
|
3
|
+
'<path d="m17 25-3 3a7.07 7.07 0 0 1-10-10l8-8a7.07 7.07 0 0 1 10 0"/>' +
|
|
4
|
+
'<path d="m23 15 3-3a7.07 7.07 0 0 1 10 10l-8 8a7.07 7.07 0 0 1-10 0"/></svg>';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export function pill(spec) {
|
|
2
|
+
const cls = 'pill pill-' + spec.tone + ' pill-' + (spec.size ?? 'md');
|
|
3
|
+
const attributes = spec.attributes ?? '';
|
|
4
|
+
if (spec.button === true)
|
|
5
|
+
return '<button type="button" class="' + cls + '"' + attributes + '>' + spec.label + '</button>';
|
|
6
|
+
return spec.href === undefined
|
|
7
|
+
? '<span class="' + cls + '"' + attributes + '>' + spec.label + '</span>'
|
|
8
|
+
: '<a class="' + cls + '" href="' + spec.href + '"' + attributes + '>' + spec.label + '</a>';
|
|
9
|
+
}
|
|
10
|
+
/** Coral words that act: "Back to this week", "✦ I'm stuck". A link, so it works with no script. Attributes arrive escaped. */
|
|
11
|
+
export function textLink(label, href, attributes = '') {
|
|
12
|
+
return '<a class="text-link" href="' + href + '"' + attributes + '>' + label + '</a>';
|
|
13
|
+
}
|
|
14
|
+
/** Coral words that act where there is nowhere to go: a script's control. */
|
|
15
|
+
export function textButton(label, attributes = '', className = '') {
|
|
16
|
+
return '<button type="button" class="text-link text-button' + (className === '' ? '' : ' ' + className) + '"' + attributes + '>' + label + '</button>';
|
|
17
|
+
}
|
|
18
|
+
/** The round × of a window. Its name is given in every language through `attributes` (`labelAttributes`). */
|
|
19
|
+
export function closeButton(attributes, size = 'md') {
|
|
20
|
+
return '<button type="button" class="close close-' + size + '"' + attributes + '>×</button>';
|
|
21
|
+
}
|
|
22
|
+
/** A bin: a simple glyph (guidelines §9.3), drawn the same wherever something is taken out. */
|
|
23
|
+
export const TRASH_SVG = '<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
|
24
|
+
'<path d="M4 7h16M9 7V4.5h6V7M6 7l1 13h10l1-13"/></svg>';
|
|
25
|
+
/**
|
|
26
|
+
* A row's round bin: takes out what the row holds. Its name is given in every language through `attributes`
|
|
27
|
+
* (`labelAttributes`). Given `href`, it is a link to the window that confirms it, so it works without a script too.
|
|
28
|
+
*/
|
|
29
|
+
export function trashButton(attributes, href) {
|
|
30
|
+
return href === undefined
|
|
31
|
+
? '<button type="button" class="close close-md trash"' + attributes + '>' + TRASH_SVG + '</button>'
|
|
32
|
+
: '<a class="close close-md trash" href="' + href + '"' + attributes + '>' + TRASH_SVG + '</a>';
|
|
33
|
+
}
|
|
34
|
+
export const BUTTON_STYLE = String.raw `
|
|
35
|
+
.pill{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;border-radius:999px;font:inherit;font-weight:600;border:1px solid transparent;cursor:pointer;transition:background .15s,border-color .15s,transform .15s}
|
|
36
|
+
.pill-sm{font-size:13px;font-weight:650;padding:6px 12px;border-radius:8px}
|
|
37
|
+
.pill-md{font-size:14px;padding:8px 16px}
|
|
38
|
+
.pill-task{font-size:14px;padding:10px 18px}
|
|
39
|
+
.pill-lg{flex:none;font-size:15px;padding:11px 20px}
|
|
40
|
+
.pill-primary{background:var(--coral);color:var(--on-coral);border-color:var(--coral)}
|
|
41
|
+
a.pill-primary:hover,button.pill-primary:hover{background:var(--coral-hover);border-color:var(--coral-hover);color:var(--on-coral)}
|
|
42
|
+
.pill-mint{background:var(--mint);color:var(--on-mint);border-color:var(--mint)}
|
|
43
|
+
a.pill-mint:hover,button.pill-mint:hover{background:var(--mint-hover);border-color:var(--mint-hover);color:var(--on-mint)}
|
|
44
|
+
.pill-light{background:var(--text);color:var(--bg);border-color:var(--text)}
|
|
45
|
+
a.pill-light:hover,button.pill-light:hover{background:var(--white);border-color:var(--white);color:var(--bg);transform:translateY(-1px)}
|
|
46
|
+
.pill-outline{background:transparent;color:var(--text-soft);border-color:var(--white-14)}
|
|
47
|
+
a.pill-outline:hover,button.pill-outline:hover{background:var(--white-05);color:var(--text)}
|
|
48
|
+
.pill-outline-coral{background:transparent;color:var(--coral-text);border-color:var(--coral-50)}
|
|
49
|
+
a.pill-outline-coral:hover,button.pill-outline-coral:hover{background:var(--coral-08);border-color:var(--coral);color:var(--coral-text)}
|
|
50
|
+
.pill-secondary{background:transparent;color:var(--text);border-color:var(--white-14);font-weight:500}
|
|
51
|
+
.pill-secondary.pill-md{padding:9px 16px}
|
|
52
|
+
a.pill-secondary:hover,button.pill-secondary:hover{background:var(--white-05);color:var(--white)}
|
|
53
|
+
.pill-quiet{background:transparent;color:var(--text-4);border-color:var(--white-08);cursor:default}
|
|
54
|
+
.text-link{color:var(--coral-text);font-size:14px;font-weight:600;padding:4px}
|
|
55
|
+
.text-link:hover{color:var(--coral-link-hover)}
|
|
56
|
+
.text-button{background:transparent;border:none;font:inherit;font-size:14px;font-weight:500;cursor:pointer;padding:6px 0}
|
|
57
|
+
.close{flex:none;border-radius:50%;background:transparent;border:1px solid var(--white-12);color:var(--text-2);line-height:1;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font:inherit}
|
|
58
|
+
.close:hover{color:var(--text);border-color:var(--white-25)}
|
|
59
|
+
.close-md{width:36px;height:36px;font-size:18px}.close-sm{width:34px;height:34px;font-size:18px}
|
|
60
|
+
.trash svg{width:17px;height:17px}
|
|
61
|
+
.trash:hover{color:var(--coral-text);border-color:var(--coral-50);background:var(--coral-08)}
|
|
62
|
+
.pill-busy{pointer-events:none}
|
|
63
|
+
.pill-busy>svg{display:none}
|
|
64
|
+
.pill-busy::before{content:"";flex:none;width:14px;height:14px;border-radius:50%;border:2px solid currentColor;border-right-color:transparent;animation:pillSpin .8s linear infinite}
|
|
65
|
+
@keyframes pillSpin{to{transform:rotate(360deg)}}
|
|
66
|
+
@media (prefers-reduced-motion:reduce){.pill-busy::before{animation:none;border-right-color:currentColor;opacity:.5}}
|
|
67
|
+
`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function callout(spec) {
|
|
2
|
+
return '<div class="co co-' + spec.tone + '"' + (spec.attributes ?? '') + '>' +
|
|
3
|
+
'<span class="co-mark" aria-hidden="true">' + (spec.tone === 'coral' ? '!' : 'i') + '</span>' +
|
|
4
|
+
'<span class="co-body">' + spec.body + '</span>' +
|
|
5
|
+
(spec.action === undefined ? '' : '<span class="co-action">' + spec.action + '</span>') +
|
|
6
|
+
'</div>';
|
|
7
|
+
}
|
|
8
|
+
export const CALLOUT_STYLE = String.raw `
|
|
9
|
+
.co{display:flex;gap:16px}
|
|
10
|
+
.co-coral{align-items:center;flex-wrap:wrap;padding:16px 20px;border-radius:14px;background:var(--coral-06);border:1px solid var(--coral-35);margin-bottom:14px}
|
|
11
|
+
.co-grey{align-items:flex-start;gap:12px;padding:14px 16px;border-radius:12px;background:var(--panel);border:1px solid var(--white-08)}
|
|
12
|
+
.co-mark{flex:none;border-radius:50%;font-weight:700;display:flex;align-items:center;justify-content:center}
|
|
13
|
+
.co-coral .co-mark{width:28px;height:28px;background:var(--coral);color:var(--on-coral);font-size:14px}
|
|
14
|
+
.co-grey .co-mark{width:22px;height:22px;background:var(--white-08);color:var(--text-soft);font-size:12px}
|
|
15
|
+
.co-body{flex:1;min-width:0}
|
|
16
|
+
.co-coral .co-body{min-width:220px;font-size:15px;line-height:1.5}
|
|
17
|
+
.co-coral .co-body strong{font-weight:650}
|
|
18
|
+
.co-grey .co-body{font-size:14.5px;line-height:1.55;color:var(--text-soft)}
|
|
19
|
+
.co-action{flex:none}
|
|
20
|
+
`;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function chatExample(spec) {
|
|
2
|
+
return '<div class="ce">' +
|
|
3
|
+
'<span class="ce-who ce-who-' + spec.tone + '" aria-hidden="true">' + spec.ai + '</span>' +
|
|
4
|
+
'<span class="ce-say ce-say-' + spec.tone + '">' + spec.answer + '</span>' +
|
|
5
|
+
'</div>';
|
|
6
|
+
}
|
|
7
|
+
export const CHAT_EXAMPLE_STYLE = String.raw `
|
|
8
|
+
.ce{display:flex;gap:8px;align-items:flex-start;margin-top:10px}
|
|
9
|
+
.ce-say{font-size:13.5px;line-height:1.45;color:var(--text);padding:7px 12px;border-radius:4px 12px 12px 12px;border:1px solid transparent}
|
|
10
|
+
.ce-say-coral{background:var(--coral-08);border-color:var(--coral-35)}
|
|
11
|
+
.ce-say-mint{background:var(--mint-07);border-color:var(--mint-30)}
|
|
12
|
+
.ce-say-grey{background:var(--white-04);border-color:var(--white-10)}
|
|
13
|
+
.ce-who{flex:none;width:22px;height:22px;margin-top:3px;border-radius:50%;font-size:9.5px;font-weight:700;display:flex;align-items:center;justify-content:center}
|
|
14
|
+
.ce-who-coral{background:var(--coral-16);color:var(--coral-text)}
|
|
15
|
+
.ce-who-mint{background:var(--mint-16);color:var(--mint)}
|
|
16
|
+
.ce-who-grey{background:var(--white-08);color:var(--text-2)}
|
|
17
|
+
`;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { pill } from './button.js';
|
|
2
|
+
export function checklist(checks, tick) {
|
|
3
|
+
return '<ul class="ck" data-checklist>' + checks.map((check) => '<li class="ck-row"><div class="ck-text"><div class="ck-name">' + check.name + '</div><div class="ck-what">' + check.what + '</div></div>' +
|
|
4
|
+
(check.link === undefined ? '' : pill({
|
|
5
|
+
label: '<span>' + check.link.label + '</span><span aria-hidden="true">↗</span>',
|
|
6
|
+
tone: 'secondary',
|
|
7
|
+
href: check.link.href,
|
|
8
|
+
attributes: ' target="_blank" rel="noopener noreferrer"',
|
|
9
|
+
})) +
|
|
10
|
+
'<button type="button" class="ck-tick js-only" aria-pressed="false" data-check><span class="ck-mark">' + tick.mark + '</span>' +
|
|
11
|
+
'<span class="ck-done">✓ ' + tick.done + '</span></button></li>').join('') + '</ul>';
|
|
12
|
+
}
|
|
13
|
+
export const CHECKLIST_STYLE = String.raw `
|
|
14
|
+
.ck{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
|
|
15
|
+
.ck-row{display:flex;align-items:center;flex-wrap:wrap;gap:12px 14px;padding:14px 16px;border-radius:14px;background:var(--raised);border:1px solid var(--white-07);transition:border-color .15s,box-shadow .15s}
|
|
16
|
+
.ck-tick{flex:none;border-radius:999px;border:1px solid var(--white-18);background:transparent;color:var(--text);font:inherit;font-size:14px;font-weight:600;padding:8px 16px;cursor:pointer;white-space:nowrap}
|
|
17
|
+
.ck-tick .ck-done{display:none}
|
|
18
|
+
.ck-row.ck-on{border-color:var(--mint-35)}
|
|
19
|
+
.ck-on .ck-tick{border-color:var(--mint-35);background:var(--mint-12);color:var(--mint)}
|
|
20
|
+
.ck-on .ck-tick .ck-mark{display:none}.ck-on .ck-tick .ck-done{display:inline}
|
|
21
|
+
.ck-row.ck-nudge{border-color:var(--coral-60);box-shadow:0 0 0 3px var(--coral-14)}
|
|
22
|
+
.ck-text{flex:1 1 220px;min-width:0}
|
|
23
|
+
.ck-name{font-size:16px;font-weight:600}
|
|
24
|
+
.ck-on .ck-name{color:var(--text-2)}
|
|
25
|
+
.ck-what{font-size:13.5px;color:var(--text-3);margin-top:2px}
|
|
26
|
+
.ck-row .pill{flex:none;font-weight:500}
|
|
27
|
+
.js .ck-row{cursor:pointer}.js .ck-row:hover{border-color:var(--white-18)}.js .ck-row:hover .ck-tick{background:var(--white-05)}
|
|
28
|
+
.js .ck-row.ck-on:hover{border-color:var(--mint-50)}.js .ck-row.ck-on:hover .ck-tick{background:var(--mint-16)}
|
|
29
|
+
`;
|
|
30
|
+
/**
|
|
31
|
+
* A tick turns its row done and back, and so does a click anywhere on the row but its link: a person clicks the card,
|
|
32
|
+
* not the circle. The list says how many are ticked, so the wizard's button can say "I did all of
|
|
33
|
+
* them" only when it is true (F52).
|
|
34
|
+
*/
|
|
35
|
+
export const CHECKLIST_SCRIPT = String.raw `
|
|
36
|
+
document.addEventListener('click', (event) => {
|
|
37
|
+
const row = event.target.closest('[data-checklist] .ck-row');
|
|
38
|
+
if (!row || event.target.closest('a')) return;
|
|
39
|
+
const tick = row.querySelector('[data-check]');
|
|
40
|
+
const on = !row.classList.contains('ck-on');
|
|
41
|
+
row.classList.toggle('ck-on', on);
|
|
42
|
+
row.classList.remove('ck-nudge');
|
|
43
|
+
tick.setAttribute('aria-pressed', String(on));
|
|
44
|
+
const list = tick.closest('[data-checklist]');
|
|
45
|
+
const all = list.querySelectorAll('.ck-row').length;
|
|
46
|
+
const ticked = list.querySelectorAll('.ck-row.ck-on').length;
|
|
47
|
+
list.dataset.ticked = String(ticked);
|
|
48
|
+
list.dispatchEvent(new CustomEvent('checklist', { bubbles: true, detail: { ticked, all } }));
|
|
49
|
+
});
|
|
50
|
+
`;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { pill } from './button.js';
|
|
2
|
+
import { CLOSES, popup } from './popup.js';
|
|
3
|
+
export function confirmDialog(spec) {
|
|
4
|
+
const title = spec.id + '-title';
|
|
5
|
+
return popup({
|
|
6
|
+
id: spec.id,
|
|
7
|
+
size: 'confirm',
|
|
8
|
+
labelledBy: title,
|
|
9
|
+
body: '<div class="cf">' +
|
|
10
|
+
(spec.glyph === '' ? '' : '<div class="cf-mark" aria-hidden="true">' + (spec.glyph ?? '⊘') + '</div>') +
|
|
11
|
+
'<h3 class="cf-title" id="' + title + '">' + spec.title + '</h3>' +
|
|
12
|
+
(spec.subject === '' ? '' : '<div class="cf-subject">' + spec.subject + '</div>') +
|
|
13
|
+
'<p class="cf-sentence">' + spec.sentence + '</p>' +
|
|
14
|
+
(spec.detail === undefined ? '' : '<div class="cf-detail">' + spec.detail + '</div>') +
|
|
15
|
+
(spec.option === '' ? '' : '<div class="cf-option">' + spec.option + '</div>') +
|
|
16
|
+
(spec.note ?? '') +
|
|
17
|
+
'<div class="cf-actions">' +
|
|
18
|
+
pill({ label: spec.cancel, tone: 'outline', size: 'lg', button: true, attributes: CLOSES }) +
|
|
19
|
+
pill({ label: spec.confirm, tone: spec.tone ?? 'mint', size: 'lg', button: true, attributes: spec.confirmAttributes }) +
|
|
20
|
+
'</div></div>',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export const CONFIRM_DIALOG_STYLE = String.raw `
|
|
24
|
+
.cf{padding:28px}
|
|
25
|
+
.cf-mark{width:48px;height:48px;border-radius:50%;background:var(--mint-14);color:var(--mint);display:flex;align-items:center;justify-content:center;font-size:22px;margin-bottom:18px}
|
|
26
|
+
.cf-title{margin:0 0 8px;font-size:22px;line-height:1.25;font-weight:650}
|
|
27
|
+
.cf-subject{margin-bottom:16px}
|
|
28
|
+
.cf-sentence{margin:0 0 24px;font-size:15px;line-height:1.55;color:var(--text-2);text-wrap:pretty}
|
|
29
|
+
.cf-option{margin:-12px 0 24px;font-size:14px;color:var(--text-2)}
|
|
30
|
+
.cf-detail{margin:-12px 0 24px;font-size:15px;line-height:1.5;color:var(--text-soft)}
|
|
31
|
+
.cf-detail ul{margin:0;padding-left:20px;display:grid;gap:8px}
|
|
32
|
+
.cf-actions{display:flex;justify-content:flex-end;gap:10px}
|
|
33
|
+
.cf-actions .pill-outline{font-weight:400}
|
|
34
|
+
`;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export function dataTable(table) {
|
|
2
|
+
const grid = ' style="grid-template-columns:' + table.columns + ';min-width:' + table.minWidth + 'px"';
|
|
3
|
+
return '<div class="dt" role="table"' + (table.attributes ?? '') + '>' +
|
|
4
|
+
'<div class="dt-head" role="row"' + grid + '>' + table.head.map((cell) => '<span role="columnheader">' + cell + '</span>').join('') + '</div>' +
|
|
5
|
+
table.rows.map((row) => 'group' in row ? group(row, table.minWidth) : 'note' in row ? note(row, table.minWidth) :
|
|
6
|
+
'<div class="dt-row' + (row.href === undefined ? '' : ' dt-linked') + '" role="row"' + grid + (row.attributes ?? '') + '>' +
|
|
7
|
+
(row.bar === true ? '<span class="dt-bar' + (row.barTone === undefined ? '' : ' dt-bar-' + row.barTone) + '" aria-hidden="true"></span>' : '') +
|
|
8
|
+
// The link sits in the first cell, since a row holds cells and nothing else; the cell is not positioned, so the
|
|
9
|
+
// link still stretches over the whole row.
|
|
10
|
+
row.cells.map((cell, at) => '<span class="dt-cell" role="cell">' + (at === 0 ? link(row) : '') + cell + '</span>').join('') +
|
|
11
|
+
'</div>').join('') +
|
|
12
|
+
(table.empty === undefined ? '' : '<div class="dt-empty" role="row" hidden><span role="cell">' + table.empty + '</span></div>') +
|
|
13
|
+
'</div>';
|
|
14
|
+
}
|
|
15
|
+
function group(row, minWidth) {
|
|
16
|
+
return '<div class="dt-group" role="row" style="min-width:' + minWidth + 'px"' + (row.attributes ?? '') + '><span class="dt-group-cell" role="cell">' +
|
|
17
|
+
'<span class="dt-group-dot dt-group-' + (row.tone ?? 'grey') + '" aria-hidden="true"></span>' + row.group +
|
|
18
|
+
(row.count === undefined ? '' : '<span class="dt-group-count">' + row.count + '</span>') + '</span></div>';
|
|
19
|
+
}
|
|
20
|
+
function note(row, minWidth) {
|
|
21
|
+
return '<div class="dt-note" role="row" style="min-width:' + minWidth + 'px"' + (row.attributes ?? '') + '><span class="dt-note-cell" role="cell">' + row.note + '</span></div>';
|
|
22
|
+
}
|
|
23
|
+
function link(row) {
|
|
24
|
+
return row.href === undefined ? '' :
|
|
25
|
+
'<a class="dt-link" href="' + row.href + '"' + (row.label === undefined ? '' : ' aria-label="' + row.label + '"') + (row.linkAttributes ?? '') + '></a>';
|
|
26
|
+
}
|
|
27
|
+
export const DATA_TABLE_STYLE = String.raw `
|
|
28
|
+
.dt{border-radius:14px;background:var(--card);border:1px solid var(--white-09);overflow-x:auto;overflow-y:hidden}
|
|
29
|
+
.dt-head,.dt-row{display:grid;column-gap:18px}
|
|
30
|
+
.dt-head{padding:12px 20px;background:var(--panel);border-bottom:1px solid var(--white-08);font-size:12.5px;font-weight:600;color:var(--text-3)}
|
|
31
|
+
.dt-row{align-items:center;position:relative;padding:16px 20px;border-bottom:1px solid var(--white-06);color:var(--text)}
|
|
32
|
+
.dt-row[hidden]{display:none}
|
|
33
|
+
.dt-linked:hover{background:var(--white-02)}
|
|
34
|
+
.dt-link{position:absolute;inset:0;z-index:1;border-radius:0}
|
|
35
|
+
.dt-link:focus-visible{outline-offset:-2px}
|
|
36
|
+
.dt-cell{min-width:0}
|
|
37
|
+
.dt-bar{position:absolute;left:0;top:15%;height:70%;width:2px;border-radius:0 2px 2px 0;background:var(--coral)}
|
|
38
|
+
.dt-bar-sand{background:var(--sand)}
|
|
39
|
+
.dt-group{padding:10px 20px;background:var(--panel);border-bottom:1px solid var(--white-08);font-size:12.5px;font-weight:600;letter-spacing:0.02em;color:var(--text-2)}
|
|
40
|
+
.dt-group[hidden]{display:none}
|
|
41
|
+
.dt-group-cell{display:flex;align-items:center;gap:8px}
|
|
42
|
+
.dt-group-dot{width:7px;height:7px;border-radius:50%;flex:none}
|
|
43
|
+
.dt-group-coral{background:var(--coral)}.dt-group-amber{background:var(--amber)}.dt-group-mint{background:var(--mint)}.dt-group-sand{background:var(--sand)}.dt-group-blue{background:var(--blue)}.dt-group-grey{background:var(--white-25)}
|
|
44
|
+
.dt-group-count{font-weight:500;color:var(--text-3)}
|
|
45
|
+
.dt-note{padding:10px 20px;border-bottom:1px solid var(--white-06)}
|
|
46
|
+
.dt-note[hidden]{display:none}
|
|
47
|
+
.dt-note-cell{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:13px;color:var(--text-3)}
|
|
48
|
+
.dt-empty{padding:28px;text-align:center;font-size:14px;color:var(--text-3)}
|
|
49
|
+
`;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { closeButton } from './button.js';
|
|
2
|
+
import { CLOSES } from './popup.js';
|
|
3
|
+
export function drawer(spec) {
|
|
4
|
+
return '<dialog class="dr" id="' + spec.id + '" aria-labelledby="' + spec.labelledBy + '">' +
|
|
5
|
+
'<div class="dr-head"><span class="dr-dot dr-dot-' + spec.tone + '" aria-hidden="true"></span>' +
|
|
6
|
+
'<div class="dr-name"><div class="dr-title" id="' + spec.labelledBy + '">' + spec.title + '</div><div class="dr-sub">' + spec.sub + '</div></div>' +
|
|
7
|
+
closeButton(spec.closeLabel + CLOSES, 'sm') + '</div>' +
|
|
8
|
+
'<div class="dr-body">' + spec.body + '</div>' +
|
|
9
|
+
(spec.foot === undefined ? '' : '<div class="dr-foot">' + spec.foot + '</div>') +
|
|
10
|
+
'</dialog>';
|
|
11
|
+
}
|
|
12
|
+
export const DRAWER_STYLE = String.raw `
|
|
13
|
+
dialog.dr{margin:0 0 0 auto;padding:0;height:100%;max-height:100%;width:480px;max-width:100%;border:0;border-left:1px solid var(--white-08);background:var(--popup);color:var(--text)}
|
|
14
|
+
dialog.dr[open]{display:flex;flex-direction:column}
|
|
15
|
+
dialog.dr::backdrop{background:var(--scrim)}
|
|
16
|
+
html:not(.js) dialog.dr:target{display:flex;flex-direction:column;position:static;height:auto;margin:24px 0 24px auto}
|
|
17
|
+
.dr-head{display:flex;align-items:center;gap:14px;padding:22px 24px;border-bottom:1px solid var(--white-07)}
|
|
18
|
+
.dr-dot{flex:none;width:10px;height:10px;border-radius:50%}
|
|
19
|
+
.dr-dot-coral{background:var(--coral)}.dr-dot-amber{background:var(--amber)}.dr-dot-blue{background:var(--blue)}.dr-dot-mint{background:var(--mint)}.dr-dot-grey{background:var(--text-4)}
|
|
20
|
+
.dr-name{flex:1;min-width:0}
|
|
21
|
+
.dr-title{font-size:19px;font-weight:650}
|
|
22
|
+
.dr-sub{font-size:13px;color:var(--text-3);margin-top:2px}
|
|
23
|
+
.dr-body{padding:24px;flex:1;overflow:auto;display:flex;flex-direction:column;gap:24px}
|
|
24
|
+
.dr-foot{padding:18px 24px;border-top:1px solid var(--white-07)}
|
|
25
|
+
`;
|