@monkey-mini-app/dsh-mini-app 0.1.0 → 0.1.4
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 +59 -0
- package/assets/apps-list.png +0 -0
- package/assets/complex-demo-app.png +0 -0
- package/assets/demo-app.png +0 -0
- package/assets/home.png +0 -0
- package/assets/sidebar-mode.png +0 -0
- package/lib/client.js +2024 -783
- package/lib/index.d.ts +5 -2
- package/lib/index.js +29 -16
- package/package.json +12 -10
- package/skills/monkey-mini-app/SKILL.md +182 -106
- package/skills/monkey-mini-app/references/catalog.md +236 -99
- package/skills/monkey-mini-app/references/contracts/accordion.md +30 -0
- package/skills/monkey-mini-app/references/contracts/activity-feed.md +12 -2
- package/skills/monkey-mini-app/references/contracts/alert-dialog.md +38 -0
- package/skills/monkey-mini-app/references/contracts/alert.md +38 -0
- package/skills/monkey-mini-app/references/contracts/app-shell.md +2 -2
- package/skills/monkey-mini-app/references/contracts/aspect-ratio.md +25 -0
- package/skills/monkey-mini-app/references/contracts/attachment-gallery.md +12 -2
- package/skills/monkey-mini-app/references/contracts/attachment.md +35 -0
- package/skills/monkey-mini-app/references/contracts/autocomplete.md +12 -2
- package/skills/monkey-mini-app/references/contracts/avatar.md +24 -0
- package/skills/monkey-mini-app/references/contracts/badge.md +26 -0
- package/skills/monkey-mini-app/references/contracts/breadcrumb.md +33 -0
- package/skills/monkey-mini-app/references/contracts/bubble.md +30 -0
- package/skills/monkey-mini-app/references/contracts/button-group.md +36 -0
- package/skills/monkey-mini-app/references/contracts/button.md +26 -0
- package/skills/monkey-mini-app/references/contracts/calendar.md +20 -0
- package/skills/monkey-mini-app/references/contracts/card.md +41 -0
- package/skills/monkey-mini-app/references/contracts/cascader.md +12 -2
- package/skills/monkey-mini-app/references/contracts/chart.md +32 -0
- package/skills/monkey-mini-app/references/contracts/checkbox.md +19 -0
- package/skills/monkey-mini-app/references/contracts/code-block.md +20 -2
- package/skills/monkey-mini-app/references/contracts/code-editor.md +30 -4
- package/skills/monkey-mini-app/references/contracts/collapsible.md +21 -0
- package/skills/monkey-mini-app/references/contracts/color-picker.md +12 -2
- package/skills/monkey-mini-app/references/contracts/combobox.md +34 -0
- package/skills/monkey-mini-app/references/contracts/command.md +41 -0
- package/skills/monkey-mini-app/references/contracts/comment-thread.md +12 -2
- package/skills/monkey-mini-app/references/contracts/commit-graph.md +50 -0
- package/skills/monkey-mini-app/references/contracts/confirm-dialog.md +20 -2
- package/skills/monkey-mini-app/references/contracts/context-menu.md +41 -0
- package/skills/monkey-mini-app/references/contracts/copyable.md +12 -2
- package/skills/monkey-mini-app/references/contracts/currency-input.md +12 -2
- package/skills/monkey-mini-app/references/contracts/dashboard-shell.md +41 -0
- package/skills/monkey-mini-app/references/contracts/data-grid.md +13 -6
- package/skills/monkey-mini-app/references/contracts/date-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/date-range-picker.md +10 -2
- package/skills/monkey-mini-app/references/contracts/date-time-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/date-time-range-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/description-list.md +12 -2
- package/skills/monkey-mini-app/references/contracts/detail-panel.md +10 -2
- package/skills/monkey-mini-app/references/contracts/dialog.md +44 -0
- package/skills/monkey-mini-app/references/contracts/diff-viewer.md +21 -2
- package/skills/monkey-mini-app/references/contracts/donut-chart.md +14 -2
- package/skills/monkey-mini-app/references/contracts/drawer.md +29 -0
- package/skills/monkey-mini-app/references/contracts/dropdown-menu.md +49 -0
- package/skills/monkey-mini-app/references/contracts/duration-input.md +20 -2
- package/skills/monkey-mini-app/references/contracts/empty.md +40 -0
- package/skills/monkey-mini-app/references/contracts/env-badge.md +12 -2
- package/skills/monkey-mini-app/references/contracts/env-table.md +46 -0
- package/skills/monkey-mini-app/references/contracts/event-calendar.md +28 -20
- package/skills/monkey-mini-app/references/contracts/field.md +34 -0
- package/skills/monkey-mini-app/references/contracts/file-dropzone.md +20 -2
- package/skills/monkey-mini-app/references/contracts/file-tree.md +12 -2
- package/skills/monkey-mini-app/references/contracts/filter-bar.md +2 -2
- package/skills/monkey-mini-app/references/contracts/form-sheet.md +51 -0
- package/skills/monkey-mini-app/references/contracts/gantt.md +20 -2
- package/skills/monkey-mini-app/references/contracts/gauge.md +14 -2
- package/skills/monkey-mini-app/references/contracts/hover-card.md +21 -0
- package/skills/monkey-mini-app/references/contracts/input-group.md +24 -0
- package/skills/monkey-mini-app/references/contracts/input.md +33 -0
- package/skills/monkey-mini-app/references/contracts/item.md +36 -0
- package/skills/monkey-mini-app/references/contracts/jira-wiki.md +3 -4
- package/skills/monkey-mini-app/references/contracts/jql-input.md +15 -8
- package/skills/monkey-mini-app/references/contracts/json-viewer.md +20 -2
- package/skills/monkey-mini-app/references/contracts/kanban-issue-panel.md +12 -2
- package/skills/monkey-mini-app/references/contracts/kanban.md +10 -2
- package/skills/monkey-mini-app/references/contracts/kbd.md +20 -0
- package/skills/monkey-mini-app/references/contracts/label.md +33 -0
- package/skills/monkey-mini-app/references/contracts/list-detail.md +46 -0
- package/skills/monkey-mini-app/references/contracts/log-viewer.md +45 -4
- package/skills/monkey-mini-app/references/contracts/markdown-editor.md +20 -2
- package/skills/monkey-mini-app/references/contracts/markdown.md +12 -2
- package/skills/monkey-mini-app/references/contracts/marker.md +30 -0
- package/skills/monkey-mini-app/references/contracts/menubar.md +34 -0
- package/skills/monkey-mini-app/references/contracts/message-scroller.md +24 -0
- package/skills/monkey-mini-app/references/contracts/message.md +24 -0
- package/skills/monkey-mini-app/references/contracts/mini-calendar.md +20 -2
- package/skills/monkey-mini-app/references/contracts/native-select.md +21 -0
- package/skills/monkey-mini-app/references/contracts/navigation-menu.md +27 -0
- package/skills/monkey-mini-app/references/contracts/notification-center.md +12 -2
- package/skills/monkey-mini-app/references/contracts/number-field.md +20 -2
- package/skills/monkey-mini-app/references/contracts/page-header.md +2 -2
- package/skills/monkey-mini-app/references/contracts/pagination.md +33 -0
- package/skills/monkey-mini-app/references/contracts/password-field.md +12 -2
- package/skills/monkey-mini-app/references/contracts/phone-input.md +12 -2
- package/skills/monkey-mini-app/references/contracts/popover.md +32 -0
- package/skills/monkey-mini-app/references/contracts/progress-ring.md +14 -2
- package/skills/monkey-mini-app/references/contracts/progress.md +39 -0
- package/skills/monkey-mini-app/references/contracts/questionnaire.md +33 -0
- package/skills/monkey-mini-app/references/contracts/radar-chart.md +14 -2
- package/skills/monkey-mini-app/references/contracts/radio-group.md +20 -0
- package/skills/monkey-mini-app/references/contracts/rating.md +12 -2
- package/skills/monkey-mini-app/references/contracts/relative-date-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/request-inspector.md +12 -2
- package/skills/monkey-mini-app/references/contracts/resizable.md +29 -0
- package/skills/monkey-mini-app/references/contracts/reveal.md +31 -0
- package/skills/monkey-mini-app/references/contracts/rich-text-editor.md +14 -2
- package/skills/monkey-mini-app/references/contracts/run-timeline.md +20 -2
- package/skills/monkey-mini-app/references/contracts/scroll-area.md +20 -0
- package/skills/monkey-mini-app/references/contracts/scrollspy.md +20 -2
- package/skills/monkey-mini-app/references/contracts/search-input.md +12 -2
- package/skills/monkey-mini-app/references/contracts/select.md +36 -0
- package/skills/monkey-mini-app/references/contracts/separator.md +27 -0
- package/skills/monkey-mini-app/references/contracts/settings-split.md +53 -0
- package/skills/monkey-mini-app/references/contracts/severity-chip.md +12 -2
- package/skills/monkey-mini-app/references/contracts/sheet.md +34 -0
- package/skills/monkey-mini-app/references/contracts/sidebar.md +42 -0
- package/skills/monkey-mini-app/references/contracts/skeleton.md +33 -0
- package/skills/monkey-mini-app/references/contracts/slider-range.md +12 -2
- package/skills/monkey-mini-app/references/contracts/slider.md +25 -0
- package/skills/monkey-mini-app/references/contracts/sortable-list.md +20 -2
- package/skills/monkey-mini-app/references/contracts/sparkline.md +13 -2
- package/skills/monkey-mini-app/references/contracts/spinner.md +31 -0
- package/skills/monkey-mini-app/references/contracts/stacked-bar-chart.md +17 -2
- package/skills/monkey-mini-app/references/contracts/stat-card.md +2 -2
- package/skills/monkey-mini-app/references/contracts/status-badge.md +2 -2
- package/skills/monkey-mini-app/references/contracts/stepper-item.md +39 -0
- package/skills/monkey-mini-app/references/contracts/stepper.md +38 -11
- package/skills/monkey-mini-app/references/contracts/switch.md +25 -0
- package/skills/monkey-mini-app/references/contracts/table-page.md +41 -0
- package/skills/monkey-mini-app/references/contracts/table.md +42 -0
- package/skills/monkey-mini-app/references/contracts/tabs.md +31 -0
- package/skills/monkey-mini-app/references/contracts/tag-input.md +12 -2
- package/skills/monkey-mini-app/references/contracts/terminal.md +13 -2
- package/skills/monkey-mini-app/references/contracts/test-step-list.md +12 -2
- package/skills/monkey-mini-app/references/contracts/textarea.md +25 -0
- package/skills/monkey-mini-app/references/contracts/time-picker.md +18 -2
- package/skills/monkey-mini-app/references/contracts/time-range-picker.md +20 -2
- package/skills/monkey-mini-app/references/contracts/time-wheel.md +6 -2
- package/skills/monkey-mini-app/references/contracts/timeline.md +20 -2
- package/skills/monkey-mini-app/references/contracts/timezone-select.md +20 -2
- package/skills/monkey-mini-app/references/contracts/toast.md +39 -0
- package/skills/monkey-mini-app/references/contracts/toggle-group.md +28 -0
- package/skills/monkey-mini-app/references/contracts/toggle.md +26 -0
- package/skills/monkey-mini-app/references/contracts/tooltip.md +30 -0
- package/skills/monkey-mini-app/references/contracts/transfer.md +12 -2
- package/skills/monkey-mini-app/references/contracts/tree-view.md +20 -2
- package/skills/monkey-mini-app/references/contracts/trend-card.md +12 -2
- package/skills/monkey-mini-app/references/contracts/user-picker.md +12 -2
- package/skills/monkey-mini-app/references/contracts/wizard-shell.md +56 -0
- package/skills/monkey-mini-app/references/ctx.md +123 -53
- package/skills/monkey-mini-app/references/eval.md +115 -0
- package/skills/monkey-mini-app/references/examples/alert/alert-01.tsx +17 -0
- package/skills/monkey-mini-app/references/examples/aspect-ratio/aspect-ratio-01.tsx +16 -0
- package/skills/monkey-mini-app/references/examples/attachment/attachment-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/breadcrumb/breadcrumb-01.tsx +31 -0
- package/skills/monkey-mini-app/references/examples/bubble/bubble-01.tsx +16 -0
- package/skills/monkey-mini-app/references/examples/button-group/button-group-01.tsx +23 -0
- package/skills/monkey-mini-app/references/examples/card/card-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/charts-blocks.md +15 -0
- package/skills/monkey-mini-app/references/examples/code-block/code-block-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/code-editor/code-editor-01.tsx +15 -0
- package/skills/monkey-mini-app/references/examples/command/command-01.tsx +30 -0
- package/skills/monkey-mini-app/references/examples/confirm-dialog/confirm-dialog-01.tsx +33 -0
- package/skills/monkey-mini-app/references/examples/context-menu/context-menu-01.tsx +29 -0
- package/skills/monkey-mini-app/references/examples/dashboard-shell/dashboard-shell-01.tsx +78 -0
- package/skills/monkey-mini-app/references/examples/data-grid/data-grid-01.tsx +34 -0
- package/skills/monkey-mini-app/references/examples/data-grid/data-grid-02.tsx +88 -0
- package/skills/monkey-mini-app/references/examples/date-picker/date-picker-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/date-range-picker/date-range-picker-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/date-time-picker/date-time-picker-01.tsx +16 -0
- package/skills/monkey-mini-app/references/examples/date-time-range-picker/date-time-range-picker-01.tsx +15 -0
- package/skills/monkey-mini-app/references/examples/detail-panel/detail-panel-01.tsx +21 -0
- package/skills/monkey-mini-app/references/examples/dialog/dialog-01.tsx +30 -0
- package/skills/monkey-mini-app/references/examples/diff-viewer/diff-viewer-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/dropdown-menu/dropdown-menu-01.tsx +31 -0
- package/skills/monkey-mini-app/references/examples/duration-input/duration-input-01.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/editors.md +11 -0
- package/skills/monkey-mini-app/references/examples/empty/empty-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/event-calendar/event-calendar-01.tsx +53 -0
- package/skills/monkey-mini-app/references/examples/file-dropzone/file-dropzone-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/form-sheet/form-sheet-01.tsx +85 -0
- package/skills/monkey-mini-app/references/examples/forms.md +16 -0
- package/skills/monkey-mini-app/references/examples/gantt/gantt-01.tsx +29 -0
- package/skills/monkey-mini-app/references/examples/input/input-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/item/item-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/jql-input/jql-input-01.tsx +33 -0
- package/skills/monkey-mini-app/references/examples/json-viewer/json-viewer-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/kanban/kanban-01.tsx +60 -0
- package/skills/monkey-mini-app/references/examples/label/label-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/list-detail/list-detail-01.tsx +117 -0
- package/skills/monkey-mini-app/references/examples/log-viewer/log-viewer-01.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/markdown-editor/markdown-editor-01.tsx +18 -0
- package/skills/monkey-mini-app/references/examples/marker/marker-01.tsx +16 -0
- package/skills/monkey-mini-app/references/examples/mini-calendar/mini-calendar-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-01.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-02.tsx +32 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-03.tsx +47 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-04.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-05.tsx +24 -0
- package/skills/monkey-mini-app/references/examples/misc-charts-blocks/misc-charts-blocks-06.tsx +89 -0
- package/skills/monkey-mini-app/references/examples/misc-editors/misc-editors-01.tsx +114 -0
- package/skills/monkey-mini-app/references/examples/misc-editors/misc-editors-02.tsx +33 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-01.tsx +22 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-02.tsx +37 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-03.tsx +42 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-04.tsx +25 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-05.tsx +27 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-06.tsx +33 -0
- package/skills/monkey-mini-app/references/examples/misc-forms/misc-forms-07.tsx +44 -0
- package/skills/monkey-mini-app/references/examples/misc-overlays/misc-overlays-01.tsx +43 -0
- package/skills/monkey-mini-app/references/examples/misc-overlays/misc-overlays-02.tsx +38 -0
- package/skills/monkey-mini-app/references/examples/misc-primitives/misc-primitives-01.tsx +21 -0
- package/skills/monkey-mini-app/references/examples/misc-primitives/misc-primitives-02.tsx +52 -0
- package/skills/monkey-mini-app/references/examples/misc-primitives/misc-primitives-03.tsx +44 -0
- package/skills/monkey-mini-app/references/examples/number-field/number-field-01.tsx +22 -0
- package/skills/monkey-mini-app/references/examples/overlays.md +11 -0
- package/skills/monkey-mini-app/references/examples/pagination/pagination-01.tsx +51 -0
- package/skills/monkey-mini-app/references/examples/primitives.md +12 -0
- package/skills/monkey-mini-app/references/examples/progress/progress-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/relative-date-picker/relative-date-picker-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/rich-text-editor/rich-text-editor-01.tsx +15 -0
- package/skills/monkey-mini-app/references/examples/run-timeline/run-timeline-01.tsx +17 -0
- package/skills/monkey-mini-app/references/examples/scrollspy/scrollspy-01.tsx +29 -0
- package/skills/monkey-mini-app/references/examples/separator/separator-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/settings-split/settings-split-01.tsx +84 -0
- package/skills/monkey-mini-app/references/examples/shared/jira-wiki-sample.ts +38 -0
- package/skills/monkey-mini-app/references/examples/skeleton/skeleton-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/slider/slider-01.tsx +22 -0
- package/skills/monkey-mini-app/references/examples/sortable-list/sortable-list-01.tsx +18 -0
- package/skills/monkey-mini-app/references/examples/spinner/spinner-01.tsx +10 -0
- package/skills/monkey-mini-app/references/examples/stepper/stepper-01.tsx +41 -0
- package/skills/monkey-mini-app/references/examples/table/table-01.tsx +25 -0
- package/skills/monkey-mini-app/references/examples/table-page/table-page-01.tsx +103 -0
- package/skills/monkey-mini-app/references/examples/time-picker/time-picker-01.tsx +19 -0
- package/skills/monkey-mini-app/references/examples/time-range-picker/time-range-picker-01.tsx +14 -0
- package/skills/monkey-mini-app/references/examples/timeline/timeline-01.tsx +18 -0
- package/skills/monkey-mini-app/references/examples/timezone-select/timezone-select-01.tsx +15 -0
- package/skills/monkey-mini-app/references/examples/toggle/toggle-01.tsx +20 -0
- package/skills/monkey-mini-app/references/examples/toggle-group/toggle-group-01.tsx +22 -0
- package/skills/monkey-mini-app/references/examples/tree-view/tree-view-01.tsx +25 -0
- package/skills/monkey-mini-app/references/examples/wizard-shell/wizard-shell-01.tsx +58 -0
- package/skills/monkey-mini-app/references/history.md +23 -7
- package/skills/monkey-mini-app/references/icons.md +99 -69
- package/skills/monkey-mini-app/references/llm-json.md +39 -26
- package/skills/monkey-mini-app/references/loader.md +47 -20
- package/skills/monkey-mini-app/references/looks/aurora-bento.md +88 -0
- package/skills/monkey-mini-app/references/looks/desk-split.md +89 -0
- package/skills/monkey-mini-app/references/looks/editorial.md +78 -0
- package/skills/monkey-mini-app/references/looks/glass-island.md +90 -0
- package/skills/monkey-mini-app/references/looks/index.md +18 -0
- package/skills/monkey-mini-app/references/looks/signage.md +74 -0
- package/skills/monkey-mini-app/references/looks/tape.md +22 -0
- package/skills/monkey-mini-app/references/looks/terminal.md +88 -0
- package/skills/monkey-mini-app/references/looks/void.md +22 -0
- package/skills/monkey-mini-app/references/styling.md +189 -0
- package/skills/monkey-mini-app/references/test.md +12 -12
- package/skills/monkey-mini-app/references/theme.md +197 -0
- package/skills/monkey-mini-app/references/tools.md +12 -12
- package/skills/monkey-mini-app/references/troubleshoot.md +165 -12
- package/skills/monkey-mini-app/templates/README.md +33 -21
- package/skills/monkey-mini-app/templates/{jira → board}/main.api.ts +11 -11
- package/skills/monkey-mini-app/templates/board/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/board/theme.css +46 -0
- package/skills/monkey-mini-app/templates/board/ui.tsx +546 -0
- package/skills/monkey-mini-app/templates/chores/main.api.ts +35 -0
- package/skills/monkey-mini-app/templates/chores/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/chores/theme.css +46 -0
- package/skills/monkey-mini-app/templates/chores/ui.tsx +117 -0
- package/skills/monkey-mini-app/templates/minimal/main.api.ts +5 -5
- package/skills/monkey-mini-app/templates/minimal/manifest.json +1 -2
- package/skills/monkey-mini-app/templates/minimal/ui.tsx +17 -8
- package/skills/monkey-mini-app/templates/radar/api/scan.ts +79 -0
- package/skills/monkey-mini-app/templates/radar/main.api.ts +29 -0
- package/skills/monkey-mini-app/templates/radar/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/radar/shared/events.ts +25 -0
- package/skills/monkey-mini-app/templates/{insights/lib → radar/shared}/sample.ts +1 -1
- package/skills/monkey-mini-app/templates/radar/theme.css +47 -0
- package/skills/monkey-mini-app/templates/radar/ui/brief.tsx +31 -0
- package/skills/monkey-mini-app/templates/radar/ui.tsx +131 -0
- package/skills/monkey-mini-app/templates/runner/main.api.ts +91 -0
- package/skills/monkey-mini-app/templates/runner/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/runner/shared/events.ts +14 -0
- package/skills/monkey-mini-app/templates/runner/theme.css +46 -0
- package/skills/monkey-mini-app/templates/runner/ui.tsx +213 -0
- package/skills/monkey-mini-app/templates/sheets/main.api.ts +276 -0
- package/skills/monkey-mini-app/templates/sheets/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/sheets/theme.css +46 -0
- package/skills/monkey-mini-app/templates/sheets/ui.tsx +419 -0
- package/skills/monkey-mini-app/templates/{todo → today}/main.api.ts +8 -8
- package/skills/monkey-mini-app/templates/today/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/today/theme.css +45 -0
- package/skills/monkey-mini-app/templates/today/ui/item-row.tsx +25 -0
- package/skills/monkey-mini-app/templates/today/ui.tsx +406 -0
- package/skills/monkey-mini-app/templates/{monitor → watch}/main.api.ts +8 -8
- package/skills/monkey-mini-app/templates/watch/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/watch/ui.tsx +187 -0
- package/skills/monkey-mini-app/tsconfig.json +31 -0
- package/skills/monkey-mini-app/types/cdn.d.ts +1 -0
- package/tsup.config.ts +1 -0
- package/skills/monkey-mini-app/templates/agentrun/main.api.ts +0 -78
- package/skills/monkey-mini-app/templates/agentrun/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/agentrun/ui.tsx +0 -125
- package/skills/monkey-mini-app/templates/insights/main.api.ts +0 -101
- package/skills/monkey-mini-app/templates/insights/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/insights/ui.tsx +0 -138
- package/skills/monkey-mini-app/templates/jira/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/jira/ui.tsx +0 -318
- package/skills/monkey-mini-app/templates/monitor/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/monitor/ui.tsx +0 -176
- package/skills/monkey-mini-app/templates/review/main.api.ts +0 -68
- package/skills/monkey-mini-app/templates/review/manifest.json +0 -9
- package/skills/monkey-mini-app/templates/review/ui.tsx +0 -159
- package/skills/monkey-mini-app/templates/todo/manifest.json +0 -8
- package/skills/monkey-mini-app/templates/todo/ui.tsx +0 -177
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
Empty,
|
|
6
|
+
EmptyDescription,
|
|
7
|
+
EmptyHeader,
|
|
8
|
+
EmptyTitle,
|
|
9
|
+
Icon,
|
|
10
|
+
Input,
|
|
11
|
+
ListDetail,
|
|
12
|
+
useApp,
|
|
13
|
+
} from "@monkey-mini-app/ui";
|
|
14
|
+
|
|
15
|
+
import { ItemRow, type Item } from "./ui/item-row";
|
|
16
|
+
|
|
17
|
+
type Filter = "all" | "active" | "done";
|
|
18
|
+
type Stats = { total: number; active: number; done: number };
|
|
19
|
+
|
|
20
|
+
const FILTERS: { id: Filter; label: string }[] = [
|
|
21
|
+
{ id: "all", label: "全部" },
|
|
22
|
+
{ id: "active", label: "先干" },
|
|
23
|
+
{ id: "done", label: "已完" },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const WEEK_LABELS = ["一", "二", "三", "四", "五", "六", "日"];
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* Real liquid glass, not frosted glass: the background is *displaced*, so the pane bends what is
|
|
30
|
+
* behind it. `backdrop-filter` accepts an SVG filter alongside the functions (verified in
|
|
31
|
+
* Chromium: `blur(2px) url(#id)` survives as written) — `LiquidDefs` below carries that filter.
|
|
32
|
+
*
|
|
33
|
+
* A displacement map can only bend structure that exists. Over a smooth gradient it renders
|
|
34
|
+
* nothing at all, which is why the sky carries grain and tight bokeh — see the wash layer.
|
|
35
|
+
*
|
|
36
|
+
* The refraction is gentle on purpose (`scale="45"`, `yChannelSelector="B"`): push it to
|
|
37
|
+
* `scale="130"` / `yChannelSelector="G"` and the text inside the pane starts wobbling — water, not glass.
|
|
38
|
+
*
|
|
39
|
+
* Non-Chromium engines drop `url()` here, so fall back to the old frost rather than a plain box.
|
|
40
|
+
*/
|
|
41
|
+
const REFRACTS =
|
|
42
|
+
typeof CSS !== "undefined" &&
|
|
43
|
+
typeof CSS.supports === "function" &&
|
|
44
|
+
CSS.supports("backdrop-filter", "blur(2px) url(#mma-liquid)");
|
|
45
|
+
|
|
46
|
+
const GLASS = {
|
|
47
|
+
// Radius lives on the style, not a class: the old `ISLAND = "rounded-3xl"` was defined and
|
|
48
|
+
// never applied, which is why the panes looked hard-edged. Token so theme.css owns the size.
|
|
49
|
+
borderRadius: "var(--radius)",
|
|
50
|
+
backgroundColor: "color-mix(in oklch, var(--card) 14%, transparent)",
|
|
51
|
+
boxShadow:
|
|
52
|
+
"inset 0 1px 0 color-mix(in oklch, var(--card) 60%, transparent)," +
|
|
53
|
+
"inset 0 -1px 0 color-mix(in oklch, var(--card) 22%, transparent)," +
|
|
54
|
+
"inset 0 0 24px color-mix(in oklch, var(--card) 14%, transparent)," +
|
|
55
|
+
"0 14px 36px -10px var(--shadow)",
|
|
56
|
+
border: "1px solid color-mix(in oklch, var(--card) 28%, transparent)",
|
|
57
|
+
backdropFilter: REFRACTS
|
|
58
|
+
? "blur(2px) saturate(160%) url(#mma-liquid)"
|
|
59
|
+
: "blur(18px) saturate(200%) brightness(1.08)",
|
|
60
|
+
WebkitBackdropFilter: REFRACTS
|
|
61
|
+
? "blur(2px) saturate(160%)"
|
|
62
|
+
: "blur(18px) saturate(200%) brightness(1.08)",
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
/** Soft card for the working set — not liquid. A full-bleed displaced pane eats the sky
|
|
66
|
+
* and is why the facade never matched the floating-pill prototype. */
|
|
67
|
+
const WORK = {
|
|
68
|
+
borderRadius: "var(--radius)",
|
|
69
|
+
backgroundColor: "color-mix(in oklch, var(--card) 78%, transparent)",
|
|
70
|
+
boxShadow: "0 10px 28px -12px var(--shadow)",
|
|
71
|
+
border: "1px solid color-mix(in oklch, var(--card) 40%, transparent)",
|
|
72
|
+
backdropFilter: "blur(12px) saturate(140%)",
|
|
73
|
+
WebkitBackdropFilter: "blur(12px) saturate(140%)",
|
|
74
|
+
} as const;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The filter lives in the app's own document — `backdrop-filter: url(#id)` resolves against the
|
|
78
|
+
* same DOM tree, so a mini-app carries its liquid glass with it. Hidden, zero-size, off-screen:
|
|
79
|
+
* a `width=0` svg still exposes its `<defs>` to the document.
|
|
80
|
+
*/
|
|
81
|
+
function LiquidDefs() {
|
|
82
|
+
return (
|
|
83
|
+
<svg
|
|
84
|
+
aria-hidden
|
|
85
|
+
className="pointer-events-none fixed -left-[9999px] top-0 h-0 w-0"
|
|
86
|
+
>
|
|
87
|
+
<defs>
|
|
88
|
+
{/* noise → blur (so the bend is smooth, not fuzzy) → displace the backdrop pixels */}
|
|
89
|
+
<filter
|
|
90
|
+
id="mma-liquid"
|
|
91
|
+
x="0%"
|
|
92
|
+
y="0%"
|
|
93
|
+
width="100%"
|
|
94
|
+
height="100%"
|
|
95
|
+
filterUnits="objectBoundingBox"
|
|
96
|
+
>
|
|
97
|
+
<feTurbulence
|
|
98
|
+
type="fractalNoise"
|
|
99
|
+
baseFrequency="0.004"
|
|
100
|
+
numOctaves="2"
|
|
101
|
+
seed="3"
|
|
102
|
+
result="n"
|
|
103
|
+
/>
|
|
104
|
+
<feGaussianBlur in="n" stdDeviation="1.8" result="m" />
|
|
105
|
+
<feDisplacementMap
|
|
106
|
+
in="SourceGraphic"
|
|
107
|
+
in2="m"
|
|
108
|
+
scale="45"
|
|
109
|
+
xChannelSelector="R"
|
|
110
|
+
yChannelSelector="B"
|
|
111
|
+
/>
|
|
112
|
+
</filter>
|
|
113
|
+
{/* fine grain for the sky: the lens needs high-frequency detail behind it to read at all */}
|
|
114
|
+
<filter id="mma-grain">
|
|
115
|
+
<feTurbulence
|
|
116
|
+
type="fractalNoise"
|
|
117
|
+
baseFrequency="0.9"
|
|
118
|
+
numOctaves="2"
|
|
119
|
+
/>
|
|
120
|
+
<feColorMatrix type="saturate" values="0" />
|
|
121
|
+
</filter>
|
|
122
|
+
</defs>
|
|
123
|
+
</svg>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default function Ui() {
|
|
128
|
+
const { call } = useApp();
|
|
129
|
+
const [filter, setFilter] = useState<Filter>("all");
|
|
130
|
+
const [draft, setDraft] = useState("");
|
|
131
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
132
|
+
const [stats, setStats] = useState<Stats>({ total: 0, active: 0, done: 0 });
|
|
133
|
+
const [sel, setSel] = useState<string | null>(null);
|
|
134
|
+
const [error, setError] = useState<string | null>(null);
|
|
135
|
+
const [loading, setLoading] = useState(true);
|
|
136
|
+
|
|
137
|
+
// ⭐ key: refresh depends on filter; useCallback avoids an infinite loop
|
|
138
|
+
const refresh = useCallback(async () => {
|
|
139
|
+
setLoading(true);
|
|
140
|
+
setError(null);
|
|
141
|
+
try {
|
|
142
|
+
const pack = (await call("list", { filter })) as {
|
|
143
|
+
items: Item[];
|
|
144
|
+
stats: Stats;
|
|
145
|
+
};
|
|
146
|
+
setItems(Array.isArray(pack?.items) ? pack.items : []);
|
|
147
|
+
setStats(pack?.stats ?? { total: 0, active: 0, done: 0 });
|
|
148
|
+
} catch (e) {
|
|
149
|
+
setError(String((e as Error)?.message || e));
|
|
150
|
+
} finally {
|
|
151
|
+
setLoading(false);
|
|
152
|
+
}
|
|
153
|
+
}, [call, filter]);
|
|
154
|
+
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
void refresh();
|
|
157
|
+
}, [refresh]);
|
|
158
|
+
|
|
159
|
+
const current = items.find((i) => i.id === sel) ?? null;
|
|
160
|
+
|
|
161
|
+
async function act(job: () => Promise<unknown>) {
|
|
162
|
+
setError(null);
|
|
163
|
+
try {
|
|
164
|
+
await job();
|
|
165
|
+
await refresh();
|
|
166
|
+
} catch (e) {
|
|
167
|
+
setError(String((e as Error)?.message || e));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function add() {
|
|
172
|
+
const title = draft.trim();
|
|
173
|
+
if (!title) return;
|
|
174
|
+
await act(async () => {
|
|
175
|
+
const item = (await call("add", { title })) as Item;
|
|
176
|
+
setDraft("");
|
|
177
|
+
setSel(item.id);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const now = new Date();
|
|
182
|
+
const weekday = now.toLocaleDateString("zh-CN", { weekday: "long" });
|
|
183
|
+
const dateLabel = `${now.getMonth() + 1} 月 ${now.getDate()} 日`;
|
|
184
|
+
// this week, Monday-first, today marked — the wide island's whole job
|
|
185
|
+
const week = Array.from({ length: 7 }, (_, i) => {
|
|
186
|
+
const d = new Date(now);
|
|
187
|
+
d.setDate(now.getDate() - ((now.getDay() + 6) % 7) + i);
|
|
188
|
+
return {
|
|
189
|
+
label: WEEK_LABELS[i],
|
|
190
|
+
day: d.getDate(),
|
|
191
|
+
today: d.toDateString() === now.toDateString(),
|
|
192
|
+
};
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
// ⭐ Look: glass-island (references/looks/glass-island.md) — a cluster of frosted widgets
|
|
197
|
+
// floating on the sky, then the working set. The sky IS the palette: this app ships
|
|
198
|
+
// theme.css, so `bg-background` is the look's own blue-grey. Do not paint a gradient over
|
|
199
|
+
// it (that flattens the ground and the slabs stop reading as glass), and do not turn this
|
|
200
|
+
// into a page-wide tile wall — that is aurora-bento.
|
|
201
|
+
<div className="bg-background relative flex h-full min-h-0 flex-col gap-3 overflow-hidden p-5">
|
|
202
|
+
<LiquidDefs />
|
|
203
|
+
{/* The lens can only bend what is there: soft pools for hue depth, tight bokeh and grain for
|
|
204
|
+
something with edges. Token-derived `color-mix()` on --primary / --card / --foreground, so a
|
|
205
|
+
different ThemePop choice or dark mode keeps working and the app ships no colour literal. */}
|
|
206
|
+
<div
|
|
207
|
+
aria-hidden
|
|
208
|
+
className="pointer-events-none absolute inset-0"
|
|
209
|
+
style={{
|
|
210
|
+
// Floating haze: large soft orbs in white / mist-blue, low contrast. Light mode is
|
|
211
|
+
// haze-grey + white + a whisper of blue — not a saturated sky. Still enough structure
|
|
212
|
+
// (orb edges + grain) for the liquid lens to bend.
|
|
213
|
+
// Floating orbs must read against the haze ground: higher alpha, clearer edges,
|
|
214
|
+
// white + soft primary only (still not a saturated sky).
|
|
215
|
+
background:
|
|
216
|
+
"radial-gradient(55% 58% at 10% -4%, color-mix(in oklch, var(--card) 92%, transparent), transparent 68%)," +
|
|
217
|
+
"radial-gradient(48% 52% at 92% 4%, color-mix(in oklch, var(--primary) 38%, transparent), transparent 66%)," +
|
|
218
|
+
"radial-gradient(50% 45% at 72% 88%, color-mix(in oklch, var(--card) 80%, transparent), transparent 64%)," +
|
|
219
|
+
"radial-gradient(42% 48% at 12% 82%, color-mix(in oklch, var(--primary) 28%, transparent), transparent 64%)," +
|
|
220
|
+
"radial-gradient(160px 160px at 32% 28%, color-mix(in oklch, var(--card) 95%, transparent), transparent 70%)," +
|
|
221
|
+
"radial-gradient(130px 130px at 78% 36%, color-mix(in oklch, var(--primary) 32%, transparent), transparent 70%)," +
|
|
222
|
+
"radial-gradient(140px 140px at 52% 62%, color-mix(in oklch, var(--card) 88%, transparent), transparent 68%)," +
|
|
223
|
+
"radial-gradient(110px 110px at 22% 58%, color-mix(in oklch, var(--primary) 24%, transparent), transparent 70%)",
|
|
224
|
+
}}
|
|
225
|
+
/>
|
|
226
|
+
{/* grain: finest structure; opacity high enough that the bend is legible on a mid sky */}
|
|
227
|
+
<svg
|
|
228
|
+
aria-hidden
|
|
229
|
+
className="pointer-events-none absolute inset-0 h-full w-full opacity-[0.2]"
|
|
230
|
+
>
|
|
231
|
+
<rect width="100%" height="100%" filter="url(#mma-grain)" />
|
|
232
|
+
</svg>
|
|
233
|
+
|
|
234
|
+
{/* the island cluster: unequal spans, each widget says exactly one thing */}
|
|
235
|
+
{/* The sky has to stay visible around the cluster: an island stretched to every edge is
|
|
236
|
+
just a page with rounded corners. Cap the content and let `--background` frame it.
|
|
237
|
+
6 columns are written out rather than switched on at `md:` — a mini-app lives in a
|
|
238
|
+
panel of whatever width the user dragged it to, and this arrangement *is* the look. */}
|
|
239
|
+
<div className="relative mx-auto flex h-full min-h-0 w-full max-w-5xl flex-col gap-3">
|
|
240
|
+
<div className="grid grid-cols-6 gap-3">
|
|
241
|
+
<div
|
|
242
|
+
style={GLASS}
|
|
243
|
+
className="col-span-2 row-span-2 flex flex-col justify-between p-4"
|
|
244
|
+
>
|
|
245
|
+
<p className="text-muted-foreground text-xs tracking-[0.18em] uppercase">
|
|
246
|
+
{weekday}
|
|
247
|
+
</p>
|
|
248
|
+
<p className="font-serif text-6xl leading-[0.82] font-medium tracking-tight tabular-nums">
|
|
249
|
+
{now.getDate()}
|
|
250
|
+
</p>
|
|
251
|
+
<p className="text-muted-foreground text-xs">{dateLabel}</p>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<div
|
|
255
|
+
style={GLASS}
|
|
256
|
+
className="col-span-4 flex items-center justify-between p-3"
|
|
257
|
+
>
|
|
258
|
+
{week.map((d) => (
|
|
259
|
+
<span
|
|
260
|
+
key={d.label}
|
|
261
|
+
className={
|
|
262
|
+
d.today
|
|
263
|
+
? "bg-foreground text-background flex size-9 flex-col items-center justify-center rounded-full text-[11px] leading-tight"
|
|
264
|
+
: "text-muted-foreground flex size-9 flex-col items-center justify-center rounded-full text-[11px] leading-tight"
|
|
265
|
+
}
|
|
266
|
+
>
|
|
267
|
+
<span className="opacity-70">{d.label}</span>
|
|
268
|
+
<span className="tabular-nums">{d.day}</span>
|
|
269
|
+
</span>
|
|
270
|
+
))}
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<div style={GLASS} className="col-span-2 p-4">
|
|
274
|
+
<p className="text-muted-foreground text-[11px]">进行中</p>
|
|
275
|
+
<p className="mt-1 text-2xl font-medium tabular-nums">
|
|
276
|
+
{stats.active}
|
|
277
|
+
</p>
|
|
278
|
+
</div>
|
|
279
|
+
<div style={GLASS} className="col-span-2 p-4">
|
|
280
|
+
<p className="text-muted-foreground text-[11px]">已完</p>
|
|
281
|
+
<p className="mt-1 text-2xl font-medium tabular-nums">
|
|
282
|
+
{stats.done}
|
|
283
|
+
</p>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
|
|
287
|
+
{/* the working set: controls in its own header, ListDetail owns the remaining height */}
|
|
288
|
+
{/* Working set is a soft card, not liquid glass — wall-to-wall displacement ate the sky
|
|
289
|
+
and is why the facade never matched the floating-pill prototype. */}
|
|
290
|
+
<div style={WORK} className="relative flex min-h-0 flex-1 flex-col">
|
|
291
|
+
<div className="border-border/60 flex flex-wrap items-center gap-2 border-b p-3">
|
|
292
|
+
{FILTERS.map((f) => (
|
|
293
|
+
<Button
|
|
294
|
+
key={f.id}
|
|
295
|
+
size="sm"
|
|
296
|
+
variant={filter === f.id ? "default" : "ghost"}
|
|
297
|
+
onClick={() => setFilter(f.id)}
|
|
298
|
+
>
|
|
299
|
+
{f.label}
|
|
300
|
+
</Button>
|
|
301
|
+
))}
|
|
302
|
+
<Button
|
|
303
|
+
size="sm"
|
|
304
|
+
variant="ghost"
|
|
305
|
+
className="ml-auto"
|
|
306
|
+
onClick={() => void act(() => call("archive", {}))}
|
|
307
|
+
>
|
|
308
|
+
<Icon.Archive size={16} strokeWidth={2} /> 归档
|
|
309
|
+
</Button>
|
|
310
|
+
<div className="flex w-full gap-2">
|
|
311
|
+
<Input
|
|
312
|
+
value={draft}
|
|
313
|
+
placeholder="加一件,回车"
|
|
314
|
+
onChange={(e) => setDraft(e.target.value)}
|
|
315
|
+
onKeyDown={(e) => {
|
|
316
|
+
if (e.key === "Enter") void add();
|
|
317
|
+
}}
|
|
318
|
+
/>
|
|
319
|
+
<Button onClick={() => void add()} disabled={!draft.trim()}>
|
|
320
|
+
<Icon.Plus size={16} strokeWidth={2} />
|
|
321
|
+
</Button>
|
|
322
|
+
</div>
|
|
323
|
+
{error ? (
|
|
324
|
+
<p className="text-destructive w-full text-sm">{error}</p>
|
|
325
|
+
) : null}
|
|
326
|
+
</div>
|
|
327
|
+
|
|
328
|
+
<div className="min-h-0 flex-1">
|
|
329
|
+
<ListDetail
|
|
330
|
+
list={
|
|
331
|
+
<ul>
|
|
332
|
+
{loading && !items.length ? (
|
|
333
|
+
<li className="text-muted-foreground px-3 py-4 text-sm">
|
|
334
|
+
加载中…
|
|
335
|
+
</li>
|
|
336
|
+
) : null}
|
|
337
|
+
{!loading && !items.length ? (
|
|
338
|
+
<li className="p-4">
|
|
339
|
+
<Empty>
|
|
340
|
+
<EmptyHeader>
|
|
341
|
+
<EmptyTitle>这一屏还空着</EmptyTitle>
|
|
342
|
+
<EmptyDescription>
|
|
343
|
+
上面加一件,它会出现在左边。
|
|
344
|
+
</EmptyDescription>
|
|
345
|
+
</EmptyHeader>
|
|
346
|
+
</Empty>
|
|
347
|
+
</li>
|
|
348
|
+
) : null}
|
|
349
|
+
{items.map((it) => (
|
|
350
|
+
<li key={it.id}>
|
|
351
|
+
<ItemRow
|
|
352
|
+
item={it}
|
|
353
|
+
selected={sel === it.id}
|
|
354
|
+
onSelect={() => setSel(it.id)}
|
|
355
|
+
/>
|
|
356
|
+
</li>
|
|
357
|
+
))}
|
|
358
|
+
</ul>
|
|
359
|
+
}
|
|
360
|
+
detail={
|
|
361
|
+
current ? (
|
|
362
|
+
<div className="flex flex-col gap-3 p-4">
|
|
363
|
+
<h2 className="text-lg font-semibold">{current.title}</h2>
|
|
364
|
+
<p className="text-muted-foreground text-sm">
|
|
365
|
+
{new Date(current.createdAt).toLocaleString("zh-CN")}
|
|
366
|
+
</p>
|
|
367
|
+
<div className="flex gap-2">
|
|
368
|
+
<Button
|
|
369
|
+
size="sm"
|
|
370
|
+
variant="outline"
|
|
371
|
+
onClick={() =>
|
|
372
|
+
void act(() => call("toggle", { id: current.id }))
|
|
373
|
+
}
|
|
374
|
+
>
|
|
375
|
+
{current.done ? "标为未完" : "标为完成"}
|
|
376
|
+
</Button>
|
|
377
|
+
<Button
|
|
378
|
+
size="sm"
|
|
379
|
+
variant="ghost"
|
|
380
|
+
onClick={() =>
|
|
381
|
+
void act(async () => {
|
|
382
|
+
await call("remove", { id: current.id });
|
|
383
|
+
setSel(null);
|
|
384
|
+
})
|
|
385
|
+
}
|
|
386
|
+
>
|
|
387
|
+
删除
|
|
388
|
+
</Button>
|
|
389
|
+
</div>
|
|
390
|
+
</div>
|
|
391
|
+
) : undefined
|
|
392
|
+
}
|
|
393
|
+
empty={
|
|
394
|
+
<p className="text-muted-foreground p-4 text-sm">
|
|
395
|
+
点左边一条,这边打开。
|
|
396
|
+
</p>
|
|
397
|
+
}
|
|
398
|
+
mobileView={current ? "detail" : "list"}
|
|
399
|
+
onMobileBack={() => setSel(null)}
|
|
400
|
+
/>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
);
|
|
406
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineApp } from "@monkey-mini-app/api";
|
|
2
2
|
|
|
3
|
-
// ⭐
|
|
4
|
-
//
|
|
3
|
+
// ⭐ key: the host already exposes OS basics via ctx.system.metrics() (memory/CPU/load/uptime are all there),
|
|
4
|
+
// so don't recompute them with bash. Use ctx.bash only for what the host lacks: ps (processes), df (disk).
|
|
5
5
|
type Proc = { pid: string; cpu: number; mem: number; name: string };
|
|
6
6
|
|
|
7
7
|
function fmtBytes(n: number): string {
|
|
@@ -26,7 +26,7 @@ async function sh(ctx, cmd: string): Promise<string> {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function parseProcesses(text: string): Proc[] {
|
|
29
|
-
//
|
|
29
|
+
// the last column is comm and may contain spaces; join the trailing tokens as name, the leading columns are pid/cpu/mem
|
|
30
30
|
if (!text) return [];
|
|
31
31
|
return text
|
|
32
32
|
.split("\n")
|
|
@@ -53,14 +53,14 @@ function parseDisk(text: string): { total: number; used: number; avail: number;
|
|
|
53
53
|
return { total, used, avail, usedPct, mount: cols[5] || "/" };
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
export default
|
|
57
|
-
name: "
|
|
58
|
-
description: "
|
|
56
|
+
export default defineApp({
|
|
57
|
+
name: "值班屏",
|
|
58
|
+
description: "打开就自己在跳。没有开始按钮。",
|
|
59
59
|
api: {
|
|
60
60
|
async getSnapshot(ctx) {
|
|
61
61
|
const base = await ctx.system.metrics();
|
|
62
62
|
const platform = base?.platform || "";
|
|
63
|
-
//
|
|
63
|
+
// memory/CPU/load come from metrics; only fill in what the host lacks here: processes + disk
|
|
64
64
|
const [psText, dfLine] = await Promise.all([
|
|
65
65
|
sh(ctx, platform === "darwin" ? "ps -axo pid,pcpu,pmem,comm -r | head -n 9" : "ps -axo pid,pcpu,pmem,comm --sort=-pcpu | head -n 9"),
|
|
66
66
|
sh(ctx, "df -k / | tail -1"),
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DashboardShell,
|
|
5
|
+
Reveal,
|
|
6
|
+
Sparkline,
|
|
7
|
+
Table,
|
|
8
|
+
TableBody,
|
|
9
|
+
TableCell,
|
|
10
|
+
TableHead,
|
|
11
|
+
TableHeader,
|
|
12
|
+
TableRow,
|
|
13
|
+
useApp,
|
|
14
|
+
} from "@monkey-mini-app/ui";
|
|
15
|
+
|
|
16
|
+
type Snapshot = {
|
|
17
|
+
hostname?: string;
|
|
18
|
+
platform?: string;
|
|
19
|
+
arch?: string;
|
|
20
|
+
loadavg?: Record<string, number>;
|
|
21
|
+
uptimeSec?: number;
|
|
22
|
+
collectedAt: number;
|
|
23
|
+
cpu: { model: string; count: number };
|
|
24
|
+
processes: { pid: string; cpu: number; mem: number; name: string }[];
|
|
25
|
+
memory: { total: number; used: number; free: number; usedPct: number };
|
|
26
|
+
disk: { total: string; used: string; free: string; usedPct: number } | null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default function Ui() {
|
|
30
|
+
const { call } = useApp();
|
|
31
|
+
const [snap, setSnap] = useState<Snapshot | null>(null);
|
|
32
|
+
const [error, setError] = useState<string | null>(null);
|
|
33
|
+
const [memHist, setMemHist] = useState<number[]>([]);
|
|
34
|
+
const [loadHist, setLoadHist] = useState<number[]>([]);
|
|
35
|
+
|
|
36
|
+
// ⭐ key: polling — fetch every 2s; stop when the page is hidden (in background) to avoid wasted runs.
|
|
37
|
+
// busy prevents issuing the next tick before the previous one returns; alive prevents setState after unmount.
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
let alive = true;
|
|
40
|
+
let busy = false;
|
|
41
|
+
async function tick() {
|
|
42
|
+
if (busy) return;
|
|
43
|
+
busy = true;
|
|
44
|
+
try {
|
|
45
|
+
const next = (await call("getSnapshot", {})) as Snapshot;
|
|
46
|
+
if (!alive) return;
|
|
47
|
+
setSnap(next);
|
|
48
|
+
setError(null);
|
|
49
|
+
setMemHist((prev) => prev.concat(next.memory.usedPct).slice(-48));
|
|
50
|
+
const load = Number(next.loadavg?.["1m"] ?? 0);
|
|
51
|
+
setLoadHist((prev) => prev.concat(load).slice(-48));
|
|
52
|
+
} catch (e) {
|
|
53
|
+
if (alive) setError(String((e as Error)?.message || e));
|
|
54
|
+
} finally {
|
|
55
|
+
busy = false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
void tick();
|
|
59
|
+
const id = setInterval(() => void tick(), 2000);
|
|
60
|
+
const stop = () => {
|
|
61
|
+
if (document.hidden) clearInterval(id);
|
|
62
|
+
};
|
|
63
|
+
document.addEventListener("visibilitychange", stop);
|
|
64
|
+
return () => {
|
|
65
|
+
alive = false;
|
|
66
|
+
clearInterval(id);
|
|
67
|
+
document.removeEventListener("visibilitychange", stop);
|
|
68
|
+
};
|
|
69
|
+
}, [call]);
|
|
70
|
+
|
|
71
|
+
const procs = snap?.processes ?? [];
|
|
72
|
+
const load = snap?.loadavg;
|
|
73
|
+
const memPct = snap?.memory.usedPct ?? 0;
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
// ⭐ Look: tape — numerals + vertical rules, no card chrome. The shape is DashboardShell:
|
|
77
|
+
// the hostname row and the KPI band are pinned, and the sparklines + process table are the
|
|
78
|
+
// one scroller. Hand-rolled, that scroller tends to land on the outer column, and the first
|
|
79
|
+
// table scroll takes the numbers off the top of a screen meant to be read from across a room.
|
|
80
|
+
<div className="h-full min-h-0 font-mono">
|
|
81
|
+
<DashboardShell
|
|
82
|
+
header={
|
|
83
|
+
<div className="text-muted-foreground flex items-center justify-between border-b px-4 py-2 text-xs tracking-widest uppercase">
|
|
84
|
+
<span>{snap?.hostname ?? "值班屏"}</span>
|
|
85
|
+
<span>每 2 秒 · {fmtUptime(snap?.uptimeSec ?? 0)}</span>
|
|
86
|
+
</div>
|
|
87
|
+
}
|
|
88
|
+
kpis={
|
|
89
|
+
<Reveal>
|
|
90
|
+
{/* four columns written out, not switched on at `md:` — the panel width is
|
|
91
|
+
user-dragged, so a breakpoint here is a lie (see `today`). */}
|
|
92
|
+
<div className="grid grid-cols-4 divide-x divide-border">
|
|
93
|
+
<div className="px-4 py-5">
|
|
94
|
+
<div className="text-muted-foreground text-[10px] tracking-widest uppercase">
|
|
95
|
+
Load
|
|
96
|
+
</div>
|
|
97
|
+
<div className="mt-1 text-3xl font-medium tracking-tight tabular-nums">
|
|
98
|
+
{load ? Number(load["1m"]).toFixed(2) : "—"}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
<div className="px-4 py-5">
|
|
102
|
+
<div className="text-muted-foreground text-[10px] tracking-widest uppercase">
|
|
103
|
+
Mem
|
|
104
|
+
</div>
|
|
105
|
+
<div className="mt-1 text-3xl font-medium tracking-tight tabular-nums">
|
|
106
|
+
{memPct}%
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
<div className="px-4 py-5">
|
|
110
|
+
<div className="text-muted-foreground text-[10px] tracking-widest uppercase">
|
|
111
|
+
Disk
|
|
112
|
+
</div>
|
|
113
|
+
<div className="mt-1 text-3xl font-medium tracking-tight tabular-nums">
|
|
114
|
+
{snap?.disk ? `${snap.disk.usedPct}%` : "—"}
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
<div className="px-4 py-5">
|
|
118
|
+
<div className="text-muted-foreground text-[10px] tracking-widest uppercase">
|
|
119
|
+
CPU
|
|
120
|
+
</div>
|
|
121
|
+
<div className="mt-1 text-3xl font-medium tracking-tight tabular-nums">
|
|
122
|
+
{snap ? snap.cpu.count : "—"}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</Reveal>
|
|
127
|
+
}
|
|
128
|
+
main={
|
|
129
|
+
<>
|
|
130
|
+
{error ? (
|
|
131
|
+
<p className="text-destructive px-4 py-2 text-sm">{error}</p>
|
|
132
|
+
) : null}
|
|
133
|
+
<div className="grid grid-cols-2 gap-0 border-t">
|
|
134
|
+
<div className="border-r p-4">
|
|
135
|
+
<Sparkline data={memHist.map((v) => ({ value: v }))} />
|
|
136
|
+
</div>
|
|
137
|
+
<div className="p-4">
|
|
138
|
+
<Sparkline data={loadHist.map((v) => ({ value: v }))} />
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
<div className="border-t">
|
|
142
|
+
<Table>
|
|
143
|
+
<TableHeader>
|
|
144
|
+
<TableRow>
|
|
145
|
+
<TableHead className="w-20">PID</TableHead>
|
|
146
|
+
<TableHead className="w-24">CPU%</TableHead>
|
|
147
|
+
<TableHead className="w-24">MEM%</TableHead>
|
|
148
|
+
<TableHead>PROC</TableHead>
|
|
149
|
+
</TableRow>
|
|
150
|
+
</TableHeader>
|
|
151
|
+
<TableBody>
|
|
152
|
+
{procs.map((p) => (
|
|
153
|
+
<TableRow key={p.pid}>
|
|
154
|
+
<TableCell className="font-mono">{p.pid}</TableCell>
|
|
155
|
+
<TableCell>{p.cpu.toFixed(1)}</TableCell>
|
|
156
|
+
<TableCell>{p.mem.toFixed(1)}</TableCell>
|
|
157
|
+
<TableCell className="max-w-[420px] truncate">
|
|
158
|
+
{p.name}
|
|
159
|
+
</TableCell>
|
|
160
|
+
</TableRow>
|
|
161
|
+
))}
|
|
162
|
+
</TableBody>
|
|
163
|
+
</Table>
|
|
164
|
+
</div>
|
|
165
|
+
</>
|
|
166
|
+
}
|
|
167
|
+
/>
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function fmtBytes(n: number): string {
|
|
173
|
+
if (!Number.isFinite(n) || n <= 0) return "—";
|
|
174
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
175
|
+
let i = 0;
|
|
176
|
+
while (n >= 1024 && i < units.length - 1) {
|
|
177
|
+
n /= 1024;
|
|
178
|
+
i++;
|
|
179
|
+
}
|
|
180
|
+
return n.toFixed(i ? 1 : 0) + units[i];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function fmtUptime(sec: number): string {
|
|
184
|
+
const h = Math.floor(sec / 3600);
|
|
185
|
+
const m = Math.floor((sec % 3600) / 60);
|
|
186
|
+
return h ? `${h}h ${m}m` : `${m}m`;
|
|
187
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"lib": ["ES2022", "DOM"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noImplicitAny": false,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
// main.api.ts runs on Node: Buffer/process are part of the backend authoring surface
|
|
13
|
+
// (the host's own static check whitelists the same names). exceljs and friends come
|
|
14
|
+
// from the repo's devDependencies so a template that names one still type-checks here.
|
|
15
|
+
"types": ["node"],
|
|
16
|
+
"paths": {
|
|
17
|
+
"@monkey-mini-app/api": ["../../packages/api/src/index.ts"],
|
|
18
|
+
"@monkey-mini-app/ui": ["../../packages/ui/src/index.ts"],
|
|
19
|
+
"@monkey-mini-app/ui/*": ["../../packages/ui/src/*"],
|
|
20
|
+
// The iframe vendors. An app directory has no node_modules, so these rows are the
|
|
21
|
+
// only reason `lodash` / `motion` are not red in the author's editor. Both motion
|
|
22
|
+
// rows are the **react** declaration, matching what /mma/vendors/motion.js ships
|
|
23
|
+
// (motion's own bare entry is the vanilla API and has no `motion.div`).
|
|
24
|
+
"lodash": ["../../node_modules/lodash-es"],
|
|
25
|
+
"lodash/*": ["../../node_modules/lodash-es/*"],
|
|
26
|
+
"motion": ["../../node_modules/motion/dist/react.d.ts"],
|
|
27
|
+
"motion/react": ["../../node_modules/motion/dist/react.d.ts"]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"include": ["templates/**/*.ts", "templates/**/*.tsx", "types/**/*.d.ts"]
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module "https://esm.sh/*";
|