@songsid/agend 2.1.12-beta.9 → 2.2.0-alpha.1
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/README.md +2 -2
- package/README.zh-TW.md +2 -2
- package/dist/auth/one-time-code.d.ts +19 -0
- package/dist/auth/one-time-code.js +49 -0
- package/dist/auth/one-time-code.js.map +1 -0
- package/dist/auth-api.d.ts +52 -0
- package/dist/auth-api.js +346 -0
- package/dist/auth-api.js.map +1 -0
- package/dist/backend/claude-code.d.ts +4 -0
- package/dist/backend/claude-code.js +97 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.js +59 -30
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/kiro-agent.d.ts +66 -0
- package/dist/backend/kiro-agent.js +302 -0
- package/dist/backend/kiro-agent.js.map +1 -0
- package/dist/backend/kiro-identity.d.ts +80 -0
- package/dist/backend/kiro-identity.js +537 -0
- package/dist/backend/kiro-identity.js.map +1 -0
- package/dist/backend/kiro-v2-store-worker.d.ts +1 -0
- package/dist/backend/kiro-v2-store-worker.js +87 -0
- package/dist/backend/kiro-v2-store-worker.js.map +1 -0
- package/dist/backend/kiro-v2-store.d.ts +54 -0
- package/dist/backend/kiro-v2-store.js +131 -0
- package/dist/backend/kiro-v2-store.js.map +1 -0
- package/dist/backend/kiro-v3-identity.d.ts +5 -0
- package/dist/backend/kiro-v3-identity.js +22 -0
- package/dist/backend/kiro-v3-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +83 -7
- package/dist/backend/kiro.js +418 -91
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +45 -3
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +1 -0
- package/dist/channel/adapters/discord.js +29 -10
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +1 -0
- package/dist/channel/adapters/telegram.js +13 -1
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/types.d.ts +9 -1
- package/dist/classic-channel-manager.d.ts +18 -10
- package/dist/classic-channel-manager.js +45 -18
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +225 -127
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +5 -3
- package/dist/command-table.js +29 -27
- package/dist/command-table.js.map +1 -1
- package/dist/config-validator.js +46 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/connection-secrets.d.ts +6 -0
- package/dist/connection-secrets.js +4 -0
- package/dist/connection-secrets.js.map +1 -1
- package/dist/daemon.d.ts +89 -4
- package/dist/daemon.js +661 -77
- package/dist/daemon.js.map +1 -1
- package/dist/darwin-memory.d.ts +6 -1
- package/dist/darwin-memory.js +17 -6
- package/dist/darwin-memory.js.map +1 -1
- package/dist/delivery-consumed-watch.d.ts +85 -0
- package/dist/delivery-consumed-watch.js +244 -0
- package/dist/delivery-consumed-watch.js.map +1 -0
- package/dist/delivery-outbox.d.ts +61 -0
- package/dist/delivery-outbox.js +120 -2
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +14 -5
- package/dist/delivery-reconciliation.js +27 -4
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/delivery-reconciliation.test.js +35 -1
- package/dist/delivery-reconciliation.test.js.map +1 -1
- package/dist/event-loop-watch.d.ts +28 -0
- package/dist/event-loop-watch.js +75 -3
- package/dist/event-loop-watch.js.map +1 -1
- package/dist/fleet-context.d.ts +22 -2
- package/dist/fleet-level-config.d.ts +2 -2
- package/dist/fleet-level-config.js +6 -1
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +293 -12
- package/dist/fleet-manager.js +2364 -449
- package/dist/fleet-manager.js.map +1 -1
- package/dist/host-memory.d.ts +4 -0
- package/dist/host-memory.js.map +1 -1
- package/dist/instance-config-impact.js +5 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +10 -5
- package/dist/instance-lifecycle.js +162 -53
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +150 -16
- package/dist/locale.js.map +1 -1
- package/dist/login-controller.d.ts +2 -0
- package/dist/login-controller.js +17 -5
- package/dist/login-controller.js.map +1 -1
- package/dist/memory-pressure.d.ts +7 -8
- package/dist/memory-pressure.js +76 -15
- package/dist/memory-pressure.js.map +1 -1
- package/dist/monotonic-budget.d.ts +2 -0
- package/dist/monotonic-budget.js +28 -0
- package/dist/monotonic-budget.js.map +1 -0
- package/dist/needs-you-hub.d.ts +114 -0
- package/dist/needs-you-hub.js +370 -0
- package/dist/needs-you-hub.js.map +1 -0
- package/dist/needs-you-live.d.ts +116 -0
- package/dist/needs-you-live.js +228 -0
- package/dist/needs-you-live.js.map +1 -0
- package/dist/needs-you.d.ts +132 -0
- package/dist/needs-you.js +164 -0
- package/dist/needs-you.js.map +1 -0
- package/dist/node-version-guard.d.ts +30 -0
- package/dist/node-version-guard.js +50 -0
- package/dist/node-version-guard.js.map +1 -0
- package/dist/operator-control-paths.d.ts +4 -0
- package/dist/operator-control-paths.js +24 -0
- package/dist/operator-control-paths.js.map +1 -0
- package/dist/outbound-handlers.d.ts +2 -0
- package/dist/outbound-handlers.js +9 -2
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +5 -5
- package/dist/profile-control.js +4 -20
- package/dist/profile-control.js.map +1 -1
- package/dist/public-web-gateway.d.ts +18 -0
- package/dist/public-web-gateway.js +141 -0
- package/dist/public-web-gateway.js.map +1 -0
- package/dist/public-web-link.d.ts +53 -0
- package/dist/public-web-link.js +175 -0
- package/dist/public-web-link.js.map +1 -0
- package/dist/quickstart-api.d.ts +8 -1
- package/dist/quickstart-api.js +86 -48
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +1 -0
- package/dist/quickstart.js +6 -2
- package/dist/quickstart.js.map +1 -1
- package/dist/scheduler/db.d.ts +7 -1
- package/dist/scheduler/db.js +38 -0
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/index.d.ts +1 -1
- package/dist/scheduler/retry-label.d.ts +11 -0
- package/dist/scheduler/retry-label.js +24 -0
- package/dist/scheduler/retry-label.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +55 -2
- package/dist/scheduler/scheduler.js +220 -8
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/scheduler/types.d.ts +22 -0
- package/dist/scheduler/types.js.map +1 -1
- package/dist/secret-store.d.ts +5 -0
- package/dist/secret-store.js +20 -0
- package/dist/secret-store.js.map +1 -1
- package/dist/service-activation.d.ts +110 -0
- package/dist/service-activation.js +302 -0
- package/dist/service-activation.js.map +1 -0
- package/dist/service-installer.d.ts +7 -0
- package/dist/service-installer.js +7 -4
- package/dist/service-installer.js.map +1 -1
- package/dist/service-restart-selection.d.ts +6 -5
- package/dist/service-restart-selection.js +6 -5
- package/dist/service-restart-selection.js.map +1 -1
- package/dist/settings-api.d.ts +10 -2
- package/dist/settings-api.js +175 -72
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.d.ts +20 -0
- package/dist/settings-baseline.js +104 -0
- package/dist/settings-baseline.js.map +1 -0
- package/dist/settings-change.d.ts +21 -0
- package/dist/settings-change.js +133 -0
- package/dist/settings-change.js.map +1 -0
- package/dist/settings-confirmation.d.ts +105 -0
- package/dist/settings-confirmation.js +232 -0
- package/dist/settings-confirmation.js.map +1 -0
- package/dist/settings-control.d.ts +41 -0
- package/dist/settings-control.js +294 -0
- package/dist/settings-control.js.map +1 -0
- package/dist/settings-effect.d.ts +24 -0
- package/dist/settings-effect.js +169 -0
- package/dist/settings-effect.js.map +1 -0
- package/dist/settings-http-confirmation.d.ts +29 -0
- package/dist/settings-http-confirmation.js +123 -0
- package/dist/settings-http-confirmation.js.map +1 -0
- package/dist/settings-instance-patch.d.ts +4 -0
- package/dist/settings-instance-patch.js +26 -0
- package/dist/settings-instance-patch.js.map +1 -0
- package/dist/settings-request-capability.d.ts +16 -0
- package/dist/settings-request-capability.js +32 -0
- package/dist/settings-request-capability.js.map +1 -0
- package/dist/settings-transaction.d.ts +65 -0
- package/dist/settings-transaction.js +223 -0
- package/dist/settings-transaction.js.map +1 -0
- package/dist/setup-auth.d.ts +10 -18
- package/dist/setup-auth.js +14 -38
- package/dist/setup-auth.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +75 -18
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-guide.d.ts +13 -0
- package/dist/setup-guide.js +25 -0
- package/dist/setup-guide.js.map +1 -0
- package/dist/setup-host.d.ts +16 -0
- package/dist/setup-host.js +197 -32
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +3 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/slash-authz.d.ts +17 -3
- package/dist/slash-authz.js +5 -0
- package/dist/slash-authz.js.map +1 -1
- package/dist/spawn-gate.js +3 -3
- package/dist/spawn-gate.js.map +1 -1
- package/dist/statusline-watcher.d.ts +5 -0
- package/dist/statusline-watcher.js +2 -0
- package/dist/statusline-watcher.js.map +1 -1
- package/dist/steer-capability.d.ts +6 -0
- package/dist/steer-capability.js +8 -0
- package/dist/steer-capability.js.map +1 -1
- package/dist/sync-work-attribution.d.ts +14 -0
- package/dist/sync-work-attribution.js +43 -8
- package/dist/sync-work-attribution.js.map +1 -1
- package/dist/tips.js +10 -5
- package/dist/tips.js.map +1 -1
- package/dist/tmux-control.d.ts +35 -5
- package/dist/tmux-control.js +291 -57
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.d.ts +20 -6
- package/dist/tmux-manager.js +90 -47
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.d.ts +59 -0
- package/dist/tmux-read.js +213 -0
- package/dist/tmux-read.js.map +1 -0
- package/dist/topic-commands.d.ts +21 -10
- package/dist/topic-commands.js +191 -58
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-delta-reader.js +2 -1
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/tunnel/cloudflared-install.d.ts +2 -0
- package/dist/tunnel/cloudflared-install.js +1 -1
- package/dist/tunnel/cloudflared-install.js.map +1 -1
- package/dist/tunnel/purpose-lane.d.ts +14 -0
- package/dist/tunnel/purpose-lane.js +43 -0
- package/dist/tunnel/purpose-lane.js.map +1 -0
- package/dist/turn-reply-guard.d.ts +2 -0
- package/dist/turn-reply-guard.js +10 -1
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/ui/app.html +18 -0
- package/dist/ui/chat-render.js +478 -0
- package/dist/ui/chat-store.js +289 -0
- package/dist/ui/chat-strings.js +69 -0
- package/dist/ui/chat-thread.js +209 -0
- package/dist/ui/chat-tour.js +116 -0
- package/dist/ui/fleet-org.js +142 -0
- package/dist/ui/panel-chat.js +418 -0
- package/dist/ui/panel-fleet.js +413 -0
- package/dist/ui/panel-needs.js +202 -0
- package/dist/ui/panel-settings.js +750 -0
- package/dist/ui/preview.js +266 -0
- package/dist/ui/settings-apply.js +239 -0
- package/dist/ui/settings-confirm.js +186 -0
- package/dist/ui/settings-dialogs.js +546 -0
- package/dist/ui/settings-model.js +277 -0
- package/dist/ui/settings-strings.js +652 -0
- package/dist/ui/settings-wizard.js +140 -0
- package/dist/ui/shared/agend-auth.js +93 -0
- package/dist/ui/shared/app-ctx.js +80 -0
- package/dist/ui/shared/app-html.js +9 -0
- package/dist/ui/shared/app-i18n.js +95 -0
- package/dist/ui/shared/app-nav.js +73 -0
- package/dist/ui/shared/app-needs.js +114 -0
- package/dist/ui/shared/app-route.js +73 -0
- package/dist/ui/shared/app-session.js +66 -0
- package/dist/ui/shared/app-shell.js +344 -0
- package/dist/ui/shared/app-store.js +51 -0
- package/dist/ui/shared/app-stream.js +201 -0
- package/dist/ui/shared/app.css +676 -0
- package/dist/ui/shared/app.js +88 -0
- package/dist/ui/shared/fonts/OFL.txt +92 -0
- package/dist/ui/shared/fonts/README.md +21 -0
- package/dist/ui/shared/fonts/inter.woff2 +0 -0
- package/dist/ui/shared/htm.module.js +1 -0
- package/dist/ui/shared/panel-view.js +655 -0
- package/dist/ui/shared/preact-hooks.module.js +2 -0
- package/dist/ui/shared/preact.module.js +2 -0
- package/dist/ui/shared/signin.js +130 -0
- package/dist/ui/shared/theme.js +29 -0
- package/dist/ui/shared/tokens.css +153 -0
- package/dist/ui/shared/ui-confirm.js +43 -0
- package/dist/ui/shared/ui-dialog.js +45 -0
- package/dist/ui/shared/ui-icons.js +61 -0
- package/dist/ui/shared/ui-menu.js +39 -0
- package/dist/ui/shared/ui-states.js +20 -0
- package/dist/ui/shared/ui-toast.js +18 -0
- package/dist/ui/shared/vendor/htm.LICENSE +202 -0
- package/dist/ui/shared/vendor/preact.LICENSE +21 -0
- package/dist/ui/shared/vendor/vendor.json +39 -0
- package/dist/ui/shared/view-strings.js +309 -0
- package/dist/ui/signin.html +51 -0
- package/dist/update-check.d.ts +6 -2
- package/dist/update-check.js +12 -3
- package/dist/update-check.js.map +1 -1
- package/dist/update-install.d.ts +71 -0
- package/dist/update-install.js +162 -0
- package/dist/update-install.js.map +1 -0
- package/dist/upgrade-notices.d.ts +17 -0
- package/dist/upgrade-notices.js +93 -0
- package/dist/upgrade-notices.js.map +1 -0
- package/dist/usage/statusline-usage.d.ts +2 -0
- package/dist/usage/statusline-usage.js +14 -10
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/view-api.d.ts +6 -1
- package/dist/view-api.js +62 -51
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +71 -14
- package/dist/web-api.js +492 -77
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.d.ts +71 -27
- package/dist/web-auth.js +169 -69
- package/dist/web-auth.js.map +1 -1
- package/dist/web-body.d.ts +3 -0
- package/dist/web-body.js +55 -0
- package/dist/web-body.js.map +1 -0
- package/dist/web-channel-echo.d.ts +9 -0
- package/dist/web-channel-echo.js +55 -0
- package/dist/web-channel-echo.js.map +1 -0
- package/dist/web-chat-history.d.ts +125 -0
- package/dist/web-chat-history.js +184 -0
- package/dist/web-chat-history.js.map +1 -0
- package/dist/web-continuation.d.ts +7 -0
- package/dist/web-continuation.js +22 -0
- package/dist/web-continuation.js.map +1 -0
- package/dist/web-host-guard.d.ts +34 -0
- package/dist/web-host-guard.js +57 -1
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-login.d.ts +72 -0
- package/dist/web-login.js +132 -0
- package/dist/web-login.js.map +1 -0
- package/dist/web-org.d.ts +55 -0
- package/dist/web-org.js +67 -0
- package/dist/web-org.js.map +1 -0
- package/dist/web-preview.d.ts +77 -0
- package/dist/web-preview.js +240 -0
- package/dist/web-preview.js.map +1 -0
- package/dist/web-request-context.d.ts +10 -0
- package/dist/web-request-context.js +13 -0
- package/dist/web-request-context.js.map +1 -0
- package/dist/web-session.d.ts +167 -0
- package/dist/web-session.js +389 -0
- package/dist/web-session.js.map +1 -0
- package/dist/web-shell-routes.d.ts +59 -0
- package/dist/web-shell-routes.js +96 -0
- package/dist/web-shell-routes.js.map +1 -0
- package/dist/web-upload.d.ts +183 -0
- package/dist/web-upload.js +468 -0
- package/dist/web-upload.js.map +1 -0
- package/dist/website-tips-renderer.d.ts +2 -2
- package/dist/website-tips-renderer.js +3 -3
- package/dist/website-tips-renderer.js.map +1 -1
- package/package.json +8 -5
- package/scripts/preinstall-guard.cjs +36 -0
- package/dist/ui/dashboard.html +0 -774
- package/dist/ui/settings.html +0 -2165
- package/dist/ui/view.html +0 -1139
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{options as n}from"./preact.module.js";var t,r,u,i,o=0,f=[],c=n,e=c.__b,a=c.__r,v=c.diffed,l=c.__c,m=c.unmount,p=c.__;function s(n,t){c.__h&&c.__h(r,n,o||t),o=0;var u=r.__H||(r.__H={__:[],__h:[]});return n>=u.__.length&&u.__.push({}),u.__[n]}function d(n){return o=1,y(D,n)}function y(n,u,i){var o=s(t++,2);if(o.t=n,!o.__c&&(o.__=[i?i(u):D(void 0,u),function(n){var t=o.__N?o.__N[0]:o.__[0],r=o.t(t,n);t!==r&&(o.__N=[r,o.__[1]],o.__c.setState({}))}],o.__c=r,!r.__f)){var f=function(n,t,r){if(!o.__c.__H)return!0;var u=!1,i=o.__c.props!==n;if(o.__c.__H.__.some(function(n){if(n.__N){u=!0;var t=n.__[0];n.__=n.__N,n.__N=void 0,t!==n.__[0]&&(i=!0)}}),c){var f=c.call(this,n,t,r);return u?f||i:f}return!u||i};r.__f=!0;var c=r.shouldComponentUpdate,e=r.componentWillUpdate;r.componentWillUpdate=function(n,t,r){if(this.__e){var u=c;c=void 0,f(n,t,r),c=u}e&&e.call(this,n,t,r)},r.shouldComponentUpdate=f}return o.__N||o.__}function h(n,u){var i=s(t++,3);!c.__s&&C(i.__H,u)&&(i.__=n,i.u=u,r.__H.__h.push(i))}function _(n,u){var i=s(t++,4);!c.__s&&C(i.__H,u)&&(i.__=n,i.u=u,r.__h.push(i))}function A(n){return o=5,T(function(){return{current:n}},[])}function F(n,t,r){o=6,_(function(){if("function"==typeof n){var r=n(t());return function(){n(null),r&&"function"==typeof r&&r()}}if(n)return n.current=t(),function(){return n.current=null}},null==r?r:r.concat(n))}function T(n,r){var u=s(t++,7);return C(u.__H,r)&&(u.__=n(),u.__H=r,u.__h=n),u.__}function q(n,t){return o=8,T(function(){return n},t)}function x(n){var u=r.context[n.__c],i=s(t++,9);return i.c=n,u?(null==i.__&&(i.__=!0,u.sub(r)),u.props.value):n.__}function P(n,t){c.useDebugValue&&c.useDebugValue(t?t(n):n)}function b(n){var u=s(t++,10),i=d();return u.__=n,r.componentDidCatch||(r.componentDidCatch=function(n,t){u.__&&u.__(n,t),i[1](n)}),[i[0],function(){i[1](void 0)}]}function g(){var n=s(t++,11);if(!n.__){for(var u=r.__v;null!==u&&!u.__m&&null!==u.__;)u=u.__;var i=u.__m||(u.__m=[0,0]);n.__="P"+i[0]+"-"+i[1]++}return n.__}function j(){for(var n;n=f.shift();){var t=n.__H;if(n.__P&&t)try{t.__h.some(z),t.__h.some(B),t.__h=[]}catch(r){t.__h=[],c.__e(r,n.__v)}}}c.__b=function(n){r=null,e&&e(n)},c.__=function(n,t){n&&t.__k&&t.__k.__m&&(n.__m=t.__k.__m),p&&p(n,t)},c.__r=function(n){a&&a(n),t=0;var i=(r=n.__c).__H;i&&(u===r?(i.__h=[],r.__h=[],i.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(i.__h.some(z),i.__h.some(B),i.__h=[],t=0)),u=r},c.diffed=function(n){v&&v(n);var t=n.__c;t&&t.__H&&(t.__H.__h.length&&(1!==f.push(t)&&i===c.requestAnimationFrame||((i=c.requestAnimationFrame)||w)(j)),t.__H.__.some(function(n){n.u&&(n.__H=n.u,n.u=void 0)})),u=r=null},c.__c=function(n,t){t.some(function(n){try{n.__h.some(z),n.__h=n.__h.filter(function(n){return!n.__||B(n)})}catch(r){t.some(function(n){n.__h&&(n.__h=[])}),t=[],c.__e(r,n.__v)}}),l&&l(n,t)},c.unmount=function(n){m&&m(n);var t,r=n.__c;r&&r.__H&&(r.__H.__.some(function(n){try{z(n)}catch(n){t=n}}),r.__H=void 0,t&&c.__e(t,r.__v))};var k="function"==typeof requestAnimationFrame;function w(n){var t,r=function(){clearTimeout(u),k&&cancelAnimationFrame(t),setTimeout(n)},u=setTimeout(r,35);k&&(t=requestAnimationFrame(r))}function z(n){var t=r,u=n.__c;"function"==typeof u&&(n.__c=void 0,u()),r=t}function B(n){var t=r;n.__c=n.__(),r=t}function C(n,t){return!n||n.length!==t.length||t.some(function(t,r){return t!==n[r]})}function D(n,t){return"function"==typeof t?t(n):t}export{q as useCallback,x as useContext,P as useDebugValue,h as useEffect,b as useErrorBoundary,g as useId,F as useImperativeHandle,_ as useLayoutEffect,T as useMemo,y as useReducer,A as useRef,d as useState};
|
|
2
|
+
//# sourceMappingURL=hooks.module.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var n,l,u,t,i,r,o,e,f,c,a,s,h,p,v,y,d={},w=[],_=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,g=Array.isArray;function m(n,l){for(var u in l)n[u]=l[u];return n}function b(n){n&&n.parentNode&&n.parentNode.removeChild(n)}function k(l,u,t){var i,r,o,e={};for(o in u)"key"==o?i=u[o]:"ref"==o?r=u[o]:e[o]=u[o];if(arguments.length>2&&(e.children=arguments.length>3?n.call(arguments,2):t),"function"==typeof l&&null!=l.defaultProps)for(o in l.defaultProps)void 0===e[o]&&(e[o]=l.defaultProps[o]);return x(l,e,i,r,null)}function x(n,t,i,r,o){var e={type:n,props:t,key:i,ref:r,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:null==o?++u:o,__i:-1,__u:0};return null==o&&null!=l.vnode&&l.vnode(e),e}function M(){return{current:null}}function S(n){return n.children}function C(n,l){this.props=n,this.context=l}function $(n,l){if(null==l)return n.__?$(n.__,n.__i+1):null;for(var u;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e)return u.__e;return"function"==typeof n.type?$(n):null}function I(n){if(n.__P&&n.__d){var u=n.__v,t=u.__e,i=[],r=[],o=m({},u);o.__v=u.__v+1,l.vnode&&l.vnode(o),q(n.__P,o,u,n.__n,n.__P.namespaceURI,32&u.__u?[t]:null,i,null==t?$(u):t,!!(32&u.__u),r),o.__v=u.__v,o.__.__k[o.__i]=o,D(i,o,r),u.__e=u.__=null,o.__e!=t&&P(o)}}function P(n){if(null!=(n=n.__)&&null!=n.__c)return n.__e=n.__c.base=null,n.__k.some(function(l){if(null!=l&&null!=l.__e)return n.__e=n.__c.base=l.__e}),P(n)}function A(n){(!n.__d&&(n.__d=!0)&&i.push(n)&&!H.__r++||r!=l.debounceRendering)&&((r=l.debounceRendering)||o)(H)}function H(){try{for(var n,l=1;i.length;)i.length>l&&i.sort(e),n=i.shift(),l=i.length,I(n)}finally{i.length=H.__r=0}}function L(n,l,u,t,i,r,o,e,f,c,a){var s,h,p,v,y,_,g=t&&t.__k||w,m=l.length;for(f=T(u,l,g,f,m),s=0;s<m;s++)null!=(p=u.__k[s])&&(h=-1!=p.__i&&g[p.__i]||d,p.__i=s,_=q(n,p,h,i,r,o,e,f,c,a),v=p.__e,p.ref&&h.ref!=p.ref&&(h.ref&&J(h.ref,null,p),a.push(p.ref,p.__c||v,p)),null==y&&null!=v&&(y=v),4&p.__u?(f=j(p,f,n),h.__e&&(h.__e=null)):"function"==typeof p.type&&void 0!==_?f=_:v&&(f=v.nextSibling),p.__u&=-7);return u.__e=y,f}function T(n,l,u,t,i){var r,o,e,f,c,a=u.length,s=a,h=0;for(n.__k=new Array(i),r=0;r<i;r++)null!=(o=l[r])&&"boolean"!=typeof o&&"function"!=typeof o?("string"==typeof o||"number"==typeof o||"bigint"==typeof o||o.constructor==String?o=n.__k[r]=x(null,o,null,null,null):g(o)?o=n.__k[r]=x(S,{children:o},null,null,null):void 0===o.constructor&&o.__b>0?o=n.__k[r]=x(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):n.__k[r]=o,f=r+h,o.__=n,o.__b=n.__b+1,e=null,-1!=(c=o.__i=O(o,u,f,s))&&(s--,(e=u[c])&&(e.__u|=2)),null==e||null==e.__v?(-1==c&&(i>a?h--:i<a&&h++),"function"!=typeof o.type&&(o.__u|=4)):c!=f&&(c==f-1?h--:c==f+1?h++:(c>f?h--:h++,o.__u|=4))):n.__k[r]=null;if(s)for(r=0;r<a;r++)null!=(e=u[r])&&0==(2&e.__u)&&(e.__e==t&&(t=$(e)),K(e,e));return t}function j(n,l,u){var t,i;if("function"==typeof n.type){for(t=n.__k,i=0;t&&i<t.length;i++)t[i]&&(t[i].__=n,l=j(t[i],l,u));return l}n.__e!=l&&(l&&n.type&&!l.parentNode&&(l=$(n)),l=u.insertBefore(n.__e,l||null));do{l=l&&l.nextSibling}while(null!=l&&8==l.nodeType);return l}function F(n,l){return l=l||[],null==n||"boolean"==typeof n||(g(n)?n.some(function(n){F(n,l)}):l.push(n)),l}function O(n,l,u,t){var i,r,o,e=n.key,f=n.type,c=l[u],a=null!=c&&0==(2&c.__u);if(null===c&&null==e||a&&e==c.key&&f==c.type)return u;if(t>(a?1:0))for(i=u-1,r=u+1;i>=0||r<l.length;)if(null!=(c=l[o=i>=0?i--:r++])&&0==(2&c.__u)&&e==c.key&&f==c.type)return o;return-1}function z(n,l,u){"-"==l[0]?n.setProperty(l,null==u?"":u):n[l]=null==u?"":"number"!=typeof u||_.test(l)?u:u+"px"}function N(n,l,u,t,i){var r,o;n:if("style"==l)if("string"==typeof u)n.style.cssText=u;else{if("string"==typeof t&&(n.style.cssText=t=""),t)for(l in t)u&&l in u||z(n.style,l,"");if(u)for(l in u)t&&u[l]==t[l]||z(n.style,l,u[l])}else if("o"==l[0]&&"n"==l[1])r=l!=(l=l.replace(s,"$1")),o=l.toLowerCase(),l=o in n||"onFocusOut"==l||"onFocusIn"==l?o.slice(2):l.slice(2),n.l||(n.l={}),n.l[l+r]=u,u?t?u[a]=t[a]:(u[a]=h,n.addEventListener(l,r?v:p,r)):n.removeEventListener(l,r?v:p,r);else{if("http://www.w3.org/2000/svg"==i)l=l.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!=l&&"height"!=l&&"href"!=l&&"list"!=l&&"form"!=l&&"tabIndex"!=l&&"download"!=l&&"rowSpan"!=l&&"colSpan"!=l&&"role"!=l&&"popover"!=l&&l in n)try{n[l]=null==u?"":u;break n}catch(n){}"function"==typeof u||(null==u||!1===u&&"-"!=l[4]?n.removeAttribute(l):n.setAttribute(l,"popover"==l&&1==u?"":u))}}function V(n){return function(u){if(this.l){var t=this.l[u.type+n];if(null==u[c])u[c]=h++;else if(u[c]<t[a])return;return t(l.event?l.event(u):u)}}}function q(n,u,t,i,r,o,e,f,c,a){var s,h,p,v,y,d,_,k,x,M,I,P,A,H,T,j,F=u.type;if(void 0!==u.constructor)return null;128&t.__u&&(c=!!(32&t.__u),o=[f=u.__e=t.__e]),(s=l.__b)&&s(u);n:if("function"==typeof F){h=e.length;try{if(x=u.props,M=F.prototype&&F.prototype.render,I=(s=F.contextType)&&i[s.__c],P=s?I?I.props.value:s.__:i,t.__c?k=(p=u.__c=t.__c).__=p.__E:(M?u.__c=p=new F(x,P):(u.__c=p=new C(x,P),p.constructor=F,p.render=Q),I&&I.sub(p),p.state||(p.state={}),p.__n=i,v=p.__d=!0,p.__h=[],p._sb=[]),M&&null==p.__s&&(p.__s=p.state),M&&null!=F.getDerivedStateFromProps&&(p.__s==p.state&&(p.__s=m({},p.__s)),m(p.__s,F.getDerivedStateFromProps(x,p.__s))),y=p.props,d=p.state,p.__v=u,v)M&&null==F.getDerivedStateFromProps&&null!=p.componentWillMount&&p.componentWillMount(),M&&null!=p.componentDidMount&&p.__h.push(p.componentDidMount);else{if(M&&null==F.getDerivedStateFromProps&&x!==y&&null!=p.componentWillReceiveProps&&p.componentWillReceiveProps(x,P),u.__v==t.__v||!p.__e&&null!=p.shouldComponentUpdate&&!1===p.shouldComponentUpdate(x,p.__s,P)){u.__v!=t.__v&&(p.props=x,p.state=p.__s,p.__d=!1),u.__e=t.__e,u.__k=t.__k,u.__k.some(function(n){n&&(n.__=u)}),w.push.apply(p.__h,p._sb),p._sb=[],p.__h.length&&e.push(p),f=$(t);break n}null!=p.componentWillUpdate&&p.componentWillUpdate(x,p.__s,P),M&&null!=p.componentDidUpdate&&p.__h.push(function(){p.componentDidUpdate(y,d,_)})}if(p.context=P,p.props=x,p.__P=n,p.__e=!1,A=l.__r,H=0,M)p.state=p.__s,p.__d=!1,A&&A(u),s=p.render(p.props,p.state,p.context),w.push.apply(p.__h,p._sb),p._sb=[];else do{p.__d=!1,A&&A(u),s=p.render(p.props,p.state,p.context),p.state=p.__s}while(p.__d&&++H<25);p.state=p.__s,null!=p.getChildContext&&(i=m(m({},i),p.getChildContext())),M&&!v&&null!=p.getSnapshotBeforeUpdate&&(_=p.getSnapshotBeforeUpdate(y,d)),T=null!=s&&s.type===S&&null==s.key?E(s.props.children):s,f=L(n,g(T)?T:[T],u,t,i,r,o,e,f,c,a),p.base=u.__e,u.__u&=-161,p.__h.length&&e.push(p),k&&(p.__E=p.__=null)}catch(n){if(e.length=h,u.__v=null,c||null!=o){if(n.then){for(u.__u|=c?160:128;f&&8==f.nodeType&&f.nextSibling;)f=f.nextSibling;null!=o&&(o[o.indexOf(f)]=null),u.__e=f}else if(null!=o)for(j=o.length;j--;)b(o[j])}else u.__e=t.__e;null==u.__k&&(u.__k=t.__k||[]),n.then||B(u),l.__e(n,u,t)}}else null==o&&u.__v==t.__v?(u.__k=t.__k,u.__e=t.__e):f=u.__e=G(t.__e,u,t,i,r,o,e,c,a);return(s=l.diffed)&&s(u),128&u.__u?void 0:f}function B(n){n&&(n.__c&&(n.__c.__e=!0),n.__k&&n.__k.some(B))}function D(n,u,t){for(var i=0;i<t.length;i++)J(t[i],t[++i],t[++i]);l.__c&&l.__c(u,n),n.some(function(u){try{n=u.__h,u.__h=[],n.some(function(n){n.call(u)})}catch(n){l.__e(n,u.__v)}})}function E(n){return"object"!=typeof n||null==n||n.__b>0?n:g(n)?n.map(E):void 0!==n.constructor?null:m({},n)}function G(u,t,i,r,o,e,f,c,a){var s,h,p,v,y,w,_,m=i.props||d,k=t.props,x=t.type;if("svg"==x?o="http://www.w3.org/2000/svg":"math"==x?o="http://www.w3.org/1998/Math/MathML":o||(o="http://www.w3.org/1999/xhtml"),null!=e)for(s=0;s<e.length;s++)if((y=e[s])&&"setAttribute"in y==!!x&&(x?y.localName==x:3==y.nodeType)){u=y,e[s]=null;break}if(null==u){if(null==x)return document.createTextNode(k);u=document.createElementNS(o,x,k.is&&k),c&&(l.__m&&l.__m(t,e),c=!1),e=null}if(null==x)m===k||c&&u.data==k||(u.data=k);else{if(e="textarea"==x&&null!=k.defaultValue?null:e&&n.call(u.childNodes),!c&&null!=e)for(m={},s=0;s<u.attributes.length;s++)m[(y=u.attributes[s]).name]=y.value;for(s in m)y=m[s],"dangerouslySetInnerHTML"==s?p=y:"children"==s||s in k||"value"==s&&"defaultValue"in k||"checked"==s&&"defaultChecked"in k||N(u,s,null,y,o);for(s in k)y=k[s],"children"==s?v=y:"dangerouslySetInnerHTML"==s?h=y:"value"==s?w=y:"checked"==s?_=y:c&&"function"!=typeof y||m[s]===y||N(u,s,y,m[s],o);if(h)c||p&&(h.__html==p.__html||h.__html==u.innerHTML)||(u.innerHTML=h.__html),t.__k=[];else if(p&&(u.innerHTML=""),L("template"==t.type?u.content:u,g(v)?v:[v],t,i,r,"foreignObject"==x?"http://www.w3.org/1999/xhtml":o,e,f,e?e[0]:i.__k&&$(i,0),c,a),null!=e)for(s=e.length;s--;)b(e[s]);c&&"textarea"!=x||(s="value","progress"==x&&null==w?u.removeAttribute("value"):null!=w&&(w!==u[s]||"progress"==x&&!w||"option"==x&&w!=m[s])&&N(u,s,w,m[s],o),s="checked",null!=_&&_!=u[s]&&N(u,s,_,m[s],o))}return u}function J(n,u,t){try{if("function"==typeof n){var i="function"==typeof n.__u;i&&n.__u(),i&&null==u||(n.__u=n(u))}else n.current=u}catch(n){l.__e(n,t)}}function K(n,u,t){var i,r;if(l.unmount&&l.unmount(n),(i=n.ref)&&(i.current&&i.current!=n.__e||J(i,null,u)),null!=(i=n.__c)){if(i.componentWillUnmount)try{i.componentWillUnmount()}catch(n){l.__e(n,u)}i.base=i.__P=i.__n=null}if(i=n.__k)for(r=0;r<i.length;r++)i[r]&&K(i[r],u,t||"function"!=typeof n.type);t||b(n.__e),n.__c=n.__=n.__e=void 0}function Q(n,l,u){return this.constructor(n,u)}function R(u,t,i){var r,o,e,f;t==document&&(t=document.documentElement),l.__&&l.__(u,t),o=(r="function"==typeof i)?null:i&&i.__k||t.__k,e=[],f=[],q(t,u=(!r&&i||t).__k=k(S,null,[u]),o||d,d,t.namespaceURI,!r&&i?[i]:o?null:t.firstChild?n.call(t.childNodes):null,e,!r&&i?i:o?o.__e:t.firstChild,r,f),D(e,u,f),u.props.children=null}function U(n,l){R(n,l,U)}function W(l,u,t){var i,r,o,e,f=m({},l.props);for(o in l.type&&l.type.defaultProps&&(e=l.type.defaultProps),u)"key"==o?i=u[o]:"ref"==o?r=u[o]:f[o]=void 0===u[o]&&null!=e?e[o]:u[o];return arguments.length>2&&(f.children=arguments.length>3?n.call(arguments,2):t),x(l.type,f,i||l.key,r||l.ref,null)}function X(n){function l(n){var u,t;return this.getChildContext||(u=new Set,(t={})[l.__c]=this,this.getChildContext=function(){return t},this.componentWillUnmount=function(){u=null},this.shouldComponentUpdate=function(n){this.props.value!=n.value&&u.forEach(function(n){n.__e=!0,A(n)})},this.sub=function(n){u.add(n);var l=n.componentWillUnmount;n.componentWillUnmount=function(){u&&u.delete(n),l&&l.call(n)}}),n.children}return l.__c="__cC"+y++,l.__=n,l.Provider=l.__l=(l.Consumer=function(n,l){return n.children(l)}).contextType=l,l}n=w.slice,l={__e:function(n,l,u,t){for(var i,r,o;l=l.__;)if((i=l.__c)&&!i.__)try{if((r=i.constructor)&&null!=r.getDerivedStateFromError&&(i.setState(r.getDerivedStateFromError(n)),o=i.__d),null!=i.componentDidCatch&&(i.componentDidCatch(n,t||{}),o=i.__d),o)return i.__E=i}catch(l){n=l}throw n}},u=0,t=function(n){return null!=n&&void 0===n.constructor},C.prototype.setState=function(n,l){var u;u=null!=this.__s&&this.__s!=this.state?this.__s:this.__s=m({},this.state),"function"==typeof n&&(n=n(m({},u),this.props)),n&&m(u,n),null!=n&&this.__v&&(l&&this._sb.push(l),A(this))},C.prototype.forceUpdate=function(n){this.__v&&(this.__e=!0,n&&this.__h.push(n),A(this))},C.prototype.render=S,i=[],o="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,e=function(n,l){return n.__v.__b-l.__v.__b},H.__r=0,f=Math.random().toString(8),c="__d"+f,a="__a"+f,s=/(PointerCapture)$|Capture$/i,h=0,p=V(!1),v=V(!0),y=0;export{C as Component,S as Fragment,W as cloneElement,X as createContext,k as createElement,M as createRef,k as h,U as hydrate,t as isValidElement,l as options,R as render,F as toChildArray};
|
|
2
|
+
//# sourceMappingURL=preact.module.js.map
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Sign-in page logic. Loaded from /assets/signin.js.
|
|
2
|
+
//
|
|
3
|
+
// Two jobs: (1) when the page is what a gated URL answered with because the browser sent no cookie
|
|
4
|
+
// (a SameSite=Strict cookie is not sent on a navigation that came from a chat app), probe the session
|
|
5
|
+
// from *here* — a same-site request does carry the cookie — and carry on to the page that was asked
|
|
6
|
+
// for; (2) otherwise take the one-time code and exchange it.
|
|
7
|
+
(() => {
|
|
8
|
+
"use strict";
|
|
9
|
+
const $ = (id) => document.getElementById(id);
|
|
10
|
+
const T = {
|
|
11
|
+
en: {
|
|
12
|
+
checking: "Checking your session…", title: "Sign in to AgEnD", lead: "Enter the one-time code from your chat channel.",
|
|
13
|
+
label: "One-time code", submit: "Sign in", working: "Signing in…",
|
|
14
|
+
hint: "Send /dashboard to your AgEnD bot, or run “agend web --code” on the host. A code works once and expires in 5 minutes.",
|
|
15
|
+
refused: "That code did not work — it may be wrong, expired or already used. Ask for a new one with /dashboard.",
|
|
16
|
+
paused: "Too many wrong codes — sign-in is paused for a few minutes.",
|
|
17
|
+
network: "Could not reach AgEnD. Check the connection and try again.",
|
|
18
|
+
},
|
|
19
|
+
"zh-TW": {
|
|
20
|
+
checking: "正在確認登入狀態…", title: "登入 AgEnD", lead: "請輸入聊天頻道給你的一次性登入碼。",
|
|
21
|
+
label: "一次性登入碼", submit: "登入", working: "登入中…",
|
|
22
|
+
hint: "在 AgEnD bot 傳 /dashboard,或在主機執行「agend web --code」。登入碼只能用一次,5 分鐘內有效。",
|
|
23
|
+
refused: "登入碼無效:可能輸入錯誤、已過期或已使用。請用 /dashboard 再要一個。",
|
|
24
|
+
paused: "錯誤次數過多,登入暫停幾分鐘。",
|
|
25
|
+
network: "連不上 AgEnD,請檢查連線後再試。",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
const lang = /^zh/i.test(navigator.language || "") ? "zh-TW" : "en";
|
|
29
|
+
const t = (k) => T[lang][k] || T.en[k] || k;
|
|
30
|
+
document.documentElement.lang = lang === "zh-TW" ? "zh-Hant" : "en";
|
|
31
|
+
|
|
32
|
+
// An old dashboard link carries `?token=`. It is not a credential any more (the server ignored it and
|
|
33
|
+
// answered with this page), but it is still the fleet's token: take it out of the address bar and
|
|
34
|
+
// the history entry at once, so it is not copied, bookmarked or shared from here.
|
|
35
|
+
try {
|
|
36
|
+
const here = new URL(location.href);
|
|
37
|
+
if (here.searchParams.has("token")) {
|
|
38
|
+
here.searchParams.delete("token");
|
|
39
|
+
history.replaceState(null, "", here.pathname + here.search + here.hash);
|
|
40
|
+
}
|
|
41
|
+
} catch { /* nothing to clean */ }
|
|
42
|
+
document.querySelectorAll("[data-i18n]").forEach((el) => { el.textContent = t(el.getAttribute("data-i18n")); });
|
|
43
|
+
|
|
44
|
+
// An old deep link, /ui#instance=<name> (#1408 §3): the fragment never reaches the server, and the sign-in page is
|
|
45
|
+
// served at the URL that was asked for, so it is still in location.hash here. Exactly that one form becomes the new
|
|
46
|
+
// path /ui/chat/<name>; any other fragment is dropped. The name is held to the same rule as the server's.
|
|
47
|
+
function legacyChatTarget(pathname, hash) {
|
|
48
|
+
if (pathname !== "/ui") return null;
|
|
49
|
+
const m = /^#instance=([^&#]*)$/.exec(hash || "");
|
|
50
|
+
if (!m) return null;
|
|
51
|
+
let name;
|
|
52
|
+
try { name = decodeURIComponent(m[1]); } catch { return null; }
|
|
53
|
+
if (!name || name.length > 128 || /[/\\\u0000-\u001f\u007f]/.test(name) || name === "." || name.includes("..")) return null;
|
|
54
|
+
return "/ui/chat/" + encodeURIComponent(name);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Where to go afterwards: only the app's pages, never an arbitrary URL.
|
|
58
|
+
function nextTarget() {
|
|
59
|
+
let candidate = new URLSearchParams(location.search).get("next");
|
|
60
|
+
if (!candidate && location.pathname !== "/signin") {
|
|
61
|
+
const legacy = legacyChatTarget(location.pathname, location.hash);
|
|
62
|
+
if (legacy) return legacy;
|
|
63
|
+
candidate = location.pathname + location.search;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const u = new URL(candidate || "/ui", location.origin);
|
|
67
|
+
u.searchParams.delete("token");
|
|
68
|
+
const path = u.pathname;
|
|
69
|
+
if (u.origin === location.origin && /^\/(ui|view|settings)(\/|$)/.test(path) && !candidate.includes("\\")) return path + u.search;
|
|
70
|
+
} catch { /* fall through */ }
|
|
71
|
+
return "/ui";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const BOUNCE_KEY = "agend_signin_bounce";
|
|
75
|
+
function recentlyBounced() {
|
|
76
|
+
try { return Date.now() - Number(sessionStorage.getItem(BOUNCE_KEY) || 0) < 10000; } catch { return false; }
|
|
77
|
+
}
|
|
78
|
+
function markBounce() { try { sessionStorage.setItem(BOUNCE_KEY, String(Date.now())); } catch { /* private mode */ } }
|
|
79
|
+
function clearBounce() { try { sessionStorage.removeItem(BOUNCE_KEY); } catch { /* private mode */ } }
|
|
80
|
+
|
|
81
|
+
function showForm() {
|
|
82
|
+
$("checking").hidden = true;
|
|
83
|
+
$("form").hidden = false;
|
|
84
|
+
// A sign-out the server could not make durable says so here, once (agend-auth.js signOut).
|
|
85
|
+
try {
|
|
86
|
+
const note = sessionStorage.getItem("agend_signout_note");
|
|
87
|
+
if (note) { sessionStorage.removeItem("agend_signout_note"); $("msg").textContent = note; }
|
|
88
|
+
} catch { /* private mode */ }
|
|
89
|
+
$("code").focus();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function probe() {
|
|
93
|
+
// A second bounce inside ten seconds means the cookie is valid but not being sent on the
|
|
94
|
+
// navigation; going round again would loop, so stop and let the person type a code.
|
|
95
|
+
if (recentlyBounced()) return false;
|
|
96
|
+
try {
|
|
97
|
+
const r = await fetch("/auth/session", { credentials: "same-origin", cache: "no-store" });
|
|
98
|
+
return r.ok;
|
|
99
|
+
} catch { return false; }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
$("form").addEventListener("submit", async (event) => {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
const button = $("go");
|
|
105
|
+
const msg = $("msg");
|
|
106
|
+
msg.textContent = "";
|
|
107
|
+
button.disabled = true;
|
|
108
|
+
button.textContent = t("working");
|
|
109
|
+
try {
|
|
110
|
+
const r = await fetch("/auth/login", {
|
|
111
|
+
method: "POST",
|
|
112
|
+
credentials: "same-origin",
|
|
113
|
+
headers: { "Content-Type": "application/json" },
|
|
114
|
+
body: JSON.stringify({ code: $("code").value }),
|
|
115
|
+
});
|
|
116
|
+
if (r.ok) { clearBounce(); location.replace(nextTarget()); return; }
|
|
117
|
+
msg.textContent = r.status === 429 ? t("paused") : t("refused");
|
|
118
|
+
} catch {
|
|
119
|
+
msg.textContent = t("network");
|
|
120
|
+
}
|
|
121
|
+
button.disabled = false;
|
|
122
|
+
button.textContent = t("submit");
|
|
123
|
+
$("code").select();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
probe().then((signedIn) => {
|
|
127
|
+
if (signedIn) { markBounce(); location.replace(nextTarget()); return; }
|
|
128
|
+
showForm();
|
|
129
|
+
});
|
|
130
|
+
})();
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Light / dark for a panel (#1307). Loaded from /assets/theme.js in <head>, before the page paints, so a chosen theme
|
|
2
|
+
// never flashes the other one first. "system" (the default) follows the device's prefers-color-scheme through CSS;
|
|
3
|
+
// "light" or "dark" is this browser's own choice and lives in localStorage, like agend_lang.
|
|
4
|
+
//
|
|
5
|
+
// A page's tokens follow the pattern: dark under :root, light under @media (prefers-color-scheme: light) for
|
|
6
|
+
// :root:not([data-theme="dark"]), and again under :root[data-theme="light"].
|
|
7
|
+
(function () {
|
|
8
|
+
"use strict";
|
|
9
|
+
var KEY = "agend_theme";
|
|
10
|
+
function valid(v) { return v === "light" || v === "dark" ? v : "system"; }
|
|
11
|
+
function read() {
|
|
12
|
+
try { return valid(localStorage.getItem(KEY)); } catch (e) { return "system"; } // storage blocked: follow the device
|
|
13
|
+
}
|
|
14
|
+
function apply(v) {
|
|
15
|
+
var root = document.documentElement;
|
|
16
|
+
if (v === "system") root.removeAttribute("data-theme");
|
|
17
|
+
else root.setAttribute("data-theme", v);
|
|
18
|
+
}
|
|
19
|
+
apply(read());
|
|
20
|
+
window.AgendTheme = {
|
|
21
|
+
get: read,
|
|
22
|
+
/** Choose "system", "light" or "dark" for this browser; applied now even when it cannot be stored. */
|
|
23
|
+
set: function (v) {
|
|
24
|
+
v = valid(v);
|
|
25
|
+
try { if (v === "system") localStorage.removeItem(KEY); else localStorage.setItem(KEY, v); } catch (e) { /* this page only */ }
|
|
26
|
+
apply(v);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
})();
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/* Design tokens for every web panel (#1408). Served as /assets/tokens.css; nothing here is a component.
|
|
2
|
+
*
|
|
3
|
+
* Semantic names only: a rule says what a colour is FOR (the page, the sidebar, secondary text), never which colour it
|
|
4
|
+
* is. The look is neutral greys with few borders: areas differ by background tone, not by lines (design §2).
|
|
5
|
+
*
|
|
6
|
+
* Themes follow /assets/theme.js: dark under :root; light under @media (prefers-color-scheme: light) for
|
|
7
|
+
* :root:not([data-theme="dark"]), and again under :root[data-theme="light"] for a browser that chose light. The two
|
|
8
|
+
* light blocks carry the same values (a test compares them). Every text colour meets WCAG AA (4.5:1) on the
|
|
9
|
+
* surfaces it is used on, and focus rings and strong borders meet 3:1 (tests/web-tokens-1408.test.ts).
|
|
10
|
+
*
|
|
11
|
+
* Inter is bundled (/assets/inter.woff2, SIL OFL 1.1 — see fonts/README.md): the CSP allows fonts from 'self' only,
|
|
12
|
+
* and nothing is loaded from another site. Chinese falls back to the system's CJK fonts, in the order below. */
|
|
13
|
+
|
|
14
|
+
@font-face {
|
|
15
|
+
font-family: "Inter";
|
|
16
|
+
font-style: normal;
|
|
17
|
+
font-weight: 100 900;
|
|
18
|
+
font-display: swap;
|
|
19
|
+
src: url("/assets/inter.woff2") format("woff2");
|
|
20
|
+
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:root {
|
|
24
|
+
/* ── Type ── */
|
|
25
|
+
--font-ui: Inter, "PingFang TC", "Noto Sans TC", "Microsoft JhengHei", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
26
|
+
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
|
27
|
+
--fs-xs: 12px; --lh-xs: 16px;
|
|
28
|
+
--fs-sm: 13px; --lh-sm: 18px;
|
|
29
|
+
--fs-md: 15px; --lh-md: 24px; /* message text */
|
|
30
|
+
--fs-lg: 17px; --lh-lg: 24px;
|
|
31
|
+
--fs-xl: 22px; --lh-xl: 28px;
|
|
32
|
+
--fw-regular: 400; --fw-medium: 500; --fw-semibold: 600; --fw-bold: 700;
|
|
33
|
+
|
|
34
|
+
/* ── Space (a 4px grid) ── */
|
|
35
|
+
--s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 20px; --s-6: 24px; --s-7: 32px; --s-8: 48px;
|
|
36
|
+
|
|
37
|
+
/* ── Shape and motion ── */
|
|
38
|
+
--r-sm: 8px; --r-md: 12px; --r-lg: 16px; --r-xl: 24px; --r-full: 999px;
|
|
39
|
+
--t-fast: 120ms; --t-med: 200ms; --ease: cubic-bezier(0.2, 0, 0, 1);
|
|
40
|
+
|
|
41
|
+
/* ── Layout ── */
|
|
42
|
+
--col: 768px; /* the conversation column */
|
|
43
|
+
--sidebar-w: 260px;
|
|
44
|
+
--header-h: 52px;
|
|
45
|
+
--tap: 44px; /* the smallest touch target on a phone */
|
|
46
|
+
|
|
47
|
+
/* ── Colour: dark ── */
|
|
48
|
+
color-scheme: dark;
|
|
49
|
+
--bg: #212121; /* the main area */
|
|
50
|
+
--bg-sidebar: #171717;
|
|
51
|
+
--surface: #2f2f2f; /* the composer, a user's bubble, cards, menus */
|
|
52
|
+
--surface-2: #3a3a3a; /* hover and pressed rows, raised chips */
|
|
53
|
+
--border: #3d3d3d; /* used rarely: tone separates areas */
|
|
54
|
+
--border-strong: #7a7a7a;
|
|
55
|
+
--text: #ececec;
|
|
56
|
+
--text-2: #b4b4b4; /* secondary: senders, labels */
|
|
57
|
+
--text-3: #a3a3a3; /* tertiary: times, hints, metadata */
|
|
58
|
+
--accent: #7ab7ff; /* links and selected text */
|
|
59
|
+
--accent-fill: #ececec; /* the primary button (Send) */
|
|
60
|
+
--on-accent: #0d0d0d;
|
|
61
|
+
--accent-dim: rgba(122, 183, 255, 0.14);
|
|
62
|
+
--focus: #7ab7ff;
|
|
63
|
+
--ok: #4cc38a;
|
|
64
|
+
--warn: #e3b341;
|
|
65
|
+
--danger: #ff8a80;
|
|
66
|
+
--danger-fill: #c9372c; /* a destructive button; its text is --on-danger */
|
|
67
|
+
--on-danger: #ffffff;
|
|
68
|
+
--ok-bg: rgba(76, 195, 138, 0.14);
|
|
69
|
+
--warn-bg: rgba(227, 179, 65, 0.14); --warn-line: rgba(227, 179, 65, 0.45);
|
|
70
|
+
--danger-bg: rgba(255, 138, 128, 0.14); --danger-line: rgba(255, 138, 128, 0.45);
|
|
71
|
+
--user-bubble: #2f2f2f;
|
|
72
|
+
--code-bg: #171717;
|
|
73
|
+
--code-head: #2a2a2a;
|
|
74
|
+
--inline-code: #383838;
|
|
75
|
+
--tk-k: #ff7b72; --tk-s: #a5d6ff; --tk-n: #79c0ff; --tk-c: #9da5ae;
|
|
76
|
+
--scrim: rgba(0, 0, 0, 0.55);
|
|
77
|
+
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
78
|
+
--shadow-2: 0 8px 28px rgba(0, 0, 0, 0.5);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@media (prefers-color-scheme: light) {
|
|
82
|
+
:root:not([data-theme="dark"]) {
|
|
83
|
+
color-scheme: light;
|
|
84
|
+
--bg: #ffffff;
|
|
85
|
+
--bg-sidebar: #f9f9f9;
|
|
86
|
+
--surface: #f4f4f4;
|
|
87
|
+
--surface-2: #ececec;
|
|
88
|
+
--border: #e5e5e5;
|
|
89
|
+
--border-strong: #858585;
|
|
90
|
+
--text: #0d0d0d;
|
|
91
|
+
--text-2: #5d5d5d;
|
|
92
|
+
--text-3: #696969;
|
|
93
|
+
--accent: #0a62c2;
|
|
94
|
+
--accent-fill: #0d0d0d;
|
|
95
|
+
--on-accent: #ffffff;
|
|
96
|
+
--accent-dim: rgba(10, 98, 194, 0.08);
|
|
97
|
+
--focus: #0a62c2;
|
|
98
|
+
--ok: #1a7f37;
|
|
99
|
+
--warn: #8a5a00;
|
|
100
|
+
--danger: #c4222b;
|
|
101
|
+
--danger-fill: #c4222b;
|
|
102
|
+
--on-danger: #ffffff;
|
|
103
|
+
--ok-bg: #e6f4ea;
|
|
104
|
+
--warn-bg: #fff6d6; --warn-line: #e3b341;
|
|
105
|
+
--danger-bg: #ffebe9; --danger-line: #ff8182;
|
|
106
|
+
--user-bubble: #f4f4f4;
|
|
107
|
+
--code-bg: #f9f9f9;
|
|
108
|
+
--code-head: #ececec;
|
|
109
|
+
--inline-code: #ececec;
|
|
110
|
+
--tk-k: #c4222b; --tk-s: #0a3069; --tk-n: #0550ae; --tk-c: #5d646c;
|
|
111
|
+
--scrim: rgba(13, 13, 13, 0.4);
|
|
112
|
+
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
113
|
+
--shadow-2: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
:root[data-theme="light"] {
|
|
118
|
+
color-scheme: light;
|
|
119
|
+
--bg: #ffffff;
|
|
120
|
+
--bg-sidebar: #f9f9f9;
|
|
121
|
+
--surface: #f4f4f4;
|
|
122
|
+
--surface-2: #ececec;
|
|
123
|
+
--border: #e5e5e5;
|
|
124
|
+
--border-strong: #858585;
|
|
125
|
+
--text: #0d0d0d;
|
|
126
|
+
--text-2: #5d5d5d;
|
|
127
|
+
--text-3: #696969;
|
|
128
|
+
--accent: #0a62c2;
|
|
129
|
+
--accent-fill: #0d0d0d;
|
|
130
|
+
--on-accent: #ffffff;
|
|
131
|
+
--accent-dim: rgba(10, 98, 194, 0.08);
|
|
132
|
+
--focus: #0a62c2;
|
|
133
|
+
--ok: #1a7f37;
|
|
134
|
+
--warn: #8a5a00;
|
|
135
|
+
--danger: #c4222b;
|
|
136
|
+
--danger-fill: #c4222b;
|
|
137
|
+
--on-danger: #ffffff;
|
|
138
|
+
--ok-bg: #e6f4ea;
|
|
139
|
+
--warn-bg: #fff6d6; --warn-line: #e3b341;
|
|
140
|
+
--danger-bg: #ffebe9; --danger-line: #ff8182;
|
|
141
|
+
--user-bubble: #f4f4f4;
|
|
142
|
+
--code-bg: #f9f9f9;
|
|
143
|
+
--code-head: #ececec;
|
|
144
|
+
--inline-code: #ececec;
|
|
145
|
+
--tk-k: #c4222b; --tk-s: #0a3069; --tk-n: #0550ae; --tk-c: #5d646c;
|
|
146
|
+
--scrim: rgba(13, 13, 13, 0.4);
|
|
147
|
+
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
148
|
+
--shadow-2: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@media (prefers-reduced-motion: reduce) {
|
|
152
|
+
:root { --t-fast: 0ms; --t-med: 0ms; }
|
|
153
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// #1408 step 5: the app's own "are you sure?" — in place of the browser's confirm(), which looked like another
|
|
2
|
+
// program and could not say which button does what. One at a time, in the app's dialog (focus trapped, Esc and the
|
|
3
|
+
// backdrop say no, a bottom sheet on a phone). Text only.
|
|
4
|
+
import { html } from "./app-html.js";
|
|
5
|
+
import { createStore, useStore } from "./app-store.js";
|
|
6
|
+
import { Dialog } from "./ui-dialog.js";
|
|
7
|
+
import { t } from "./app-i18n.js";
|
|
8
|
+
|
|
9
|
+
/** Pending questions, oldest first: { id, title, message, confirmLabel, danger, resolve }. */
|
|
10
|
+
export const confirmStore = createStore({ queue: [] });
|
|
11
|
+
let seq = 0;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Ask. Resolves true for the confirm button, false for Cancel, Esc, the backdrop or ×.
|
|
15
|
+
* `message` may hold blank lines (paragraphs); it is shown as text.
|
|
16
|
+
*/
|
|
17
|
+
export function confirmDialog({ title, message, confirmLabel, danger = false } = {}) {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
const item = { id: ++seq, title: title || t("app.confirmTitle"), message: String(message || ""), confirmLabel: confirmLabel || t("app.confirmOk"), danger, resolve };
|
|
20
|
+
confirmStore.set((s) => ({ queue: [...s.queue, item] }));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Answer the oldest question (the host's buttons; tests may call it too). */
|
|
25
|
+
export function answerConfirm(id, yes) {
|
|
26
|
+
const item = confirmStore.get().queue.find((q) => q.id === id);
|
|
27
|
+
if (!item) return;
|
|
28
|
+
confirmStore.set((s) => ({ queue: s.queue.filter((q) => q.id !== id) }));
|
|
29
|
+
item.resolve(!!yes);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The shell renders this once: the oldest question as a dialog. */
|
|
33
|
+
export function ConfirmHost() {
|
|
34
|
+
const { queue } = useStore(confirmStore);
|
|
35
|
+
const q = queue[0];
|
|
36
|
+
if (!q) return null;
|
|
37
|
+
const paragraphs = q.message.split(/\n{2,}/);
|
|
38
|
+
return html`<${Dialog} key=${q.id} title=${q.title} onClose=${() => answerConfirm(q.id, false)}
|
|
39
|
+
actions=${html`<button type="button" class="btn" onClick=${() => answerConfirm(q.id, false)}>${t("app.cancel")}</button>
|
|
40
|
+
<button type="button" class=${`btn ${q.danger ? "btn-danger" : "btn-primary"}`} data-confirm="yes" onClick=${() => answerConfirm(q.id, true)}>${q.confirmLabel}</button>`}>
|
|
41
|
+
${paragraphs.map((p, i) => html`<p key=${i} class="confirm-text">${p}</p>`)}
|
|
42
|
+
</${Dialog}>`;
|
|
43
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// #1408 §7: one dialog for the whole app — the native <dialog> opened with showModal(), so the browser traps focus,
|
|
2
|
+
// makes the rest inert and closes it on Esc. Focus goes back to whatever opened it. On a phone it is a bottom sheet
|
|
3
|
+
// with its own × (app.css). Text and buttons only; no style attribute (#1300).
|
|
4
|
+
import { html, useEffect, useLayoutEffect, useRef } from "./app-html.js";
|
|
5
|
+
import { Icon } from "./ui-icons.js";
|
|
6
|
+
import { t } from "./app-i18n.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* <${Dialog} title="Create task" onClose=${…} actions=${html`…`}>…body…</${Dialog}>
|
|
10
|
+
* Rendered = open; the parent unmounts it to close. `busy` keeps Esc and the backdrop from closing it mid-request.
|
|
11
|
+
*/
|
|
12
|
+
export function Dialog({ title, onClose, actions, children, busy = false, wide = false, label }) {
|
|
13
|
+
const ref = useRef(null);
|
|
14
|
+
const opener = useRef(null);
|
|
15
|
+
const busyRef = useRef(busy);
|
|
16
|
+
busyRef.current = busy;
|
|
17
|
+
useLayoutEffect(() => {
|
|
18
|
+
const d = ref.current;
|
|
19
|
+
opener.current = typeof document !== "undefined" ? document.activeElement : null;
|
|
20
|
+
if (d && typeof d.showModal === "function" && !d.open) d.showModal();
|
|
21
|
+
return () => {
|
|
22
|
+
if (d && d.open && typeof d.close === "function") d.close();
|
|
23
|
+
const back = opener.current;
|
|
24
|
+
if (back && typeof back.focus === "function" && document.contains?.(back)) back.focus();
|
|
25
|
+
};
|
|
26
|
+
}, []);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const d = ref.current;
|
|
29
|
+
if (!d) return undefined;
|
|
30
|
+
// Esc: the browser fires "cancel"; we close through the parent so its state stays the truth.
|
|
31
|
+
const onCancel = (e) => { e.preventDefault(); if (!busyRef.current) onClose(); };
|
|
32
|
+
// A click on the backdrop lands on the <dialog> element itself, outside its inner box.
|
|
33
|
+
const onClick = (e) => { if (e.target === d && !busyRef.current) onClose(); };
|
|
34
|
+
d.addEventListener("cancel", onCancel);
|
|
35
|
+
d.addEventListener("click", onClick);
|
|
36
|
+
return () => { d.removeEventListener("cancel", onCancel); d.removeEventListener("click", onClick); };
|
|
37
|
+
}, [onClose]);
|
|
38
|
+
return html`<dialog ref=${ref} class=${`dlg${wide ? " dlg-wide" : ""}`} aria-label=${label || title}>
|
|
39
|
+
<div class="dlg-box">
|
|
40
|
+
<div class="dlg-head"><h2 class="dlg-title">${title}</h2>
|
|
41
|
+
<button type="button" class="icon-btn dlg-x" aria-label=${t("app.close")} title=${t("app.close")} onClick=${() => { if (!busyRef.current) onClose(); }}><${Icon} name="close" /></button></div>
|
|
42
|
+
<div class="dlg-body">${children}</div>
|
|
43
|
+
${actions ? html`<div class="dlg-actions">${actions}</div>` : null}
|
|
44
|
+
</div></dialog>`;
|
|
45
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// #1408 §2: our own icon set — 24-px line icons, 2-px stroke, currentColor. No third-party or brand assets.
|
|
2
|
+
// Each path is built fresh per use (a Preact vnode must not be mounted twice).
|
|
3
|
+
// Decorative by default (aria-hidden); the button around one carries the label.
|
|
4
|
+
import { html } from "./app-html.js";
|
|
5
|
+
|
|
6
|
+
const P = {
|
|
7
|
+
menu: () => html`<path d="M4 6h16M4 12h16M4 18h16"/>`,
|
|
8
|
+
sidebar: () => html`<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M9 4v16"/>`,
|
|
9
|
+
plus: () => html`<path d="M12 5v14M5 12h14"/>`,
|
|
10
|
+
edit: () => html`<path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/>`,
|
|
11
|
+
more: () => html`<circle cx="5" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="19" cy="12" r="1.5"/>`,
|
|
12
|
+
chat: () => html`<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>`,
|
|
13
|
+
fleet: () => html`<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>`,
|
|
14
|
+
view: () => html`<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/>`,
|
|
15
|
+
settings: () => html`<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/>`,
|
|
16
|
+
attach: () => html`<path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/>`,
|
|
17
|
+
send: () => html`<path d="M12 19V5M5 12l7-7 7 7"/>`,
|
|
18
|
+
stop: () => html`<rect x="6" y="6" width="12" height="12" rx="2"/>`,
|
|
19
|
+
copy: () => html`<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>`,
|
|
20
|
+
file: () => html`<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/>`,
|
|
21
|
+
close: () => html`<path d="M18 6L6 18M6 6l12 12"/>`,
|
|
22
|
+
play: () => html`<path d="M6 4l14 8-14 8z"/>`,
|
|
23
|
+
restart: () => html`<path d="M1 4v6h6M23 20v-6h-6"/><path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"/>`,
|
|
24
|
+
trash: () => html`<path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>`,
|
|
25
|
+
info: () => html`<circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/>`,
|
|
26
|
+
sun: () => html`<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/>`,
|
|
27
|
+
globe: () => html`<circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 0 1 0 20M12 2a15 15 0 0 0 0 20"/>`,
|
|
28
|
+
user: () => html`<circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/>`,
|
|
29
|
+
tasks: () => html`<path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/>`,
|
|
30
|
+
clock: () => html`<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>`,
|
|
31
|
+
team: () => html`<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/>`,
|
|
32
|
+
sliders: () => html`<path d="M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6"/>`,
|
|
33
|
+
down: () => html`<path d="M12 5v14M19 12l-7 7-7-7"/>`,
|
|
34
|
+
alert: () => html`<path d="M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/><path d="M12 9v4M12 17h.01"/>`,
|
|
35
|
+
chevron: () => html`<path d="M6 9l6 6 6-6"/>`,
|
|
36
|
+
search: () => html`<circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/>`,
|
|
37
|
+
type: () => html`<path d="M4 7V5h16v2M9 19h6M12 5v14"/>`,
|
|
38
|
+
chart: () => html`<path d="M3 20h18M6 16v-4M11 16V8M16 16v-6"/>`,
|
|
39
|
+
up: () => html`<path d="M12 19V5M5 12l7-7 7 7"/>`,
|
|
40
|
+
eye: () => html`<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>`,
|
|
41
|
+
check: () => html`<path d="M20 6L9 17l-5-5"/>`,
|
|
42
|
+
inbox: () => html`<path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/>`,
|
|
43
|
+
bell: () => html`<path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>`,
|
|
44
|
+
bot: () => html`<rect x="4" y="8" width="16" height="12" rx="2"/><path d="M12 8V4M9 4h6"/><path d="M9 13h.01M15 13h.01M9 17h6"/>`,
|
|
45
|
+
plug: () => html`<path d="M9 2v6M15 2v6M6 8h12v4a6 6 0 0 1-12 0z"/><path d="M12 18v4"/>`,
|
|
46
|
+
room: () => html`<path d="M3 21V9l9-6 9 6v12"/><path d="M9 21v-6h6v6"/>`,
|
|
47
|
+
code: () => html`<path d="M16 18l6-6-6-6M8 6l-6 6 6 6"/>`,
|
|
48
|
+
wand: () => html`<path d="M15 4V2M15 10V8M11 6H9M21 6h-2M18.5 3.5l-1.4 1.4M18.5 8.5l-1.4-1.4"/><path d="M3 21l11-11"/>`,
|
|
49
|
+
key: () => html`<circle cx="7.5" cy="15.5" r="4.5"/><path d="M10.7 12.3L21 2M17 6l3 3M14 9l2 2"/>`,
|
|
50
|
+
pause: () => html`<path d="M8 5v14M16 5v14"/>`,
|
|
51
|
+
download: () => html`<path d="M12 3v12M7 10l5 5 5-5M5 21h14"/>`,
|
|
52
|
+
org: () => html`<rect x="9" y="2" width="6" height="5" rx="1"/><rect x="2" y="17" width="6" height="5" rx="1"/><rect x="16" y="17" width="6" height="5" rx="1"/><path d="M12 7v5M5 17v-5h14v5"/>`,
|
|
53
|
+
external: () => html`<path d="M14 4h6v6M20 4l-9 9"/><path d="M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5"/>`,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** <${Icon} name="menu" />; `size` 16 / 18 / 20 / 24. */
|
|
57
|
+
export function Icon({ name, size = 18, cls = "" }) {
|
|
58
|
+
return html`<svg class=${`icon ${cls}`} width=${size} height=${size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
59
|
+
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${P[name] ? P[name]() : null}</svg>`;
|
|
60
|
+
}
|
|
61
|
+
export const ICON_NAMES = Object.keys(P);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// #1408 §7: the ⋯ menu — a button and a list of actions. Arrow keys move, Enter/Space choose, Esc closes and puts focus
|
|
2
|
+
// back on the button. Esc inside the menu is the menu's: it never reaches the app (e.g. never stops an agent's reply).
|
|
3
|
+
import { html, useEffect, useRef, useState } from "./app-html.js";
|
|
4
|
+
import { Icon } from "./ui-icons.js";
|
|
5
|
+
import { t } from "./app-i18n.js";
|
|
6
|
+
|
|
7
|
+
/** items: [{ key, label, icon?, onSelect, danger?, disabled? }] (falsy entries are skipped). */
|
|
8
|
+
export function Menu({ items, label, icon = "more", cls = "" }) {
|
|
9
|
+
const [open, setOpen] = useState(false);
|
|
10
|
+
const btn = useRef(null), list = useRef(null);
|
|
11
|
+
const shown = (items || []).filter(Boolean);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!open) return undefined;
|
|
14
|
+
const first = list.current && list.current.querySelector("[role=menuitem]:not([disabled])");
|
|
15
|
+
if (first) first.focus();
|
|
16
|
+
const outside = (e) => { if (list.current && !list.current.contains(e.target) && btn.current && !btn.current.contains(e.target)) setOpen(false); };
|
|
17
|
+
document.addEventListener("pointerdown", outside, true);
|
|
18
|
+
return () => document.removeEventListener("pointerdown", outside, true);
|
|
19
|
+
}, [open]);
|
|
20
|
+
function onKey(e) {
|
|
21
|
+
const all = [...list.current.querySelectorAll("[role=menuitem]:not([disabled])")];
|
|
22
|
+
const i = all.indexOf(document.activeElement);
|
|
23
|
+
if (e.key === "Escape") { e.preventDefault(); e.stopPropagation(); setOpen(false); btn.current && btn.current.focus(); }
|
|
24
|
+
else if (e.key === "ArrowDown") { e.preventDefault(); (all[(i + 1) % all.length] || all[0])?.focus(); }
|
|
25
|
+
else if (e.key === "ArrowUp") { e.preventDefault(); (all[(i - 1 + all.length) % all.length] || all[0])?.focus(); }
|
|
26
|
+
else if (e.key === "Home") { e.preventDefault(); all[0]?.focus(); }
|
|
27
|
+
else if (e.key === "End") { e.preventDefault(); all[all.length - 1]?.focus(); }
|
|
28
|
+
else if (e.key === "Tab") setOpen(false);
|
|
29
|
+
}
|
|
30
|
+
function choose(item) { setOpen(false); btn.current && btn.current.focus(); item.onSelect(); }
|
|
31
|
+
return html`<div class=${`menu ${cls}`}>
|
|
32
|
+
<button ref=${btn} type="button" class="icon-btn" aria-haspopup="menu" aria-expanded=${open ? "true" : "false"}
|
|
33
|
+
aria-label=${label || t("app.more")} title=${label || t("app.more")} onClick=${() => setOpen(!open)}><${Icon} name=${icon} /></button>
|
|
34
|
+
${open ? html`<div ref=${list} class="menu-list" role="menu" aria-label=${label || t("app.more")} onKeyDown=${onKey}>
|
|
35
|
+
${shown.map(item => html`<button key=${item.key} type="button" role="menuitem" class=${`menu-item${item.danger ? " danger" : ""}`}
|
|
36
|
+
disabled=${!!item.disabled} onClick=${() => choose(item)}>${item.icon ? html`<${Icon} name=${item.icon} size=${16} />` : null}<span>${item.label}</span></button>`)}
|
|
37
|
+
</div>` : null}
|
|
38
|
+
</div>`;
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// #1408 §6: one set of empty / loading / error states for every panel.
|
|
2
|
+
import { html } from "./app-html.js";
|
|
3
|
+
import { Icon } from "./ui-icons.js";
|
|
4
|
+
import { t } from "./app-i18n.js";
|
|
5
|
+
|
|
6
|
+
/** Placeholder lines while something loads. Shown only after 300 ms (CSS), so a fast load never flashes. */
|
|
7
|
+
export function Skeleton({ lines = 3 }) {
|
|
8
|
+
return html`<div class="skeleton" aria-busy="true" aria-label=${t("app.loading")}>${Array.from({ length: lines }, (_, i) => html`<div key=${i} class="sk-line"></div>`)}</div>`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function Empty({ icon = "info", title, hint, action }) {
|
|
12
|
+
return html`<div class="empty"><${Icon} name=${icon} size=${32} cls="empty-icon" />
|
|
13
|
+
<p class="empty-title">${title}</p>${hint ? html`<p class="empty-hint">${hint}</p>` : null}${action || null}</div>`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function ErrorState({ message, onRetry }) {
|
|
17
|
+
return html`<div class="error-state" role="alert"><${Icon} name="alert" size=${24} />
|
|
18
|
+
<p>${message || t("app.loadFailed")}</p>
|
|
19
|
+
${onRetry ? html`<button type="button" class="btn" onClick=${onRetry}>${t("app.retry")}</button>` : null}</div>`;
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Toasts: one stack in a corner (under the header on a phone), each gone after a few seconds. Text only.
|
|
2
|
+
import { html, useEffect, useState } from "./app-html.js";
|
|
3
|
+
import { createStore } from "./app-store.js";
|
|
4
|
+
|
|
5
|
+
const toasts = createStore([]);
|
|
6
|
+
let seq = 0;
|
|
7
|
+
|
|
8
|
+
export function toast(text, ok = true) {
|
|
9
|
+
const id = ++seq;
|
|
10
|
+
toasts.set(list => [...list, { id, text: String(text), ok }]);
|
|
11
|
+
setTimeout(() => toasts.set(list => list.filter(x => x.id !== id)), 4000);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function Toasts() {
|
|
15
|
+
const [list, setList] = useState(toasts.get());
|
|
16
|
+
useEffect(() => toasts.subscribe(setList), []);
|
|
17
|
+
return html`<div class="toasts" role="status" aria-live="polite">${list.map(x => html`<div key=${x.id} class=${`toast ${x.ok ? "ok" : "err"}`}>${x.text}</div>`)}</div>`;
|
|
18
|
+
}
|