@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,77 @@
|
|
|
1
|
+
import { stars } from './backdrop.js';
|
|
2
|
+
export function popup(spec) {
|
|
3
|
+
const sky = spec.size === 'wide' ? '<div class="pp-sky" aria-hidden="true">' + stars(34) + '</div>' : '';
|
|
4
|
+
return '<dialog class="pp pp-' + spec.size + '" id="' + spec.id + '" aria-labelledby="' + spec.labelledBy + '">' + sky + spec.body + '</dialog>';
|
|
5
|
+
}
|
|
6
|
+
/** What a link or button needs to open a window: its address with no script, and the id the script opens. */
|
|
7
|
+
export function opens(id) {
|
|
8
|
+
return ' href="#' + id + '"' + opener(id);
|
|
9
|
+
}
|
|
10
|
+
/** Only the id the script opens, for a control that has its address already (a pill given `href: '#' + id`). */
|
|
11
|
+
export function opener(id) {
|
|
12
|
+
return ' data-popup-open="' + id + '"';
|
|
13
|
+
}
|
|
14
|
+
/** What a control needs to close the window it sits in. */
|
|
15
|
+
export const CLOSES = ' data-popup-close';
|
|
16
|
+
/** The strip at the bottom of a window: a grey note on the left, its actions on the right. */
|
|
17
|
+
export function popupFoot(note, actions, tight = false) {
|
|
18
|
+
return '<div class="pp-foot' + (tight ? ' pp-foot-tight' : '') + '"><span class="pp-note">' + note + '</span>' +
|
|
19
|
+
'<span class="pp-actions">' + actions + '</span></div>';
|
|
20
|
+
}
|
|
21
|
+
export const POPUP_STYLE = String.raw `
|
|
22
|
+
dialog.pp{padding:0;border:1px solid var(--white-09);border-radius:22px;background:var(--popup);color:var(--text);box-shadow:0 40px 120px var(--shadow);width:calc(100% - 40px);max-width:1200px;max-height:calc(100vh - 96px);overflow:auto;margin:48px auto auto}
|
|
23
|
+
dialog.pp-wide{background:radial-gradient(900px 300px at 35% -60px,var(--coral-08) 0%,transparent 70%) no-repeat local,radial-gradient(1200px 480px at 50% -120px,var(--glow) 0%,var(--glow-mid) 55%,transparent 100%) no-repeat local,var(--popup)}
|
|
24
|
+
dialog.pp-wide{isolation:isolate}
|
|
25
|
+
.pp-sky{position:absolute;left:0;right:0;top:0;height:min(100%,900px);z-index:-1;pointer-events:none;overflow:hidden}
|
|
26
|
+
html:not(.js) dialog.pp-wide:target{position:relative}
|
|
27
|
+
dialog.pp::backdrop{background:var(--backdrop);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
|
|
28
|
+
dialog.pp-wizard{max-width:640px;margin-top:56px;max-height:calc(100vh - 112px)}
|
|
29
|
+
dialog.pp-list{max-width:800px;margin-top:56px;max-height:calc(100vh - 112px)}
|
|
30
|
+
dialog.pp-small,dialog.pp-pick,dialog.pp-confirm{border-color:var(--white-10);border-radius:20px;margin:auto}
|
|
31
|
+
dialog.pp-small{max-width:560px}dialog.pp-pick{max-width:520px}dialog.pp-confirm{max-width:460px}
|
|
32
|
+
html:not(.js) dialog.pp:target{display:block;position:static;margin:24px auto;max-height:none}
|
|
33
|
+
.pp-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:16px 32px;border-top:1px solid var(--white-07);background:var(--popup-foot)}
|
|
34
|
+
.pp-foot-tight{padding:16px 24px}
|
|
35
|
+
.pp-note{font-size:13px;color:var(--text-3)}
|
|
36
|
+
.pp-actions{display:flex;gap:10px;align-items:center}
|
|
37
|
+
@media (max-width:640px){dialog.pp{margin-top:16px;width:calc(100% - 20px)}.pp-foot{padding:14px 18px}}
|
|
38
|
+
`;
|
|
39
|
+
/**
|
|
40
|
+
* Opens a window from its link, closes it from any control marked to, and from a click on the backdrop - the dialog
|
|
41
|
+
* itself, outside its content. Escape is the browser's. Closing gives the focus back to what opened it.
|
|
42
|
+
*/
|
|
43
|
+
export const POPUP_SCRIPT = String.raw `
|
|
44
|
+
document.addEventListener('click', (event) => {
|
|
45
|
+
const opener = event.target.closest('[data-popup-open]');
|
|
46
|
+
if (opener) {
|
|
47
|
+
const dialog = document.getElementById(opener.getAttribute('data-popup-open'));
|
|
48
|
+
if (dialog && typeof dialog.showModal === 'function') {
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
dialog.opener = opener;
|
|
51
|
+
if (!dialog.open) dialog.showModal();
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const closer = event.target.closest('[data-popup-close]');
|
|
56
|
+
if (closer) {
|
|
57
|
+
const dialog = closer.closest('dialog');
|
|
58
|
+
if (dialog) { event.preventDefault(); dialog.close(); }
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (event.target instanceof HTMLDialogElement && event.target.open) {
|
|
62
|
+
const box = event.target.getBoundingClientRect();
|
|
63
|
+
const inside = event.clientX >= box.left && event.clientX <= box.right && event.clientY >= box.top && event.clientY <= box.bottom;
|
|
64
|
+
if (!inside) event.target.close();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
document.addEventListener('close', (event) => {
|
|
68
|
+
const dialog = event.target;
|
|
69
|
+
if (dialog instanceof HTMLDialogElement && dialog.opener && typeof dialog.opener.focus === 'function') dialog.opener.focus();
|
|
70
|
+
}, true);
|
|
71
|
+
// A window named by the address is open when the page loads: a link from another page (the Files window of
|
|
72
|
+
// Conversations, F58) lands on the window it names, not on the page under it.
|
|
73
|
+
(() => {
|
|
74
|
+
const named = location.hash.length > 1 ? document.getElementById(decodeURIComponent(location.hash.slice(1))) : null;
|
|
75
|
+
if (named instanceof HTMLDialogElement && named.classList.contains('pp') && typeof named.showModal === 'function' && !named.open) named.showModal();
|
|
76
|
+
})();
|
|
77
|
+
`;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a person is (guidelines §1.5): the mint bar with "{n} of {N} done", the rail of one dash per file in the Fix it
|
|
3
|
+
* wizard, and its stepper of three steps.
|
|
4
|
+
*/
|
|
5
|
+
/** The mint bar and its words, already written in every language. */
|
|
6
|
+
export function progressBar(done, total, words) {
|
|
7
|
+
const percent = total === 0 ? 0 : Math.round((done / total) * 1000) / 10;
|
|
8
|
+
return '<span class="pg"><span class="pg-track" role="progressbar" aria-valuemin="0" aria-valuemax="' + total +
|
|
9
|
+
'" aria-valuenow="' + done + '"><span class="pg-fill" style="width:' + percent + '%"></span></span>' +
|
|
10
|
+
'<span class="pg-words">' + words + '</span></span>';
|
|
11
|
+
}
|
|
12
|
+
/** One dash per item; its title is the item's name, escaped by the caller; `item` is what a script finds it by. */
|
|
13
|
+
export function rail(dashes) {
|
|
14
|
+
return '<div class="rl" aria-hidden="true">' + dashes.map((dash) => '<span class="rl-dash rl-' + dash.state + '" title="' + dash.title + '"' +
|
|
15
|
+
(dash.item === undefined ? '' : ' data-rail-item="' + dash.item + '"') + '></span>').join('') + '</div>';
|
|
16
|
+
}
|
|
17
|
+
/** The wizard's steps: a past one carries a tick, the current one is lit, the rest wait. Labels in every language. */
|
|
18
|
+
export function stepper(steps) {
|
|
19
|
+
return '<ol class="st">' + steps.map((step, at) => '<li class="st-step st-' + step.state + '"' + (step.state === 'current' ? ' aria-current="step"' : '') + '>' +
|
|
20
|
+
'<span class="st-mark" aria-hidden="true">' + (step.state === 'past' ? '✓' : String(at + 1)) + '</span>' + step.label + '</li>').join('') + '</ol>';
|
|
21
|
+
}
|
|
22
|
+
export const PROGRESS_STYLE = String.raw `
|
|
23
|
+
.pg{display:flex;align-items:center;gap:10px;font-size:14px;color:var(--text-2)}
|
|
24
|
+
.pg-track{display:block;width:90px;height:5px;border-radius:999px;background:var(--white-08);overflow:hidden}
|
|
25
|
+
.pg-fill{display:block;height:100%;background:var(--mint);border-radius:999px;transition:width .4s}
|
|
26
|
+
.pg-words{white-space:nowrap}
|
|
27
|
+
.rl{display:flex;gap:6px;margin-bottom:18px}
|
|
28
|
+
.rl-dash{flex:1;height:5px;border-radius:3px;background:var(--white-12)}
|
|
29
|
+
.rl-now{background:var(--coral)}.rl-done{background:var(--mint)}
|
|
30
|
+
.st{flex:1;display:flex;gap:6px;justify-content:center;list-style:none;margin:0;padding:0;flex-wrap:wrap}
|
|
31
|
+
.st-step{display:flex;align-items:center;gap:7px;font-size:12.5px;font-weight:600;padding:5px 10px;border-radius:999px;color:var(--text-3)}
|
|
32
|
+
.st-mark{width:18px;height:18px;border-radius:50%;font-size:11px;display:flex;align-items:center;justify-content:center;background:var(--white-08);color:var(--text-2)}
|
|
33
|
+
.st-current{color:var(--text);background:var(--white-07)}.st-current .st-mark{background:var(--coral);color:var(--on-coral)}
|
|
34
|
+
.st-past{color:var(--mint)}.st-past .st-mark{background:var(--mint);color:var(--on-coral)}
|
|
35
|
+
`;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../html-report-components.js';
|
|
2
|
+
import { inLanguages, LANGS, translator } from '../report-copy.js';
|
|
3
|
+
import { initial } from './app-sidebar.js';
|
|
4
|
+
import { dayName, localClock } from './local-date.js';
|
|
5
|
+
import { tag } from './tag.js';
|
|
6
|
+
/** V10: at most this many rows, then how many older projects there are. */
|
|
7
|
+
const ROWS = 30;
|
|
8
|
+
/** The design's step shows five, and "Show 3 more projects" for the rest. */
|
|
9
|
+
const FIRST = 5;
|
|
10
|
+
const MINUTE = 60_000;
|
|
11
|
+
const HOUR = 60 * MINUTE;
|
|
12
|
+
/**
|
|
13
|
+
* The list of a person's projects (V10, V11), drawn as the maintainer's design of 2026-09-28 draws it: the project this
|
|
14
|
+
* page is about on its own, under "You're here now"; the others in one table, newest first, each with its status in one
|
|
15
|
+
* column and what can be done in the next - so which project to pick is plain at a glance. A row says the project's
|
|
16
|
+
* name, when it was last used and how many AI chats it has; where it is, whole, on hover. Folders that are gone are
|
|
17
|
+
* folded into one line at the table's foot, opened with no script.
|
|
18
|
+
*/
|
|
19
|
+
export function projectList(spec) {
|
|
20
|
+
const clock = localClock(spec.timeZone);
|
|
21
|
+
const today = clock(spec.now).day.number;
|
|
22
|
+
const when = (row) => lastUsed(row.newest.modifiedAt, spec.now, clock, today);
|
|
23
|
+
const here = spec.rows.find((row) => row.current);
|
|
24
|
+
const others = spec.rows.filter((row) => !row.current && row.exists);
|
|
25
|
+
const gone = spec.rows.filter((row) => !row.current && !row.exists);
|
|
26
|
+
const shown = others.slice(0, ROWS);
|
|
27
|
+
const older = others.length - shown.length;
|
|
28
|
+
if (spec.pick !== undefined)
|
|
29
|
+
return pickList(spec, spec.pick, when);
|
|
30
|
+
const action = spec.action;
|
|
31
|
+
const row = (one) => '<li class="pjl-row"' + searchable(one) + '>' + cells(one, when, action) + '</li>';
|
|
32
|
+
return '<div class="pjl">' +
|
|
33
|
+
(here === undefined ? '' :
|
|
34
|
+
'<p class="pjl-label">' + inLanguages((t) => t('proj.here')) + '</p>' +
|
|
35
|
+
'<div class="pjl-here' + (here.setUp === true ? ' pjl-here-set' : '') + '">' + cells(here, when, action) + '</div>') +
|
|
36
|
+
'<div class="pjl-label-line"><p class="pjl-label">' + inLanguages((t) => t('proj.others')) + '</p>' +
|
|
37
|
+
(others.length + gone.length === 0 ? '' : search()) + '</div>' +
|
|
38
|
+
'<p class="pjl-none" data-search-none hidden></p>' +
|
|
39
|
+
(shown.length === 0 && gone.length === 0
|
|
40
|
+
? '<p class="pjl-none">' + inLanguages((t) => t('proj.none')) + '</p>'
|
|
41
|
+
: '<div class="pjl-table">' +
|
|
42
|
+
(shown.length === 0 ? '' :
|
|
43
|
+
'<div class="pjl-heads" aria-hidden="true"><span></span><span>' + inLanguages((t) => t('proj.col.project')) + '</span>' +
|
|
44
|
+
'<span>' + inLanguages((t) => t('proj.col.status')) + '</span><span></span></div>' +
|
|
45
|
+
'<ul class="pjl-rows">' + shown.map(row).join('') + '</ul>') +
|
|
46
|
+
(gone.length === 0 ? '' :
|
|
47
|
+
'<details class="pjl-gone"><summary class="pjl-gone-line"><span>' + inLanguages((t) => t('proj.goneFold', { n: gone.length })) + '</span>' +
|
|
48
|
+
'<span class="pjl-gone-toggle"><span class="pjl-gone-show">' + inLanguages((t) => t('fold.show')) + '</span>' +
|
|
49
|
+
'<span class="pjl-gone-hide">' + inLanguages((t) => t('fold.hide')) + '</span> ▾</span></summary>' +
|
|
50
|
+
'<ul class="pjl-rows">' + gone.map((one) => '<li class="pjl-row pjl-row-gone"' + searchable(one) + '>' + cells(one, when, undefined) + '</li>').join('') + '</ul></details>') +
|
|
51
|
+
'</div>') +
|
|
52
|
+
(spec.temporary === undefined || spec.temporary === 0 ? '' : '<p class="pjl-foot">' + hiddenLine(spec.temporary, 0) + '</p>') +
|
|
53
|
+
feet(older, spec.unreadable) +
|
|
54
|
+
'</div>';
|
|
55
|
+
}
|
|
56
|
+
/** How many older projects are not drawn, and how many could not be read. */
|
|
57
|
+
function feet(older, unreadable) {
|
|
58
|
+
return (older === 0 ? '' : '<p class="pjl-foot">' + inLanguages((t) => t('proj.older', { n: older })) + '</p>') +
|
|
59
|
+
(unreadable === 0 ? '' : '<p class="pjl-foot">' + inLanguages((t) => t('proj.unreadable', { n: unreadable })) + '</p>');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The step's list (V11, the maintainer's design): "Where you started agentwhy" and its row, chosen, where the run is in a
|
|
63
|
+
* listed project; the others under "Other projects" - or "Your projects", where it is in none - five of them, and the rest
|
|
64
|
+
* behind **Show 3 more projects**, which only a script folds; what is not listed, counted beside it. Nothing is chosen
|
|
65
|
+
* where the run is in no listed project.
|
|
66
|
+
*/
|
|
67
|
+
function pickList(spec, group, when) {
|
|
68
|
+
const here = spec.rows.find((row) => row.current && row.exists);
|
|
69
|
+
const others = spec.rows.filter((row) => !row.current && row.exists);
|
|
70
|
+
const gone = spec.rows.filter((row) => !row.exists).length;
|
|
71
|
+
const shown = others.slice(0, ROWS);
|
|
72
|
+
const more = Math.max(0, shown.length - FIRST);
|
|
73
|
+
const hidden = hiddenLine(spec.temporary ?? 0, gone);
|
|
74
|
+
return '<div class="pjl pjl-picking' + (more > 0 ? ' pjl-folded' : '') + '">' +
|
|
75
|
+
(here === undefined ? '' :
|
|
76
|
+
'<p class="pjl-label">' + inLanguages((t) => t('proj.startedIn')) + '</p>' +
|
|
77
|
+
'<label class="pjl-pick pjl-pick-here">' + pickCells(here, when, group) + '</label>') +
|
|
78
|
+
'<p class="pjl-label">' + inLanguages((t) => t(here === undefined ? 'proj.yours' : 'proj.others')) + '</p>' +
|
|
79
|
+
(shown.length === 0
|
|
80
|
+
? '<p class="pjl-none">' + inLanguages((t) => t('proj.none')) + '</p>'
|
|
81
|
+
: '<div class="pjl-table"><ul class="pjl-rows">' +
|
|
82
|
+
shown.map((row, at) => '<li class="pjl-row-pick"' + (at >= FIRST ? ' data-pjl-extra' : '') + '><label class="pjl-pick">' + pickCells(row, when, group) + '</label></li>').join('') +
|
|
83
|
+
'</ul>' +
|
|
84
|
+
(more === 0 && hidden === '' ? '' :
|
|
85
|
+
'<div class="pjl-more-line">' +
|
|
86
|
+
(more === 0 ? '<span></span>' : '<button type="button" class="pjl-more js-only" data-pjl-more>' + inLanguages((t) => t('proj.more', { n: more })) + ' ▾</button>') +
|
|
87
|
+
(hidden === '' ? '' : '<span class="pjl-hidden">' + hidden + '</span>') + '</div>') +
|
|
88
|
+
'</div>') +
|
|
89
|
+
feet(others.length - shown.length, spec.unreadable) +
|
|
90
|
+
'</div>';
|
|
91
|
+
}
|
|
92
|
+
/** A row of the step: its radio, the project - "Started here" beside the run's own - and its status. */
|
|
93
|
+
function pickCells(row, when, group) {
|
|
94
|
+
return radio(group, row) +
|
|
95
|
+
'<span class="pjl-project"><span class="pjl-name-line"><span class="pjl-name" title="' + e(row.place) + '">' + e(row.name) + '</span>' +
|
|
96
|
+
(row.current ? tag(inLanguages((t) => t('proj.startedHere')), 'grey', 'badge') : '') + '</span>' +
|
|
97
|
+
'<span class="pjl-detail"><span class="pjl-in">' + inParent(row.place) + ' · </span>' + when(row) + ' · ' + inLanguages((t) => t('proj.chats', { n: row.conversations })) + '</span></span>' +
|
|
98
|
+
'<span class="pjl-status">' + status(row) + '</span>';
|
|
99
|
+
}
|
|
100
|
+
/** "in Projects": the folder a project lies in, as a person reads it - "in your home folder" where that is where. */
|
|
101
|
+
function inParent(place) {
|
|
102
|
+
const cut = Math.max(place.lastIndexOf('/'), place.lastIndexOf('\\'));
|
|
103
|
+
const parent = cut <= 0 ? place.slice(0, cut + 1) : place.slice(0, cut);
|
|
104
|
+
if (parent === '~')
|
|
105
|
+
return inLanguages((t) => t('proj.inHome'));
|
|
106
|
+
return inLanguages((t) => t('proj.in', { place: e(parent.replace(/^~[\\/]/, '')) }));
|
|
107
|
+
}
|
|
108
|
+
/** "Hidden: 1 temporary folder, 1 that no longer exists": what the list leaves out, counted. Empty where nothing is. */
|
|
109
|
+
function hiddenLine(temporary, gone) {
|
|
110
|
+
if (temporary + gone === 0)
|
|
111
|
+
return '';
|
|
112
|
+
return inLanguages((t) => t('proj.hidden', {
|
|
113
|
+
what: [temporary > 0 ? t('proj.hidden.temporary', { n: temporary }) : '', gone > 0 ? t('proj.hidden.gone', { n: gone }) : ''].filter((part) => part !== '').join(', '),
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* A small field that narrows the list as it is typed in, by a project's name or where it is (the maintainer, 2026-09-28).
|
|
118
|
+
* Only a script can narrow, so only a page with one shows it; its placeholder is set in the page's language.
|
|
119
|
+
*/
|
|
120
|
+
function search() {
|
|
121
|
+
const words = Object.fromEntries(LANGS.map((lang) => [lang, { placeholder: translator(lang)('proj.search'), none: translator(lang)('proj.noMatch', { q: '{q}' }) }]));
|
|
122
|
+
return '<input type="search" class="pjl-search js-only" data-project-search autocomplete="off" spellcheck="false"' +
|
|
123
|
+
' aria-label="' + e(translator('en')('proj.search')) + '" data-search-words="' + e(JSON.stringify(words)) + '">';
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* A row's radio, in the column where the window offers **Open**: a real one, so the keys move between the rows as they do
|
|
127
|
+
* in any group. What the page chooses by is the id, never a path (V17). The row chosen is mint, not coral (the
|
|
128
|
+
* maintainer, 2026-09-29): choosing a project is a safe thing, and coral read as a warning.
|
|
129
|
+
*/
|
|
130
|
+
function radio(group, row) {
|
|
131
|
+
return '<input type="radio" class="pjl-radio-input" name="' + e(group) + '" value="' + e(row.id) + '" data-pick-name="' + e(row.name) + '"' +
|
|
132
|
+
(row.current ? ' data-pick-here checked' : '') + '><span class="pjl-radio" aria-hidden="true"><span class="pjl-radio-dot"></span></span>';
|
|
133
|
+
}
|
|
134
|
+
/** What the field matches a row by: its name and where it is, in lower case. */
|
|
135
|
+
function searchable(row) {
|
|
136
|
+
return ' data-search="' + e((row.name + ' ' + row.place).toLowerCase()) + '"';
|
|
137
|
+
}
|
|
138
|
+
/** A row's four cells: the folder's initial, the project, its status, and what it offers. */
|
|
139
|
+
function cells(row, when, action) {
|
|
140
|
+
const detail = row.exists
|
|
141
|
+
? when(row) + ' · ' + inLanguages((t) => t('proj.chats', { n: row.conversations }))
|
|
142
|
+
: inLanguages((t) => t('proj.gone'));
|
|
143
|
+
return '<span class="pjl-mark" aria-hidden="true">' + e(initial(row.name)) + '</span>' +
|
|
144
|
+
'<span class="pjl-project"><span class="pjl-name" title="' + e(row.place) + '">' + e(row.name) + '</span>' +
|
|
145
|
+
'<span class="pjl-detail">' + detail + '</span></span>' +
|
|
146
|
+
'<span class="pjl-status">' + status(row) + '</span>' +
|
|
147
|
+
'<span class="pjl-action">' + (row.exists && action !== undefined ? action(row) : '') + '</span>';
|
|
148
|
+
}
|
|
149
|
+
/** Set up (mint), not set up yet (amber); nothing where it is not known, or the folder is gone (V10). */
|
|
150
|
+
function status(row) {
|
|
151
|
+
return !row.exists || row.setUp === undefined ? ''
|
|
152
|
+
: row.setUp ? tag(inLanguages((t) => t('proj.setUp')), 'mint') : tag(inLanguages((t) => t('proj.notSetUp')), 'amber');
|
|
153
|
+
}
|
|
154
|
+
/** "Last used 2 hours ago", "…yesterday", "…Mon, Sep 21": as near as the moment is, in the page's clock. */
|
|
155
|
+
function lastUsed(at, now, clock, today) {
|
|
156
|
+
const since = Math.max(0, now - at);
|
|
157
|
+
const day = clock(at).day;
|
|
158
|
+
const ago = (t, lang) => since < MINUTE ? t('proj.ago.now')
|
|
159
|
+
: since < HOUR ? t('proj.ago.minutes', { n: Math.floor(since / MINUTE) })
|
|
160
|
+
: day.number === today ? t('proj.ago.hours', { n: Math.floor(since / HOUR) })
|
|
161
|
+
: day.number === today - 1 ? t('proj.ago.yesterday')
|
|
162
|
+
: dayName(day, lang);
|
|
163
|
+
return inLanguages((t, lang) => t('proj.used', { when: ago(t, lang) }));
|
|
164
|
+
}
|
|
165
|
+
export const PROJECT_LIST_STYLE = String.raw `
|
|
166
|
+
.pjl{--pjl-columns:44px minmax(0,1fr) 172px 128px}
|
|
167
|
+
.pjl-label{margin:22px 4px 10px;font-size:13.5px;font-weight:600;color:var(--text-3)}
|
|
168
|
+
.pjl-label:first-child{margin-top:4px}
|
|
169
|
+
.pjl-label-line{display:flex;align-items:flex-end;justify-content:space-between;gap:12px}
|
|
170
|
+
.pjl-label-line .pjl-label{margin-top:22px}
|
|
171
|
+
.pjl-search{width:200px;margin:0 0 8px;padding:7px 12px;border-radius:999px;border:1px solid var(--white-14);background:var(--card);color:var(--text);font:inherit;font-size:13.5px}
|
|
172
|
+
.pjl-search::placeholder{color:var(--text-3)}
|
|
173
|
+
.pjl-search:focus{outline:none;border-color:var(--white-32)}
|
|
174
|
+
.pjl [hidden]{display:none!important}
|
|
175
|
+
.pjl-here,.pjl-row{display:grid;grid-template-columns:var(--pjl-columns);gap:18px;align-items:center}
|
|
176
|
+
.pjl-here{grid-template-columns:44px minmax(0,1fr) auto;padding:18px 20px;border-radius:16px;background:var(--raised);border:1px solid var(--white-28)}
|
|
177
|
+
.pjl-here .pjl-action:empty{display:none}
|
|
178
|
+
.pjl-here-set{border-color:var(--mint-50);background:var(--mint-05)}
|
|
179
|
+
.pjl-here-set .pjl-mark{background:var(--mint-14);border-color:var(--mint-30);color:var(--mint)}
|
|
180
|
+
.pjl-table{border:1px solid var(--white-09);border-radius:16px;background:var(--card);overflow:hidden}
|
|
181
|
+
.pjl-heads{display:grid;grid-template-columns:var(--pjl-columns);gap:18px;padding:13px 20px;font-size:12.5px;font-weight:600;color:var(--text-3);border-bottom:1px solid var(--white-07)}
|
|
182
|
+
.pjl-rows{list-style:none;margin:0;padding:0}
|
|
183
|
+
.pjl-row{padding:14px 20px;border-top:1px solid var(--white-07)}
|
|
184
|
+
.pjl-rows>.pjl-row:first-child{border-top:0}
|
|
185
|
+
.pjl-row-gone{opacity:.5}
|
|
186
|
+
.pjl-mark{width:44px;height:44px;border-radius:12px;display:flex;align-items:center;justify-content:center;background:var(--white-06);border:1px solid var(--white-10);color:var(--text);font-size:16px;font-weight:650}
|
|
187
|
+
.pjl-project{min-width:0;display:flex;flex-direction:column;gap:3px}
|
|
188
|
+
.pjl-name{font-size:16.5px;font-weight:600;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
189
|
+
.pjl-detail{font-size:14px;line-height:1.4;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
190
|
+
.pjl-status{display:flex;align-items:center}
|
|
191
|
+
.pjl-action{display:flex;align-items:center;justify-content:flex-end}
|
|
192
|
+
.pjl-picking .pjl-label{margin:18px 4px 8px}
|
|
193
|
+
.pjl-pick{position:relative;display:grid;grid-template-columns:22px minmax(0,1fr) auto;gap:16px;align-items:center;padding:13px 18px;cursor:pointer;transition:background .15s,border-color .2s}
|
|
194
|
+
.pjl-pick:hover{background:var(--white-04)}
|
|
195
|
+
.pjl-pick:has(:checked){background:var(--mint-05)}
|
|
196
|
+
.pjl-pick-here{border-radius:14px;background:var(--card);border:1px solid var(--white-09)}
|
|
197
|
+
.pjl-pick-here:has(:checked){border-color:var(--mint-50)}
|
|
198
|
+
.pjl-row-pick{border-top:1px solid var(--white-07)}
|
|
199
|
+
.pjl-rows>.pjl-row-pick:first-child{border-top:0}
|
|
200
|
+
.pjl-name-line{display:flex;align-items:center;gap:8px;min-width:0}
|
|
201
|
+
.pjl-picking .pjl-name{font-size:15.5px}
|
|
202
|
+
.pjl-picking .pjl-detail{font-size:13px;color:var(--text-3)}
|
|
203
|
+
.js .pjl-folded [data-pjl-extra]{display:none}
|
|
204
|
+
.pjl-more-line{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:12px 18px;border-top:1px solid var(--white-07);font-size:13px}
|
|
205
|
+
.pjl-more{background:none;border:0;padding:0;font:inherit;font-size:13.5px;font-weight:600;color:var(--text-soft);cursor:pointer}
|
|
206
|
+
.pjl-more:hover{color:var(--text)}
|
|
207
|
+
.js .pjl-picking:not(.pjl-folded) .pjl-more{display:none}
|
|
208
|
+
.pjl-hidden{color:var(--text-3);text-align:right}
|
|
209
|
+
.pjl-radio-input{position:absolute;opacity:0;width:1px;height:1px;margin:0;pointer-events:none}
|
|
210
|
+
.pjl-radio{width:22px;height:22px;border-radius:50%;border:1.5px solid var(--white-30);display:flex;align-items:center;justify-content:center;transition:border-color .2s,box-shadow .2s}
|
|
211
|
+
.pjl-radio-dot{width:11px;height:11px;border-radius:50%;transform:scale(0);transition:transform .2s cubic-bezier(.2,.9,.3,1.3),background .2s}
|
|
212
|
+
.pjl-radio-input:checked+.pjl-radio{border-color:var(--mint)}
|
|
213
|
+
.pjl-radio-input:checked+.pjl-radio .pjl-radio-dot{background:var(--mint);transform:scale(1)}
|
|
214
|
+
.pjl-radio-input:focus-visible+.pjl-radio{box-shadow:0 0 0 3px var(--coral-45)}
|
|
215
|
+
.pjl-gone{border-top:1px solid var(--white-07)}
|
|
216
|
+
.pjl-gone-line{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 20px;cursor:pointer;list-style:none;font-size:14px;color:var(--text-2)}
|
|
217
|
+
.pjl-gone-line::-webkit-details-marker{display:none}
|
|
218
|
+
.pjl-gone-line:hover{color:var(--text)}
|
|
219
|
+
.pjl-gone-toggle{font-weight:600;color:var(--text-soft);white-space:nowrap}
|
|
220
|
+
.pjl-gone-hide{display:none}.pjl-gone[open] .pjl-gone-hide{display:inline}.pjl-gone[open] .pjl-gone-show{display:none}
|
|
221
|
+
.pjl-gone .pjl-rows{border-top:1px solid var(--white-07)}
|
|
222
|
+
.pjl-foot,.pjl-none{margin:12px 4px 0;font-size:13px;line-height:1.5;color:var(--text-3)}
|
|
223
|
+
@media (max-width:720px){
|
|
224
|
+
.pjl{--pjl-columns:40px minmax(0,1fr) auto}
|
|
225
|
+
.pjl-search{width:150px}
|
|
226
|
+
.pjl-heads{display:none}
|
|
227
|
+
.pjl-here,.pjl-row,.pjl-pick{gap:6px 12px;padding:14px 16px}
|
|
228
|
+
.pjl-picking .pjl-pick{grid-template-columns:22px minmax(0,1fr)}
|
|
229
|
+
.pjl-picking .pjl-radio{grid-row:span 2}
|
|
230
|
+
.pjl-in{display:none}
|
|
231
|
+
.pjl-more-line{flex-direction:column;align-items:flex-start}.pjl-hidden{text-align:left}
|
|
232
|
+
.pjl-mark{width:40px;height:40px;grid-row:span 2}
|
|
233
|
+
.pjl-project{grid-column:2}
|
|
234
|
+
.pjl-status{grid-column:2;grid-row:2}
|
|
235
|
+
.pjl-action{grid-column:3;grid-row:1 / span 2}
|
|
236
|
+
.pjl-row .pjl-detail{display:none}
|
|
237
|
+
.pjl-here .pjl-status{grid-row:auto}
|
|
238
|
+
}
|
|
239
|
+
`;
|
|
240
|
+
/**
|
|
241
|
+
* The field narrows the rows to those whose name or place holds what is typed; a folder that is gone is looked in too,
|
|
242
|
+
* and its fold opens where it holds a match. Nothing matching is said, with the words typed.
|
|
243
|
+
*/
|
|
244
|
+
export const PROJECT_LIST_SCRIPT = String.raw `
|
|
245
|
+
(() => {
|
|
246
|
+
// The step's list: the rest of the projects, a click away.
|
|
247
|
+
document.querySelectorAll('[data-pjl-more]').forEach((button) => button.addEventListener('click', () => {
|
|
248
|
+
const list = button.closest('.pjl');
|
|
249
|
+
if (list) list.classList.remove('pjl-folded');
|
|
250
|
+
}));
|
|
251
|
+
document.querySelectorAll('[data-project-search]').forEach((input) => {
|
|
252
|
+
const list = input.closest('.pjl');
|
|
253
|
+
if (!list) return;
|
|
254
|
+
const rows = [...list.querySelectorAll('[data-search]')];
|
|
255
|
+
const none = list.querySelector('[data-search-none]');
|
|
256
|
+
const gone = list.querySelector('.pjl-gone');
|
|
257
|
+
const words = JSON.parse(input.getAttribute('data-search-words'));
|
|
258
|
+
const said = () => words[document.documentElement.dataset.lang] || words.en;
|
|
259
|
+
const place = () => { input.placeholder = said().placeholder; };
|
|
260
|
+
place();
|
|
261
|
+
const language = document.getElementById('lang');
|
|
262
|
+
if (language) language.addEventListener('change', () => setTimeout(place, 0));
|
|
263
|
+
input.addEventListener('input', () => {
|
|
264
|
+
const typed = input.value.trim();
|
|
265
|
+
const wanted = typed.toLowerCase();
|
|
266
|
+
let found = 0;
|
|
267
|
+
rows.forEach((row) => {
|
|
268
|
+
const hit = wanted === '' || row.getAttribute('data-search').includes(wanted);
|
|
269
|
+
row.hidden = !hit;
|
|
270
|
+
if (hit) found += 1;
|
|
271
|
+
});
|
|
272
|
+
if (gone) {
|
|
273
|
+
const inGone = rows.filter((row) => gone.contains(row) && !row.hidden).length;
|
|
274
|
+
gone.hidden = wanted !== '' && inGone === 0;
|
|
275
|
+
if (wanted !== '' && inGone > 0) gone.open = true;
|
|
276
|
+
}
|
|
277
|
+
if (none) {
|
|
278
|
+
none.hidden = wanted === '' || found > 0;
|
|
279
|
+
none.textContent = said().none.replace('{q}', typed);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
})();
|
|
284
|
+
`;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function scopeChoice(question, name, options, chosen = 'local') {
|
|
2
|
+
return '<fieldset class="sc"><legend class="sc-q">' + question + '</legend>' + options.map((option) => '<label class="sc-option"><input type="radio" class="sc-radio" name="' + name + '" value="' + option.value + '"' +
|
|
3
|
+
(option.value === chosen ? ' checked' : '') + '><span class="sc-ring" aria-hidden="true"></span>' +
|
|
4
|
+
'<span class="sc-text"><span class="sc-label">' + option.label + '</span><span class="sc-sub">' + option.sub + '</span></span></label>').join('') +
|
|
5
|
+
'</fieldset>';
|
|
6
|
+
}
|
|
7
|
+
export const SCOPE_CHOICE_STYLE = String.raw `
|
|
8
|
+
.sc{border:0;margin:0 0 22px;padding:0;display:flex;flex-direction:column;gap:10px}
|
|
9
|
+
.sc-q{padding:0;margin-bottom:10px;font-size:13.5px;font-weight:600;color:var(--text-3)}
|
|
10
|
+
.sc-option{position:relative;display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-radius:12px;background:var(--panel);border:1px solid var(--white-09);cursor:pointer}
|
|
11
|
+
.sc-option:has(.sc-radio:checked){background:var(--mint-07);border-color:var(--mint-50)}
|
|
12
|
+
.sc-option:has(.sc-radio:focus-visible){outline:2px solid var(--coral);outline-offset:2px}
|
|
13
|
+
.sc-radio{position:absolute;opacity:0;pointer-events:none}
|
|
14
|
+
.sc-ring{flex:none;width:20px;height:20px;border-radius:50%;border:1.5px solid var(--white-30);display:flex;align-items:center;justify-content:center;margin-top:1px}
|
|
15
|
+
.sc-ring:after{content:"";width:10px;height:10px;border-radius:50%}
|
|
16
|
+
.sc-radio:checked+.sc-ring{border-color:var(--mint)}.sc-radio:checked+.sc-ring:after{background:var(--mint)}
|
|
17
|
+
.sc-label{display:block;font-size:15px;font-weight:600}
|
|
18
|
+
.sc-sub{display:block;font-size:13.5px;line-height:1.45;color:var(--text-2);margin-top:3px}
|
|
19
|
+
`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small number with its name (Advanced's four numbers, the record tab's): `page` sits on the page, `record` inside a
|
|
3
|
+
* window. The tone colours the number only.
|
|
4
|
+
*/
|
|
5
|
+
export function stats(items, variant) {
|
|
6
|
+
return '<div class="sx sx-' + variant + '">' + items.map((item) => '<div class="sx-card"><div class="sx-label">' + item.label + '</div><div class="sx-value' +
|
|
7
|
+
(item.tone === undefined ? '' : ' sx-' + item.tone) + '">' + item.value + '</div></div>').join('') + '</div>';
|
|
8
|
+
}
|
|
9
|
+
export const STAT_STYLE = String.raw `
|
|
10
|
+
.sx{display:grid;gap:10px}
|
|
11
|
+
.sx-page{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin-bottom:16px}
|
|
12
|
+
.sx-record{grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin-bottom:28px}
|
|
13
|
+
.sx-card{border-radius:14px}
|
|
14
|
+
.sx-page .sx-card{padding:14px 18px;background:var(--card);border:1px solid var(--white-08)}
|
|
15
|
+
.sx-record .sx-card{padding:16px 18px;background:var(--raised);border:1px solid var(--white-07)}
|
|
16
|
+
.sx-label{color:var(--text-3)}
|
|
17
|
+
.sx-page .sx-label{font-size:12.5px;margin-bottom:4px}.sx-record .sx-label{font-size:13px;margin-bottom:6px}
|
|
18
|
+
.sx-value{font-weight:650;color:var(--text)}
|
|
19
|
+
.sx-page .sx-value{font-size:24px}.sx-record .sx-value{font-size:26px;letter-spacing:-0.01em}
|
|
20
|
+
.sx-coral{color:var(--coral-text)}.sx-mint{color:var(--mint)}
|
|
21
|
+
`;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { inLanguages } from '../report-copy.js';
|
|
2
|
+
import { LOOKS } from './status-look.js';
|
|
3
|
+
/**
|
|
4
|
+
* The look in a 26px circle, and its words beside it (guidelines §4, "AI icons"). `label`, already written in every
|
|
5
|
+
* language, says it of one file where the look's own words say it of a conversation ("Read it", not "Read private files").
|
|
6
|
+
*/
|
|
7
|
+
export function statusIcon(look, label) {
|
|
8
|
+
const style = LOOKS[look];
|
|
9
|
+
return glyphIcon(style.glyph, style.tone, label ?? inLanguages((t) => t(style.label)));
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Any state drawn the way a look is - a glyph in the 26px circle, its words beside it, both in the state's colour - for
|
|
13
|
+
* a state that is not what the AI did: whether a file is blocked (the Files table's mode column, `mode-icon.ts`).
|
|
14
|
+
*/
|
|
15
|
+
export function glyphIcon(glyph, tone, label) {
|
|
16
|
+
return '<span class="look look-' + tone + '"><span class="look-glyph" aria-hidden="true">' + glyph + '</span>' +
|
|
17
|
+
'<span class="look-label">' + label + '</span></span>';
|
|
18
|
+
}
|
|
19
|
+
export const STATUS_ICON_STYLE = String.raw `
|
|
20
|
+
.look{display:flex;align-items:center;gap:9px}
|
|
21
|
+
.look-glyph{flex:none;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700}
|
|
22
|
+
.look-glyph svg{width:13px;height:13px}
|
|
23
|
+
.look-label{font-size:14px;font-weight:600;line-height:1.3;white-space:nowrap}
|
|
24
|
+
.look-coral .look-glyph{background:var(--coral-16);color:var(--coral-text)}.look-coral .look-label{color:var(--coral-text)}
|
|
25
|
+
.look-amber .look-glyph{background:var(--amber-16);color:var(--amber)}.look-amber .look-label{color:var(--amber)}
|
|
26
|
+
.look-mint .look-glyph{background:var(--mint-14);color:var(--mint)}.look-mint .look-label{color:var(--mint)}
|
|
27
|
+
.look-sand .look-glyph{background:var(--sand-16);color:var(--sand)}.look-sand .look-label{color:var(--sand)}
|
|
28
|
+
.look-blue .look-glyph{background:var(--blue-16);color:var(--blue)}.look-blue .look-label{color:var(--blue)}
|
|
29
|
+
.look-grey .look-glyph{background:var(--white-06);color:var(--text-2)}.look-grey .look-label{color:var(--text-2)}
|
|
30
|
+
`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MODE_SVG } from './mode-icon.js';
|
|
2
|
+
/**
|
|
3
|
+
* One meaning, one look, read by every place a look is shown - a table row, a day tile, a guide card - so the same
|
|
4
|
+
* fact is never drawn in two colours (`.ai/plans/2026-09-23-conversations-redesign.md`, rule 5).
|
|
5
|
+
*/
|
|
6
|
+
export const LOOKS = {
|
|
7
|
+
read: { glyph: '◉', label: 'look.read', tone: 'coral', needsFix: true, attention: true, known: true },
|
|
8
|
+
// The glyph says what the AI did, which a mark does not undo; the colour says it is done (guidelines §2).
|
|
9
|
+
fixed: { glyph: '◉', label: 'look.fixed', tone: 'mint', needsFix: false, attention: false, known: true },
|
|
10
|
+
// It read them, as the person chose: Track's colour and a tick, not a read's coral ◉, since there is nothing to fix
|
|
11
|
+
// (the maintainer, 2026-09-25; violet and ◉ the same morning).
|
|
12
|
+
allowed: { glyph: '✓', label: 'look.allowed', tone: 'sand', needsFix: false, attention: true, known: true },
|
|
13
|
+
// Blue, not amber (the maintainer, 2026-09-25): a name seen is harmless, and amber sat too near Track's sand. The eye,
|
|
14
|
+
// not ○ (the maintainer, 2026-09-30): it saw the name, drawn with Settings' eye (`mode-icon.ts`).
|
|
15
|
+
name: { glyph: MODE_SVG.tell, label: 'look.name', tone: 'blue', needsFix: false, attention: false, known: true },
|
|
16
|
+
stopped: { glyph: '⊘', label: 'look.stopped', tone: 'mint', needsFix: false, attention: false, known: true },
|
|
17
|
+
none: { glyph: '✓', label: 'look.none', tone: 'grey', needsFix: false, attention: false, known: true },
|
|
18
|
+
unchecked: { glyph: '?', label: 'look.unchecked', tone: 'grey', needsFix: false, attention: false, known: false },
|
|
19
|
+
failed: { glyph: '!', label: 'look.failed', tone: 'grey', needsFix: false, attention: false, known: false },
|
|
20
|
+
outside: { glyph: '…', label: 'look.outside', tone: 'grey', needsFix: false, attention: false, known: false },
|
|
21
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function toggleSwitch(spec) {
|
|
2
|
+
return '<button type="button" class="sw' + (spec.on ? ' sw-on' : '') + '" role="switch" aria-checked="' + String(spec.on) + '"' +
|
|
3
|
+
(spec.disabled === true ? ' disabled' : '') + spec.attributes + '><span class="sw-knob" aria-hidden="true"></span></button>';
|
|
4
|
+
}
|
|
5
|
+
export const SWITCH_STYLE = String.raw `
|
|
6
|
+
.sw{flex:none;width:56px;height:32px;border-radius:999px;border:none;padding:3px;cursor:pointer;background:var(--white-16);display:flex;justify-content:flex-start;transition:background .2s}
|
|
7
|
+
.sw-on{background:var(--mint);justify-content:flex-end}
|
|
8
|
+
.sw:disabled{cursor:default}
|
|
9
|
+
.sw[aria-busy="true"]{opacity:.6;cursor:progress}
|
|
10
|
+
.sw-knob{width:26px;height:26px;border-radius:50%;background:var(--white)}
|
|
11
|
+
`;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function tag(label, tone, size = 'sm', outlined = false) {
|
|
2
|
+
return '<span class="tag tag-' + tone + ' tag-' + size + (outlined ? ' tag-outlined' : '') + '">' + (size === 'sm' ? '<span class="tag-dot" aria-hidden="true"></span>' : '') + label + '</span>';
|
|
3
|
+
}
|
|
4
|
+
export const TAG_STYLE = String.raw `
|
|
5
|
+
.tag{display:inline-flex;align-items:center;gap:7px;font-weight:600;border-radius:999px;white-space:nowrap;border:1px solid transparent}
|
|
6
|
+
.tag-sm{font-size:12.5px;padding:4px 11px}
|
|
7
|
+
.tag-md{font-size:13px;padding:8px 14px}
|
|
8
|
+
.tag-dot{width:6px;height:6px;border-radius:50%;background:currentColor}
|
|
9
|
+
.tag-coral{color:var(--coral-text);background:var(--coral-08);border-color:var(--coral-40)}
|
|
10
|
+
.tag-mint{color:var(--mint);background:var(--mint-10)}
|
|
11
|
+
.tag-md.tag-mint{background:var(--mint-12)}
|
|
12
|
+
.tag-grey{color:var(--text-3);background:var(--white-04)}
|
|
13
|
+
.tag-amber{color:var(--amber);background:var(--amber-12)}
|
|
14
|
+
.tag-sand{color:var(--sand);background:var(--sand-16)}.tag-blue{color:var(--blue);background:var(--blue-16)}
|
|
15
|
+
.tag-badge{font-size:12px;padding:2px 9px;border:0}
|
|
16
|
+
.tag-badge.tag-outlined{border:1px solid var(--white-14)}
|
|
17
|
+
.tag-outlined.tag-coral{border-color:var(--coral-35)}.tag-outlined.tag-mint{border-color:var(--mint-35)}.tag-outlined.tag-amber{border-color:var(--amber-35)}
|
|
18
|
+
.tag-badge.tag-coral{background:var(--coral-12)}.tag-badge.tag-mint{background:var(--mint-12)}.tag-badge.tag-grey{color:var(--text-2);background:var(--white-06)}
|
|
19
|
+
`;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../html-report-components.js';
|
|
2
|
+
/** `head` is the three column names, already written in every language; a list of compact cards has none. */
|
|
3
|
+
export function taskList(head, tasks) {
|
|
4
|
+
return (head === undefined ? '' :
|
|
5
|
+
'<div class="tl-head" aria-hidden="true"><span class="tl-file">' + head[0] + '</span><span>' + head[1] + '</span><span>' + head[2] + '</span></div>') +
|
|
6
|
+
'<ul class="tl">' + tasks.map(taskCard).join('') + '</ul>';
|
|
7
|
+
}
|
|
8
|
+
function taskCard(task) {
|
|
9
|
+
const compact = task.compact;
|
|
10
|
+
const chip = '<span class="tc-chip" title="' + e(task.path) + '">' + e(task.label ?? task.path) + '</span>';
|
|
11
|
+
if (compact !== undefined) {
|
|
12
|
+
return '<li class="tc tc-compact"' + (task.attributes ?? '') + '><div class="tc-row">' +
|
|
13
|
+
'<span class="tc-bar tc-bar-' + compact.bar + '" aria-hidden="true"></span>' +
|
|
14
|
+
'<a class="tc-link"' + compact.opens + compact.label + '></a>' +
|
|
15
|
+
'<span class="tc-text"><span class="tc-head"><span class="tc-title">' + task.title + '</span>' + (compact.tag ?? '') + '</span>' +
|
|
16
|
+
'<span class="tc-sub">' + chip + '<span class="tc-context">' + compact.context + '</span></span></span>' +
|
|
17
|
+
(task.details === undefined ? '' : '<span class="tc-details tc-over">' + task.details + '</span>') +
|
|
18
|
+
'<span class="tc-action">' + task.action + '</span><span class="tc-trail" aria-hidden="true">›</span></div></li>';
|
|
19
|
+
}
|
|
20
|
+
return '<li class="tc' + (task.done ? ' tc-done' : '') + '"' + (task.attributes ?? '') + '><div class="tc-row">' +
|
|
21
|
+
'<span class="tc-main"><span class="tc-check" aria-hidden="true">' + (task.done ? '✓' : '') + '</span>' +
|
|
22
|
+
'<span class="tc-text"><span class="tc-title">' + task.title + '</span>' + chip + '</span></span>' +
|
|
23
|
+
'<span class="tc-details">' + (task.details ?? '') + '</span><span class="tc-action">' + task.action + '</span></div></li>';
|
|
24
|
+
}
|
|
25
|
+
export const TASK_LIST_STYLE = String.raw `
|
|
26
|
+
.tl-head,.tc-row{display:grid;grid-template-columns:minmax(0,1fr) 150px 118px;column-gap:20px;align-items:center}
|
|
27
|
+
.tl-head{padding:0 22px 8px;font-size:12.5px;font-weight:600;color:var(--text-3)}
|
|
28
|
+
.tl-file{padding-left:40px}
|
|
29
|
+
.tl{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
|
|
30
|
+
.tc{border-radius:14px;background:var(--card);border:1px solid var(--white-09);overflow:hidden}
|
|
31
|
+
.tc-row{padding:18px 22px}
|
|
32
|
+
.tc-main{min-width:0;display:flex;align-items:center;gap:16px}
|
|
33
|
+
.tc-check{flex:none;width:24px;height:24px;border-radius:50%;border:1.5px solid var(--white-25);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;color:var(--on-mint)}
|
|
34
|
+
.tc-done .tc-check{border-color:var(--mint);background:var(--mint)}
|
|
35
|
+
.tc-text{flex:1;min-width:0}
|
|
36
|
+
.tc-title{display:block;font-size:16px;font-weight:600;line-height:1.35}
|
|
37
|
+
.tc-done .tc-title{color:var(--text-3)}
|
|
38
|
+
.tc-chip{display:inline-flex;font-family:var(--mono);font-size:14px;font-weight:500;color:var(--text);background:var(--white-07);border:1px solid var(--white-10);border-radius:6px;padding:3px 8px;margin-top:7px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
39
|
+
.tc-details,.tc-action{display:flex}
|
|
40
|
+
.tc-compact{position:relative;transition:border-color .15s}
|
|
41
|
+
.tc-compact:hover{border-color:var(--white-25)}
|
|
42
|
+
.tc-compact .tc-row{grid-auto-flow:column;grid-template-columns:minmax(0,1fr);grid-auto-columns:auto;column-gap:18px;padding:24px 20px 24px 24px}
|
|
43
|
+
.tc-over{position:relative;z-index:2}
|
|
44
|
+
.tc-bar{position:absolute;left:0;top:15%;height:70%;width:2px;border-radius:0 2px 2px 0}
|
|
45
|
+
.tc-bar-coral{background:var(--coral)}.tc-bar-amber{background:var(--amber)}
|
|
46
|
+
.tc-link{position:absolute;inset:0;z-index:1;border-radius:14px}
|
|
47
|
+
.tc-link:focus-visible{outline-offset:-2px}
|
|
48
|
+
.tc-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
|
|
49
|
+
.tc-sub{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:7px}
|
|
50
|
+
.tc-sub .tc-chip{margin-top:0}
|
|
51
|
+
.tc-context{font-size:13.5px;color:var(--text-3);white-space:nowrap}
|
|
52
|
+
.tc-trail{font-size:20px;color:var(--text-4)}
|
|
53
|
+
@media (max-width:640px){.tl-head{display:none}.tc-row{grid-template-columns:1fr;row-gap:12px}.tc-details,.tc-action{padding-left:40px}
|
|
54
|
+
.tc-compact .tc-row{grid-auto-flow:row;grid-template-columns:minmax(0,1fr) auto;padding:20px 18px 20px 20px}
|
|
55
|
+
.tc-compact .tc-text{grid-column:1/-1}.tc-compact .tc-details,.tc-compact .tc-action{padding-left:0}.tc-trail{display:none}}
|
|
56
|
+
`;
|