unmagic-components 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +98 -1
- data/README.md +506 -1
- data/app/assets/icons/lucide/LICENSE +43 -0
- data/app/assets/icons/lucide/arrow-down.svg +1 -0
- data/app/assets/icons/lucide/arrow-left.svg +1 -0
- data/app/assets/icons/lucide/arrow-up.svg +1 -0
- data/app/assets/icons/lucide/ban.svg +1 -0
- data/app/assets/icons/lucide/brain.svg +1 -0
- data/app/assets/icons/lucide/check.svg +1 -0
- data/app/assets/icons/lucide/chevron-down.svg +1 -0
- data/app/assets/icons/lucide/chevron-left.svg +1 -0
- data/app/assets/icons/lucide/chevron-right.svg +1 -0
- data/app/assets/icons/lucide/circle-check.svg +1 -0
- data/app/assets/icons/lucide/circle-dashed.svg +1 -0
- data/app/assets/icons/lucide/circle-question-mark.svg +1 -0
- data/app/assets/icons/lucide/circle-stop.svg +1 -0
- data/app/assets/icons/lucide/circle-x.svg +1 -0
- data/app/assets/icons/lucide/clock.svg +1 -0
- data/app/assets/icons/lucide/copy.svg +1 -0
- data/app/assets/icons/lucide/ellipsis-vertical.svg +1 -0
- data/app/assets/icons/lucide/file.svg +1 -0
- data/app/assets/icons/lucide/folder.svg +1 -0
- data/app/assets/icons/lucide/grip-vertical.svg +1 -0
- data/app/assets/icons/lucide/info.svg +1 -0
- data/app/assets/icons/lucide/lightbulb.svg +1 -0
- data/app/assets/icons/lucide/list-checks.svg +1 -0
- data/app/assets/icons/lucide/loader-circle.svg +1 -0
- data/app/assets/icons/lucide/messages-square.svg +1 -0
- data/app/assets/icons/lucide/paperclip.svg +1 -0
- data/app/assets/icons/lucide/pencil.svg +1 -0
- data/app/assets/icons/lucide/plus.svg +1 -0
- data/app/assets/icons/lucide/rotate-cw.svg +1 -0
- data/app/assets/icons/lucide/shield-alert.svg +1 -0
- data/app/assets/icons/lucide/timer.svg +1 -0
- data/app/assets/icons/lucide/triangle-alert.svg +1 -0
- data/app/assets/icons/lucide/wrench.svg +1 -0
- data/app/assets/icons/lucide/x.svg +1 -0
- data/app/assets/javascripts/unmagic/components/ai_chat.js +142 -0
- data/app/assets/javascripts/unmagic/components/autoscroll.js +103 -0
- data/app/assets/javascripts/unmagic/components/board.js +65 -0
- data/app/assets/javascripts/unmagic/components/dropzone.js +206 -0
- data/app/assets/javascripts/unmagic/components/elapsed.js +64 -0
- data/app/assets/javascripts/unmagic/components/optimistic.js +71 -0
- data/app/assets/javascripts/unmagic/components/placement.js +30 -0
- data/app/assets/javascripts/unmagic/components/slash_menu.js +186 -0
- data/app/assets/javascripts/unmagic/components/sortable.js +6 -0
- data/app/assets/javascripts/unmagic/components/sortable_item.js +122 -0
- data/app/assets/javascripts/unmagic/components/sortable_list.js +135 -0
- data/app/assets/javascripts/unmagic/components/sortable_param.js +14 -0
- data/app/assets/javascripts/unmagic/components/sortable_session.js +502 -0
- data/app/assets/javascripts/unmagic/components/streaming_markdown.js +269 -0
- data/app/assets/javascripts/unmagic/components/toasts.js +14 -4
- data/app/assets/javascripts/unmagic/components/toolbar.js +76 -0
- data/app/assets/javascripts/unmagic/components/upsert.js +4 -20
- data/app/assets/javascripts/unmagic/components.js +10 -0
- data/app/assets/tailwind/unmagic_components/engine.css +1515 -0
- data/lib/unmagic/components/action_view_helpers.rb +558 -3
- data/lib/unmagic/components/ai_chat/action_bar.rb +70 -0
- data/lib/unmagic/components/ai_chat/attachments.rb +119 -0
- data/lib/unmagic/components/ai_chat/branch_picker.rb +65 -0
- data/lib/unmagic/components/ai_chat/citation.rb +89 -0
- data/lib/unmagic/components/ai_chat/composer.rb +160 -0
- data/lib/unmagic/components/ai_chat/failure.rb +80 -0
- data/lib/unmagic/components/ai_chat/message.rb +142 -0
- data/lib/unmagic/components/ai_chat/payload.rb +93 -0
- data/lib/unmagic/components/ai_chat/permission.rb +143 -0
- data/lib/unmagic/components/ai_chat/plan.rb +91 -0
- data/lib/unmagic/components/ai_chat/proposal.rb +102 -0
- data/lib/unmagic/components/ai_chat/reasoning.rb +75 -0
- data/lib/unmagic/components/ai_chat/request.rb +206 -0
- data/lib/unmagic/components/ai_chat/section.rb +53 -0
- data/lib/unmagic/components/ai_chat/slash_menu.rb +68 -0
- data/lib/unmagic/components/ai_chat/tool_call.rb +181 -0
- data/lib/unmagic/components/ai_chat/transcript.rb +68 -0
- data/lib/unmagic/components/ai_chat/welcome.rb +73 -0
- data/lib/unmagic/components/ai_chat/workspace.rb +74 -0
- data/lib/unmagic/components/ai_chat.rb +31 -0
- data/lib/unmagic/components/avatar.rb +134 -0
- data/lib/unmagic/components/board.rb +182 -0
- data/lib/unmagic/components/browser/app/controllers/unmagic/components/browser/application_controller.rb +80 -0
- data/lib/unmagic/components/browser/app/controllers/unmagic/components/browser/demos_controller.rb +137 -0
- data/lib/unmagic/components/browser/app/controllers/unmagic/components/browser/pages_controller.rb +40 -0
- data/lib/unmagic/components/browser/app/helpers/unmagic/components/browser/application_helper.rb +52 -0
- data/lib/unmagic/components/browser/app/models/unmagic/components/browser/board_store.rb +88 -0
- data/lib/unmagic/components/browser/app/models/unmagic/components/browser/catalog.rb +65 -0
- data/lib/unmagic/components/browser/app/models/unmagic/components/browser/pager.rb +11 -0
- data/lib/unmagic/components/browser/app/models/unmagic/components/browser/profile.rb +25 -0
- data/lib/unmagic/components/browser/app/models/unmagic/components/browser/reply.rb +72 -0
- data/lib/unmagic/components/browser/app/models/unmagic/components/browser/thing.rb +31 -0
- data/lib/unmagic/components/browser/app/views/layouts/unmagic/components/browser/application.html.erb +65 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/application/_code.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/application/_crumb.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/application/_example.html.erb +37 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/application/_nav.html.erb +17 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/demos/edit_profile.html.erb +9 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat/_conversation.html.erb +101 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat/_live.html.erb +53 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat/_thumbnail.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat/_welcome.html.erb +12 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_action_bar/_always.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_action_bar/_hover.html.erb +12 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_action_bar/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_attachments/_dropzone.html.erb +17 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_attachments/_sent.html.erb +11 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_attachments/_thumbnail.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_branch_picker/_positions.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_branch_picker/_thumbnail.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_citation/_compact.html.erb +10 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_citation/_quote.html.erb +11 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_citation/_thumbnail.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_composer/_parts.html.erb +14 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_composer/_states.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_composer/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_failure/_full.html.erb +11 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_failure/_plain.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_failure/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_message/_parts.html.erb +23 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_message/_states.html.erb +9 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_message/_thumbnail.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_message/_turns.html.erb +16 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_payload/_json.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_payload/_text.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_payload/_thumbnail.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_permission/_answered.html.erb +12 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_permission/_thumbnail.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_permission/_waiting.html.erb +12 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_plan/_empty.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_plan/_states.html.erb +9 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_plan/_thumbnail.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_proposal/_decided.html.erb +11 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_proposal/_inline.html.erb +18 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_proposal/_thumbnail.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_reasoning/_settled.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_reasoning/_thinking.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_reasoning/_thumbnail.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_request/_answered.html.erb +10 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_request/_choices.html.erb +13 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_request/_form.html.erb +9 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_request/_thumbnail.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_slash_menu/_composer.html.erb +15 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_slash_menu/_thumbnail.html.erb +9 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_tool_call/_made.html.erb +12 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_tool_call/_run.html.erb +25 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_tool_call/_states.html.erb +22 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_tool_call/_thumbnail.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_welcome/_suggestions.html.erb +11 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_welcome/_thumbnail.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_workspace/_files.html.erb +12 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/ai_chat_workspace/_thumbnail.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/avatar/_group.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/avatar/_sizes.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/avatar/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/avatar/_tints.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/badge/_in_context.html.erb +14 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/badge/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/badge/_tones.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/board/_handles.html.erb +13 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/board/_live.html.erb +34 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/board/_thumbnail.html.erb +10 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/button/_sizes.html.erb +12 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/button/_thumbnail.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/button/_variants.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/callout/_neutral.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/callout/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/callout/_tones.html.erb +14 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/card/_actions_and_footer.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/card/_flush_table.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/card/_link.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/card/_thumbnail.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/confirm/_danger.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/confirm/_plain.html.erb +2 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/confirm/_thumbnail.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/copy_button/_from_element.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/copy_button/_thumbnail.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/copy_button/_with_label.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/detail_list/_inline.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/detail_list/_stacked.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/detail_list/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/dialog/_dialog_tag.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/dialog/_modal.html.erb +10 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/dialog/_thumbnail.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/elapsed/_countdown.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/elapsed/_running.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/elapsed/_thumbnail.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/empty_state/_default.html.erb +1 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/empty_state/_thumbnail.html.erb +3 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/forms/_autogrow.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/forms/_control_classes.html.erb +54 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/forms/_fields.html.erb +28 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/forms/_states.html.erb +11 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/forms/_thumbnail.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/forms/_uuid_field.html.erb +9 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/local_time/_absolute.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/local_time/_relative.html.erb +14 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/local_time/_thumbnail.html.erb +14 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/menu/_actions.html.erb +10 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/menu/_labelled.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/menu/_thumbnail.html.erb +14 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/page_header/_default.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/page_header/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/page_header/_with_leading.html.erb +14 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/skeleton/_blocking_out.html.erb +25 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/skeleton/_card.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/skeleton/_detail_list.html.erb +15 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/skeleton/_page_header.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/skeleton/_text_and_button.html.erb +17 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/skeleton/_thumbnail.html.erb +10 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/sortable_list/_connected.html.erb +17 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/sortable_list/_grid.html.erb +20 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/sortable_list/_handles.html.erb +22 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/sortable_list/_thumbnail.html.erb +7 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/streaming_markdown/_reveal.html.erb +19 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/streaming_markdown/_stopped.html.erb +31 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/streaming_markdown/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/table/_deferred.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/table/_empty.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/table/_sortable.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/table/_table_tag.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/table/_thumbnail.html.erb +4 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/tabs/_links.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/tabs/_panels.html.erb +18 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/tabs/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/toast/_above_dialog.html.erb +10 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/toast/_flash.html.erb +13 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/toast/_stream.html.erb +6 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/toast/_thumbnail.html.erb +10 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/tooltip/_placement.html.erb +8 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/tooltip/_term.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/examples/tooltip/_thumbnail.html.erb +5 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/pages/component.html.erb +58 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/pages/installation.html.erb +47 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/pages/overview.html.erb +49 -0
- data/lib/unmagic/components/browser/app/views/unmagic/components/browser/pages/theming.html.erb +52 -0
- data/lib/unmagic/components/browser/assets/browser.css +2 -0
- data/lib/unmagic/components/browser/catalog/ai_chat.rb +21 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_action_bar.rb +15 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_attachments.rb +15 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_branch_picker.rb +12 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_citation.rb +15 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_composer.rb +16 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_failure.rb +15 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_message.rb +17 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_payload.rb +16 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_permission.rb +15 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_plan.rb +14 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_proposal.rb +15 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_reasoning.rb +14 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_request.rb +17 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_slash_menu.rb +14 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_tool_call.rb +17 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_welcome.rb +13 -0
- data/lib/unmagic/components/browser/catalog/ai_chat_workspace.rb +12 -0
- data/lib/unmagic/components/browser/catalog/avatar.rb +15 -0
- data/lib/unmagic/components/browser/catalog/badge.rb +11 -0
- data/lib/unmagic/components/browser/catalog/board.rb +18 -0
- data/lib/unmagic/components/browser/catalog/button.rb +14 -0
- data/lib/unmagic/components/browser/catalog/callout.rb +13 -0
- data/lib/unmagic/components/browser/catalog/card.rb +16 -0
- data/lib/unmagic/components/browser/catalog/confirm.rb +14 -0
- data/lib/unmagic/components/browser/catalog/copy_button.rb +15 -0
- data/lib/unmagic/components/browser/catalog/detail_list.rb +14 -0
- data/lib/unmagic/components/browser/catalog/dialog.rb +15 -0
- data/lib/unmagic/components/browser/catalog/elapsed.rb +14 -0
- data/lib/unmagic/components/browser/catalog/empty_state.rb +11 -0
- data/lib/unmagic/components/browser/catalog/forms.rb +21 -0
- data/lib/unmagic/components/browser/catalog/local_time.rb +13 -0
- data/lib/unmagic/components/browser/catalog/menu.rb +15 -0
- data/lib/unmagic/components/browser/catalog/page_header.rb +13 -0
- data/lib/unmagic/components/browser/catalog/skeleton.rb +18 -0
- data/lib/unmagic/components/browser/catalog/sortable_list.rb +17 -0
- data/lib/unmagic/components/browser/catalog/streaming_markdown.rb +17 -0
- data/lib/unmagic/components/browser/catalog/table.rb +17 -0
- data/lib/unmagic/components/browser/catalog/tabs.rb +15 -0
- data/lib/unmagic/components/browser/catalog/toast.rb +17 -0
- data/lib/unmagic/components/browser/catalog/tooltip.rb +14 -0
- data/lib/unmagic/components/browser/config/routes.rb +41 -0
- data/lib/unmagic/components/browser/tailwind/browser.css +33 -0
- data/lib/unmagic/components/browser.rb +39 -0
- data/lib/unmagic/components/configuration.rb +31 -1
- data/lib/unmagic/components/duration.rb +35 -0
- data/lib/unmagic/components/elapsed.rb +46 -0
- data/lib/unmagic/components/engine.rb +9 -0
- data/lib/unmagic/components/icons.rb +34 -26
- data/lib/unmagic/components/modal.rb +1 -1
- data/lib/unmagic/components/page_header.rb +8 -0
- data/lib/unmagic/components/sortable.rb +104 -0
- data/lib/unmagic/components/streaming_markdown.rb +34 -0
- data/lib/unmagic/components/turbo_stream_actions.rb +16 -0
- data/lib/unmagic/components/version.rb +1 -1
- data/lib/unmagic/components.rb +30 -1
- metadata +308 -4
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<%# The browser has no Action Cable, so the server's reply arrives as a list of
|
|
2
|
+
flushes in the response, and this driver appends them one at a time. Each is
|
|
3
|
+
the real stream_markdown action; the last is the settled turn's upsert. A
|
|
4
|
+
flush for a reply that has been stopped is dropped, as a real one would be
|
|
5
|
+
refused by the frozen element. %>
|
|
6
|
+
<div class="mx-auto flex max-w-2xl flex-col gap-4">
|
|
7
|
+
<div id="demo_scroll" class="h-96 overflow-y-auto pr-2">
|
|
8
|
+
<%= ai_chat id: "demo_entries", scroller: "#demo_scroll" do |chat| %>
|
|
9
|
+
<% chat.welcome do %>
|
|
10
|
+
<%= ai_chat_welcome heading: "Ask about your candidates", composer: "demo_composer" do |welcome| %>
|
|
11
|
+
<% welcome.body "This one only knows one answer, but it streams it properly." %>
|
|
12
|
+
<% welcome.suggestion "Who hasn't replied yet?", icon: :messages_square %>
|
|
13
|
+
<% welcome.suggestion "Draft a nudge for…", icon: :pencil, fill: true, value: "Draft a nudge for " %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% end %>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<%= form_with url: ai_chat_messages_path, scope: :message, id: "demo_composer" do |form| %>
|
|
20
|
+
<%= ai_chat_composer form: form, field: :content, placeholder: "Ask something, or / for a command…",
|
|
21
|
+
stop_form: "demo_stop" do |composer| %>
|
|
22
|
+
<% composer.optimistic id: "message[client_id]", container: "#demo_entries" %>
|
|
23
|
+
<% composer.menu do %>
|
|
24
|
+
<%= ai_chat_slash_menu above: true do |menu| %>
|
|
25
|
+
<% menu.item "summarise", description: "Summarise the conversation so far" %>
|
|
26
|
+
<% menu.item "invite", description: "Invite a candidate to a job", arguments: %w[email job] %>
|
|
27
|
+
<% menu.item "nudge", description: "Draft a follow-up for someone who hasn't replied", arguments: %w[name] %>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% end %>
|
|
30
|
+
<% end %>
|
|
31
|
+
<% end %>
|
|
32
|
+
<%= ai_chat_stop_form ai_chat_stop_path, id: "demo_stop" %>
|
|
33
|
+
|
|
34
|
+
<div id="demo_driver" hidden></div>
|
|
35
|
+
<script type="module">
|
|
36
|
+
const driver = document.getElementById("demo_driver")
|
|
37
|
+
|
|
38
|
+
new MutationObserver(() => {
|
|
39
|
+
for (const list of driver.querySelectorAll("template[data-flushes]")) {
|
|
40
|
+
list.remove()
|
|
41
|
+
play(Array.from(list.content.children).filter((child) => child.localName === "template"))
|
|
42
|
+
}
|
|
43
|
+
}).observe(driver, { childList: true })
|
|
44
|
+
|
|
45
|
+
async function play(frames) {
|
|
46
|
+
for (const frame of frames) {
|
|
47
|
+
await new Promise((resolve) => setTimeout(resolve, Number(frame.dataset.delay)))
|
|
48
|
+
if (document.getElementById(frame.dataset.target)?.hasAttribute("final")) return
|
|
49
|
+
document.body.append(frame.content.cloneNode(true))
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
</script>
|
|
53
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<div class="flex w-64 flex-col gap-2 text-xs">
|
|
2
|
+
<%= ai_chat_message "Who hasn't replied?", role: :user %>
|
|
3
|
+
<%= ai_chat_tool_call name: "search_invitations", state: :done, icon: :messages_square, timeline: false do |tool| %>
|
|
4
|
+
<% tool.timing duration: 1.8 %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<%= ai_chat_message role: :assistant do %><p>Three candidates haven't replied since Monday.</p><% end %>
|
|
7
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat id: "welcome_entries", follow: false do |chat| %>
|
|
3
|
+
<% chat.welcome do %>
|
|
4
|
+
<%= ai_chat_welcome heading: "What can I help with?", composer: "welcome_composer" do |welcome| %>
|
|
5
|
+
<% welcome.body "It can search your jobs and candidates, draft messages, and keep track of who has replied." %>
|
|
6
|
+
<% welcome.suggestion "Who hasn't replied yet?", icon: :messages_square %>
|
|
7
|
+
<% welcome.suggestion "Which job is getting the most views?", icon: :list_checks %>
|
|
8
|
+
<% welcome.suggestion "Create a job at Acme", icon: :pencil %>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<%= ai_chat_action_bar for: "bar_reply", reveal: :always do |bar| %>
|
|
2
|
+
<% bar.copy "Friday at 2pm works for everyone." %>
|
|
3
|
+
<% bar.action "Try again", "#", icon: :rotate_cw, method: :post, confirm: "Replace this reply?" %>
|
|
4
|
+
<% bar.action "Edit", "#", icon: :pencil %>
|
|
5
|
+
<% bar.control { ai_chat_branch_picker index: 1, count: 2, next: "#" } %>
|
|
6
|
+
<% end %>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat_message role: :assistant, id: "bar_reply" do |turn| %>
|
|
3
|
+
<% turn.actions do %>
|
|
4
|
+
<%= ai_chat_action_bar for: "bar_reply" do |bar| %>
|
|
5
|
+
<% bar.copy "Friday at 2pm works for everyone." %>
|
|
6
|
+
<% bar.action "Try again", "#", icon: :rotate_cw, method: :post %>
|
|
7
|
+
<% bar.action "Edit", "#", icon: :pencil %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% end %>
|
|
10
|
+
<p>Friday at 2pm works for everyone.</p>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<%= ai_chat_action_bar for: "thumb", reveal: :always, class: "rounded-lg border border-neutral-200 bg-white p-1 dark:border-neutral-800 dark:bg-neutral-900" do |bar| %>
|
|
2
|
+
<% bar.copy "x" %>
|
|
3
|
+
<% bar.action "Try again", "#", icon: :rotate_cw, method: :post %>
|
|
4
|
+
<% bar.action "Edit", "#", icon: :pencil %>
|
|
5
|
+
<% end %>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat_dropzone input: "#drop_files", chips: "#drop_composer [data-ai-chat-chips]", label: "Drop to attach to your message",
|
|
3
|
+
class: "rounded-2xl border border-dashed border-neutral-200 p-4 dark:border-neutral-800" do %>
|
|
4
|
+
<p class="mb-4 text-sm text-neutral-500">The whole box is the drop zone.</p>
|
|
5
|
+
<%= form_with url: "#", id: "drop_composer", multipart: true do |form| %>
|
|
6
|
+
<%= ai_chat_composer form: form, field: :content, placeholder: "Paste an image here, or drop a file…" do |composer| %>
|
|
7
|
+
<% composer.attach do %>
|
|
8
|
+
<label class="<%= button_classes(:icon) %>" title="Attach a file">
|
|
9
|
+
<%= Unmagic::Components::Icons.svg(self, :paperclip) %>
|
|
10
|
+
<span class="UnmagicVisuallyHidden">Attach a file</span>
|
|
11
|
+
<%= form.file_field :files, multiple: true, id: "drop_files", class: "UnmagicVisuallyHidden" %>
|
|
12
|
+
</label>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<% end %>
|
|
17
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<div class="mx-auto flex max-w-2xl flex-col gap-6">
|
|
2
|
+
<%= ai_chat_message role: :user, id: "sent_q" do |turn| %>
|
|
3
|
+
<% turn.attachments do %>
|
|
4
|
+
<%= ai_chat_attachments align: :end do |files| %>
|
|
5
|
+
<% files.file "brief.pdf", size: 204_800, url: "#" %>
|
|
6
|
+
<% files.file "moodboard.png", size: 1_480_000, thumbnail: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Crect width='4' height='4' fill='%23f97316'/%3E%3Crect width='2' height='2' fill='%23db2777'/%3E%3C/svg%3E" %>
|
|
7
|
+
<% end %>
|
|
8
|
+
<% end %>
|
|
9
|
+
Use these for the lantern scene.
|
|
10
|
+
<% end %>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<% [ [ "Handbook · Leave", "Four weeks, accruing monthly from the first day." ],
|
|
3
|
+
[ "Handbook · Remote work", "Anyone can work from anywhere in the same timezone band." ],
|
|
4
|
+
[ "Contract template §4", "Notice is one month on either side after probation." ] ].each do |source, text| %>
|
|
5
|
+
<%= ai_chat_citation compact: true do |cite| %>
|
|
6
|
+
<% cite.who source %>
|
|
7
|
+
<% cite.quote text %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% end %>
|
|
10
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat_message role: :assistant do %>
|
|
3
|
+
<p>She said as much last week:</p>
|
|
4
|
+
<%= ai_chat_citation do |cite| %>
|
|
5
|
+
<% cite.avatar %>
|
|
6
|
+
<% cite.who "Ana Silva" %>
|
|
7
|
+
<% cite.when @now - 6.days, url: "#" %>
|
|
8
|
+
<% cite.quote "I'm keen, but I'm travelling until the 18th.\nCould we talk after that? <b>Thanks!</b>" %>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= form_with url: "#", id: "composer_parts", namespace: "composer_parts" do |form| %>
|
|
3
|
+
<%= ai_chat_composer form: form, field: :content, placeholder: "Message the assistant…", label: "Start chat" do |composer| %>
|
|
4
|
+
<% composer.attach do %>
|
|
5
|
+
<button type="button" class="<%= button_classes(:icon) %>" aria-label="Attach a file" title="Attach a file">
|
|
6
|
+
<%= Unmagic::Components::Icons.svg(self, :paperclip) %>
|
|
7
|
+
</button>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% composer.actions do %>
|
|
10
|
+
<%= select_tag :model, options_for_select([ "Fast", "Thorough" ]), class: control_classes(:select, size: :small) %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<div class="mx-auto flex max-w-2xl flex-col gap-4">
|
|
2
|
+
<% %i[idle running stopping waiting].each do |state| %>
|
|
3
|
+
<%= form_with url: "#", id: "composer_#{state}", namespace: "composer_#{state}" do |form| %>
|
|
4
|
+
<%= ai_chat_composer form: form, field: :content, state: state, placeholder: "#{state.to_s.capitalize}…", rows: 1,
|
|
5
|
+
stop_form: "composer_states_stop" %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% end %>
|
|
8
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat_message role: :assistant do %>
|
|
3
|
+
<p>Here's the shortlist so far: Ana Silva, Grace Okafor, and</p>
|
|
4
|
+
<% end %>
|
|
5
|
+
<%= ai_chat_failure "The assistant couldn't finish this reply.", class: "mt-2" do |failure| %>
|
|
6
|
+
<% failure.cause "RubyLLM::ContextLengthExceededError: prompt is too long: 212,408 tokens > 200,000 maximum" %>
|
|
7
|
+
<% failure.detail "Provider said", { type: "error", error: { type: "invalid_request_error", message: "prompt is too long" } } %>
|
|
8
|
+
<% failure.detail "Where it happened", "app/models/chat.rb:88:in 'Chat#reply'\napp/jobs/reply_job.rb:6:in 'ReplyJob#perform'", language: :plaintext %>
|
|
9
|
+
<% failure.retry { button_to "Try again", "#", class: button_classes(size: :small) } %>
|
|
10
|
+
<% end %>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<div class="mx-auto flex max-w-2xl flex-col gap-6">
|
|
2
|
+
<%= ai_chat_message role: :user, id: "parts_q" do |turn| %>
|
|
3
|
+
<% turn.attachments do %>
|
|
4
|
+
<%= ai_chat_attachments align: :end do |files| %>
|
|
5
|
+
<% files.file "brief.pdf", size: 204_800 %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% end %>
|
|
8
|
+
Summarise this brief for the hiring panel.
|
|
9
|
+
<% end %>
|
|
10
|
+
<%= ai_chat_message role: :assistant, id: "parts_a" do |turn| %>
|
|
11
|
+
<% turn.reasoning duration: 7 do %>
|
|
12
|
+
<p>The brief is four pages. The panel cares about the must-haves and the salary band, so lead with those.</p>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% turn.branches { ai_chat_branch_picker index: 2, count: 3, previous: "#", next: "#" } %>
|
|
15
|
+
<% turn.actions do %>
|
|
16
|
+
<%= ai_chat_action_bar for: "parts_a" do |bar| %>
|
|
17
|
+
<% bar.copy "Must-haves: Go, Kubernetes, on-call experience." %>
|
|
18
|
+
<% bar.action "Try again", "#", icon: :rotate_cw, method: :post %>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% end %>
|
|
21
|
+
<p><strong>Must-haves:</strong> Go, Kubernetes, and on-call experience. <strong>Band:</strong> $180–210k.</p>
|
|
22
|
+
<% end %>
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<div class="mx-auto flex max-w-2xl flex-col gap-6">
|
|
2
|
+
<%= ai_chat_message role: :assistant, id: "states_thinking", streaming: true %>
|
|
3
|
+
<%= ai_chat_message role: :assistant, id: "states_stopped", final: true do %>
|
|
4
|
+
<p class="text-neutral-500">Response stopped.</p>
|
|
5
|
+
<% end %>
|
|
6
|
+
<%= ai_chat_message role: :user, id: "states_optimistic", optimistic: { id: "x", text: "y" } %>
|
|
7
|
+
<p class="text-sm text-neutral-500">Above: an optimistic bubble as its template renders it, before the composer fills it in. Below this line is an empty settled turn, hidden.</p>
|
|
8
|
+
<%= ai_chat_message role: :assistant, id: "states_empty" %>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<div class="mx-auto flex max-w-2xl flex-col gap-6">
|
|
2
|
+
<%= ai_chat_message "Can you move Thursday's interview with Ana to Friday?\nSame time is fine.", role: :user, id: "turns_q" %>
|
|
3
|
+
<%= ai_chat_message role: :assistant, id: "turns_a" do %>
|
|
4
|
+
<p>Done — Ana's interview is now <strong>Friday at 2pm</strong>. I've:</p>
|
|
5
|
+
<ol>
|
|
6
|
+
<li>moved the calendar event and kept the same video link,</li>
|
|
7
|
+
<li>sent Ana an updated invitation, and</li>
|
|
8
|
+
<li>let <a href="#">the hiring panel</a> know.</li>
|
|
9
|
+
</ol>
|
|
10
|
+
<table>
|
|
11
|
+
<thead><tr><th>Who</th><th>Status</th></tr></thead>
|
|
12
|
+
<tbody><tr><td>Ana Silva</td><td>Invited</td></tr><tr><td>Panel</td><td>Notified</td></tr></tbody>
|
|
13
|
+
</table>
|
|
14
|
+
<p>The event is <code>evt_4821</code> if you need it.</p>
|
|
15
|
+
<% end %>
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div class="mx-auto flex max-w-xl flex-col gap-4">
|
|
2
|
+
<%= ai_chat_permission tool: "delete_files", state: :granted do |ask| %>
|
|
3
|
+
<% ask.argument "paths", "drafts/*" %>
|
|
4
|
+
<% ask.summary { tag.p("Remove the three superseded drafts.") } %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<%= ai_chat_permission tool: "send_email", state: :refused do |ask| %>
|
|
7
|
+
<% ask.argument "to", "grace.okafor@example.com" %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<%= ai_chat_permission tool: "read_chat", state: :lapsed do |ask| %>
|
|
10
|
+
<% ask.argument "chat_id", 4812 %>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div class="mx-auto max-w-xl">
|
|
2
|
+
<%= ai_chat_permission tool: "read_chat", state: :waiting, url: "#" do |ask| %>
|
|
3
|
+
<% ask.argument "chat_id", 4812 %>
|
|
4
|
+
<% ask.summary { tag.p("Read the conversation where the lantern brief was agreed.") } %>
|
|
5
|
+
<% ask.reason { tag.p("The brief here refers to decisions made there, and I can't see them.") } %>
|
|
6
|
+
<% ask.example "“Go with the lit version” — 3 Sept" %>
|
|
7
|
+
<% ask.example "“Keep it under 3k triangles” — 4 Sept" %>
|
|
8
|
+
<% ask.allow confirm: "Let this chat read conversation 4812?" %>
|
|
9
|
+
<% ask.allow "Allow for any chat", params: { widened: true }, confirm: "Let this chat read any conversation?" %>
|
|
10
|
+
<% ask.refuse %>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<div class="w-80 rounded-xl border border-neutral-200 bg-white dark:border-neutral-800 dark:bg-neutral-900">
|
|
2
|
+
<%= ai_chat_plan id: "plan_states" do |plan| %>
|
|
3
|
+
<% plan.step "Find the job", state: :completed %>
|
|
4
|
+
<% plan.step "List who hasn't replied", state: :completed %>
|
|
5
|
+
<% plan.step "Check the bounced address", state: :in_progress %>
|
|
6
|
+
<% plan.step "Nudge Grace", state: :waiting do %>Needs your go-ahead to send<% end %>
|
|
7
|
+
<% plan.step "Remind me about Ana on the 19th" %>
|
|
8
|
+
<% end %>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<div class="w-56 rounded-xl border border-neutral-200 bg-white text-xs dark:border-neutral-800 dark:bg-neutral-900">
|
|
2
|
+
<%= ai_chat_plan class: "p-3" do |plan| %>
|
|
3
|
+
<% plan.step "Find the job", state: :completed %>
|
|
4
|
+
<% plan.step "Check the address", state: :in_progress %>
|
|
5
|
+
<% plan.step "Nudge Grace", state: :waiting %>
|
|
6
|
+
<% end %>
|
|
7
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat_proposal state: :accepted do |offer| %>
|
|
3
|
+
<% offer.claim "Ana is travelling until the 18th" %>
|
|
4
|
+
<% offer.meta "About Ana Silva" %>
|
|
5
|
+
<% offer.outcome "Remembered" %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<%= ai_chat_proposal state: :rejected, icon: :list_checks do |offer| %>
|
|
8
|
+
<% offer.claim "Track notice period for everyone?" %>
|
|
9
|
+
<% offer.meta "A new kind of detail worth keeping" %>
|
|
10
|
+
<% end %>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat_message role: :assistant do %>
|
|
3
|
+
<p>Ana mentioned she's travelling, so I'd hold the nudge until she's back.</p>
|
|
4
|
+
<%= ai_chat_proposal id: "inline_fact" do |offer| %>
|
|
5
|
+
<% offer.claim "Ana is travelling until the 18th" %>
|
|
6
|
+
<% offer.meta "About Ana Silva · 80% sure" %>
|
|
7
|
+
<% offer.accept { button_to "Remember", "#", class: button_classes(:primary, size: :small) } %>
|
|
8
|
+
<% offer.reject { button_to "Dismiss", "#", class: button_classes(size: :small) } %>
|
|
9
|
+
<% end %>
|
|
10
|
+
<%= ai_chat_proposal id: "inline_finder", icon: :list_checks do |offer| %>
|
|
11
|
+
<% offer.claim { safe_join [ "Track ", tag.strong("notice period"), " for everyone?" ] } %>
|
|
12
|
+
<% offer.meta "e.g. Ana Silva — one month" %>
|
|
13
|
+
<% offer.accept { button_to "Track this", "#", class: button_classes(:primary, size: :small) } %>
|
|
14
|
+
<% offer.reject { button_to "No thanks", "#", class: button_classes(size: :small) } %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<p>I'll remind you on the 19th.</p>
|
|
17
|
+
<% end %>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<div class="w-[32rem] max-w-full">
|
|
2
|
+
<%= ai_chat_reasoning duration: 12.4 do |reasoning| %>
|
|
3
|
+
<% reasoning.block { tag.p("The user wants candidates who haven't replied. Replies are messages on the invitation, so an invitation with no inbound message counts.") } %>
|
|
4
|
+
<p>First find the job, since "Platform Engineer" could match two.</p>
|
|
5
|
+
<% end %>
|
|
6
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<div class="mx-auto flex max-w-xl flex-col gap-4">
|
|
2
|
+
<%= ai_chat_request state: :accepted do |request| %>
|
|
3
|
+
<% request.question "Which candidates should get a nudge?", header: "Who", picked: [ "Ana Silva", "Grace Okafor" ] %>
|
|
4
|
+
<% request.question "How should it sound?", header: "Tone", picked: [ "Friendly" ] %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<%= ai_chat_request state: :declined, prompt: "I need a few details to create the job." %>
|
|
7
|
+
<%= ai_chat_request state: :timed_out do |request| %>
|
|
8
|
+
<% request.question "Send it now?", picked: [] %>
|
|
9
|
+
<% end %>
|
|
10
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div class="mx-auto max-w-xl">
|
|
2
|
+
<%= ai_chat_request state: :waiting, url: "#", prompt: "Before I send anything:" do |request| %>
|
|
3
|
+
<% request.question "Which candidates should get a nudge?", header: "Who", multiple: true do |q| %>
|
|
4
|
+
<% q.option "Ana Silva", description: "Opened it twice, hasn't answered" %>
|
|
5
|
+
<% q.option "Grace Okafor", description: "Hasn't opened it" %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% request.question "How should it sound?", header: "Tone" do |q| %>
|
|
8
|
+
<% q.option "Friendly", description: "A short, warm check-in" %>
|
|
9
|
+
<% q.option "Direct", description: "The role closes on Friday" %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% request.aside "Or say something else in the box below." %>
|
|
12
|
+
<% end %>
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<div class="mx-auto max-w-xl">
|
|
2
|
+
<%= ai_chat_request state: :waiting, url: "#", prompt: "I need a few details to create the job." do |request| %>
|
|
3
|
+
<% request.form do |form| %>
|
|
4
|
+
<%= form.field :title, "Job title", required: true %>
|
|
5
|
+
<%= form.field :salary, "Salary band", hint: "For example, $180–210k" %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% request.decline %>
|
|
8
|
+
<% end %>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl pt-56">
|
|
2
|
+
<%= form_with url: "#", id: "slash_composer" do |form| %>
|
|
3
|
+
<%= ai_chat_composer form: form, field: :content, placeholder: "Type / for a command…" do |composer| %>
|
|
4
|
+
<% composer.menu do %>
|
|
5
|
+
<%= ai_chat_slash_menu above: true do |menu| %>
|
|
6
|
+
<% menu.item "summarise", description: "Summarise the conversation so far" %>
|
|
7
|
+
<% menu.item "invite", description: "Invite a candidate to a job", arguments: %w[email job] %>
|
|
8
|
+
<% menu.item "interview", description: "Schedule an interview", arguments: %w[name] %>
|
|
9
|
+
<% menu.item "nudge", description: "Draft a follow-up for someone who hasn't replied", arguments: %w[name] %>
|
|
10
|
+
<% menu.item "export", description: "Export the shortlist as a spreadsheet" %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<div class="relative w-64 text-xs">
|
|
2
|
+
<div class="UnmagicAIChatSlashMenu static mt-0">
|
|
3
|
+
<ul class="UnmagicAIChatSlashMenu__list">
|
|
4
|
+
<li class="UnmagicAIChatSlashMenu__item" aria-selected="true"><span class="UnmagicAIChatSlashMenu__name">/invite <span class="UnmagicAIChatSlashMenu__argument">[email]</span></span><span class="UnmagicAIChatSlashMenu__description">Invite a candidate</span></li>
|
|
5
|
+
<li class="UnmagicAIChatSlashMenu__item"><span class="UnmagicAIChatSlashMenu__name">/interview</span><span class="UnmagicAIChatSlashMenu__description">Schedule one</span></li>
|
|
6
|
+
</ul>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="UnmagicAIChatComposer__box mt-2"><span class="px-2 py-1 text-sm">/in</span></div>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat_tool_call name: "generate_image", state: :done, icon: :lightbulb do |tool| %>
|
|
3
|
+
<% tool.summary "a red paper lantern" %>
|
|
4
|
+
<% tool.timing duration: 14.2 %>
|
|
5
|
+
<% tool.asked({ prompt: "a red paper lantern, night market, soft glow" }) %>
|
|
6
|
+
<% tool.made do %>
|
|
7
|
+
<% %w[from-red-500 from-orange-400 from-rose-500].each do |from| %>
|
|
8
|
+
<div class="grid h-28 w-40 place-items-center rounded-lg bg-gradient-to-br <%= from %> to-neutral-900 text-xs text-white">lantern.png</div>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<div class="mx-auto max-w-2xl">
|
|
2
|
+
<%= ai_chat id: "run_entries", follow: false do %>
|
|
3
|
+
<%= ai_chat_message role: :assistant do %><p>Let me look through the shelves.</p><% end %>
|
|
4
|
+
<%= ai_chat_tool_call name: "list_shelves", state: :done, icon: :folder do |tool| %>
|
|
5
|
+
<% tool.timing duration: 0.09 %>
|
|
6
|
+
<% tool.asked({}) %>
|
|
7
|
+
<% tool.answered({ shelves: [ "Backgrounds", "Characters", "Props" ] }) %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<div data-ai-chat-timeline="gap" hidden></div>
|
|
10
|
+
<%= ai_chat_tool_call name: "search_files", state: :done, icon: :file, open: true do |tool| %>
|
|
11
|
+
<% tool.summary "red lantern" %>
|
|
12
|
+
<% tool.timing duration: 0.64 %>
|
|
13
|
+
<% tool.asked({ query: "red lantern", shelf: "Props" }) %>
|
|
14
|
+
<% tool.answered({ files: [ "props/lantern-red.glb", "props/lantern-red-lit.glb" ] }) %>
|
|
15
|
+
<% end %>
|
|
16
|
+
<div data-ai-chat-timeline="gap" hidden></div>
|
|
17
|
+
<%= ai_chat_tool_call name: "read_file", state: :done, icon: :file do |tool| %>
|
|
18
|
+
<% tool.summary "props/lantern-red.glb" %>
|
|
19
|
+
<% tool.timing duration: 2.4 %>
|
|
20
|
+
<% tool.asked({ path: "props/lantern-red.glb" }) %>
|
|
21
|
+
<% tool.answered "A 3D model: 2,140 triangles, one material, no animations." %>
|
|
22
|
+
<% end %>
|
|
23
|
+
<%= ai_chat_message role: :assistant do %><p>There are two red lanterns; the lit one has an emissive material.</p><% end %>
|
|
24
|
+
<% end %>
|
|
25
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<div class="mx-auto flex max-w-2xl flex-col gap-4">
|
|
2
|
+
<%= ai_chat_tool_call name: "render_scene", state: :queued, timeline: false %>
|
|
3
|
+
<%= ai_chat_tool_call name: "render_scene", state: :running, id: "states_render", timeline: false do |tool| %>
|
|
4
|
+
<% tool.summary "night market" %>
|
|
5
|
+
<% tool.timing started_at: @now - 72 %>
|
|
6
|
+
<% tool.progress "Frame 12 of 40" %>
|
|
7
|
+
<% end %>
|
|
8
|
+
<%= ai_chat_tool_call name: "ask_person", state: :waiting, timeline: false do |tool| %>
|
|
9
|
+
<% tool.summary "which lantern?" %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<%= ai_chat_tool_call name: "delete_files", state: :done, icon: :folder, timeline: false do |tool| %>
|
|
12
|
+
<% tool.timing duration: 3.1 %>
|
|
13
|
+
<% tool.failures 2 %>
|
|
14
|
+
<% tool.asked({ paths: [ "a.png", "b.png", "c.png" ] }) %>
|
|
15
|
+
<% tool.answered({ deleted: 1, errors: [ { path: "b.png", error: "locked" }, { path: "c.png", error: "missing" } ] }) %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<%= ai_chat_tool_call name: "fetch_page", state: :failed, timeline: false do |tool| %>
|
|
18
|
+
<% tool.summary "example.com/pricing" %>
|
|
19
|
+
<% tool.timing duration: 30 %>
|
|
20
|
+
<% tool.answered "Timed out after 30 seconds" %>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<div class="w-60 text-xs">
|
|
2
|
+
<%= ai_chat id: "thumb_tools", follow: false do %>
|
|
3
|
+
<%= ai_chat_tool_call name: "list_shelves", state: :done, icon: :folder do |tool| %><% tool.timing duration: 0.09 %><% end %>
|
|
4
|
+
<%= ai_chat_tool_call name: "search_files", state: :done, icon: :file do |tool| %><% tool.timing duration: 0.64 %><% end %>
|
|
5
|
+
<%= ai_chat_tool_call name: "render_scene", state: :running do |tool| %><% tool.timing started_at: @now - 72 %><% end %>
|
|
6
|
+
<% end %>
|
|
7
|
+
</div>
|