@pagelines/sdk 1.0.877 → 1.0.879

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.
Files changed (92) hide show
  1. package/README.md +68 -68
  2. package/dist/BotProvider.js +777 -0
  3. package/dist/BotProvider.js.map +1 -0
  4. package/dist/{AgentWidgetInline.js → BotWidgetInline.js} +8 -8
  5. package/dist/BotWidgetInline.js.map +1 -0
  6. package/dist/{AgentWidgetModal.js → BotWidgetModal.js} +7 -7
  7. package/dist/BotWidgetModal.js.map +1 -0
  8. package/dist/{AgentWrap.js → BotWrap.js} +1202 -1155
  9. package/dist/BotWrap.js.map +1 -0
  10. package/dist/{agent/AgentController.d.ts → bot/BotController.d.ts} +36 -18
  11. package/dist/bot/index.d.ts +14 -0
  12. package/dist/{agent → bot}/schema.d.ts +6 -6
  13. package/dist/{agent/ui/AgentAvatar.vue.d.ts → bot/ui/BotAvatar.vue.d.ts} +6 -6
  14. package/dist/{agent/ui/AgentChat.vue.d.ts → bot/ui/BotChat.vue.d.ts} +5 -5
  15. package/dist/{agent/ui/AgentProvider.vue.d.ts → bot/ui/BotProvider.vue.d.ts} +3 -3
  16. package/dist/{agent/ui/AgentWrap.vue.d.ts → bot/ui/BotWrap.vue.d.ts} +3 -4
  17. package/dist/{agent/ui/ElAgentAbout.vue.d.ts → bot/ui/ElBotAbout.vue.d.ts} +2 -2
  18. package/dist/{agent/ui/ElAgentChat.vue.d.ts → bot/ui/ElBotChat.vue.d.ts} +5 -5
  19. package/dist/{agent/ui/ElAgentChatPreview.vue.d.ts → bot/ui/ElBotChatPreview.vue.d.ts} +1 -1
  20. package/dist/{agent/ui/ElAgentHeader.vue.d.ts → bot/ui/ElBotHeader.vue.d.ts} +2 -2
  21. package/dist/{agent/ui/ElAgentModeSidebar.vue.d.ts → bot/ui/ElBotModeSidebar.vue.d.ts} +2 -2
  22. package/dist/{agent/ui/ElAgentSidebar.vue.d.ts → bot/ui/ElBotSidebar.vue.d.ts} +2 -2
  23. package/dist/bot/ui/ElCreateBot.vue.d.ts +12 -0
  24. package/dist/{agent → bot}/ui/ElModeHeader.vue.d.ts +2 -2
  25. package/dist/{agent → bot}/ui/ElProvisioningStatus.vue.d.ts +1 -1
  26. package/dist/{agent → bot}/ui/VoiceMode.vue.d.ts +4 -4
  27. package/dist/{agent → bot}/utils.d.ts +5 -5
  28. package/dist/{agent → bot}/voice/provider.d.ts +2 -2
  29. package/dist/{agent → bot}/voice/providers/livekit/provider.d.ts +8 -7
  30. package/dist/{agent → bot}/voice/voice-session-client.d.ts +2 -1
  31. package/dist/{agent → bot}/work-journal.d.ts +1 -1
  32. package/dist/{agent.js → bot.js} +89 -84
  33. package/dist/bot.js.map +1 -0
  34. package/dist/clients/BillingClient.d.ts +1 -1
  35. package/dist/clients/BotClient.d.ts +26 -0
  36. package/dist/clients/ChatClient.d.ts +6 -5
  37. package/dist/clients/ComputerClient.d.ts +16 -0
  38. package/dist/clients/UserClient.d.ts +4 -7
  39. package/dist/clients/types.d.ts +7 -2
  40. package/dist/contract/build.d.ts +1 -2
  41. package/dist/index.d.ts +3 -2
  42. package/dist/provider.js +1 -1
  43. package/dist/provider.js.map +1 -1
  44. package/dist/provider2.js +28 -36
  45. package/dist/provider2.js.map +1 -1
  46. package/dist/sdk.css +1 -1
  47. package/dist/sdk.js +4 -4
  48. package/dist/sdkClient.d.ts +33 -376
  49. package/dist/sdkClient.js +168 -170
  50. package/dist/sdkClient.js.map +1 -1
  51. package/dist/useWidgetState.js +9 -9
  52. package/dist/useWidgetState.js.map +1 -1
  53. package/dist/widget/PLWidget.d.ts +6 -6
  54. package/dist/widget/composables/useWidgetState.d.ts +3 -402
  55. package/dist/widget/index.d.ts +2 -2
  56. package/dist/widget/mode.d.ts +2 -2
  57. package/dist/widget/ui/{AgentWidgetInline.vue.d.ts → BotWidgetInline.vue.d.ts} +2 -2
  58. package/dist/widget/ui/{AgentWidgetModal.vue.d.ts → BotWidgetModal.vue.d.ts} +2 -2
  59. package/dist/widget/ui/{AgentWidgetPopup.vue.d.ts → BotWidgetPopup.vue.d.ts} +4 -4
  60. package/dist/widget.js +206 -206
  61. package/dist/widget.js.map +1 -1
  62. package/package.json +5 -5
  63. package/dist/AgentProvider.js +0 -764
  64. package/dist/AgentProvider.js.map +0 -1
  65. package/dist/AgentWidgetInline.js.map +0 -1
  66. package/dist/AgentWidgetModal.js.map +0 -1
  67. package/dist/AgentWrap.js.map +0 -1
  68. package/dist/agent/index.d.ts +0 -14
  69. package/dist/agent/ui/ElCreateAgent.vue.d.ts +0 -277
  70. package/dist/agent.js.map +0 -1
  71. package/dist/clients/AgentClient.d.ts +0 -48
  72. /package/dist/{agent → bot}/VoiceRecorderController.d.ts +0 -0
  73. /package/dist/{agent/ui/AgentInputEmail.vue.d.ts → bot/ui/BotInputEmail.vue.d.ts} +0 -0
  74. /package/dist/{agent/ui/AgentInputOneTimeCode.vue.d.ts → bot/ui/BotInputOneTimeCode.vue.d.ts} +0 -0
  75. /package/dist/{agent/ui/AgentSidebarClose.vue.d.ts → bot/ui/BotSidebarClose.vue.d.ts} +0 -0
  76. /package/dist/{agent/ui/AgentToolActivityGroup.vue.d.ts → bot/ui/BotToolActivityGroup.vue.d.ts} +0 -0
  77. /package/dist/{agent/ui/AgentWidget.vue.d.ts → bot/ui/BotWidget.vue.d.ts} +0 -0
  78. /package/dist/{agent → bot}/ui/ChatCardBlock.vue.d.ts +0 -0
  79. /package/dist/{agent → bot}/ui/ChatRichText.vue.d.ts +0 -0
  80. /package/dist/{agent → bot}/ui/ChatScroller.vue.d.ts +0 -0
  81. /package/dist/{agent → bot}/ui/ChatVisualBlock.vue.d.ts +0 -0
  82. /package/dist/{agent → bot}/ui/ElAuthGate.vue.d.ts +0 -0
  83. /package/dist/{agent → bot}/ui/ElAuthPanel.vue.d.ts +0 -0
  84. /package/dist/{agent/ui/ElAgentButton.vue.d.ts → bot/ui/ElBotButton.vue.d.ts} +0 -0
  85. /package/dist/{agent → bot}/ui/ElSidebar.vue.d.ts +0 -0
  86. /package/dist/{agent → bot}/ui/VoiceHistogramController.d.ts +0 -0
  87. /package/dist/{agent → bot}/ui/chat-diagram-layout.d.ts +0 -0
  88. /package/dist/{agent → bot}/ui/chat-visual-format.d.ts +0 -0
  89. /package/dist/{agent → bot}/ui/voice-mode-presentation.d.ts +0 -0
  90. /package/dist/{agent → bot}/voice/voice-error-copy.d.ts +0 -0
  91. /package/dist/{agent → bot}/voice/voice-work-state.d.ts +0 -0
  92. /package/dist/widget/ui/{AgentWidgetOnboard.vue.d.ts → BotWidgetOnboard.vue.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BotProvider.js","names":["$emit","$slots","$slots","$slots"],"sources":["../bot/schema.ts","../ui/EffectTransitionList.vue","../ui/EffectTransitionList.vue","../bot/ui/ElAuthGate.vue","../bot/ui/ElAuthGate.vue","../bot/ui/ElBotAbout.vue","../bot/ui/ElBotAbout.vue","../bot/ui/ElBotHeader.vue","../bot/ui/ElBotHeader.vue","../bot/ui/BotSidebarClose.vue","../bot/ui/BotSidebarClose.vue","../bot/ui/ElSidebar.vue","../bot/ui/ElSidebar.vue","../bot/ui/ElBotModeSidebar.vue","../bot/ui/ElBotModeSidebar.vue","../bot/ui/ElBotSidebar.vue","../bot/ui/ElBotSidebar.vue","../bot/ui/BotChat.vue","../bot/ui/BotChat.vue","../bot/ui/BotProvider.vue","../bot/ui/BotProvider.vue"],"sourcesContent":["// Re-export bot types from @pagelines/core for external consumers\nimport type { ChatAttachment, ChatToolActivityData } from '@pagelines/core'\n\nexport { Bot } from '@pagelines/core'\nexport type { BotData, ChatAttachment, ChatToolActivityData as ChatToolActivity } from '@pagelines/core'\n\n// Issue metadata rendered on system rows (blocking chat states). Deliberately\n// looser than the persisted ChatMessageIssue in @pagelines/core: live `error`\n// SSE frames may omit the CTA fields, and this one view shape renders both\n// live frames and persisted rows.\nexport interface ChatMessageIssue {\n code: string\n bucket: 'account' | 'error'\n actionLabel?: string\n actionUrl?: string\n help?: string\n}\n\n// Chat message interface from web project\nexport interface ChatMessage {\n id: string\n text: string\n sender: 'user' | 'bot' | 'system'\n timestamp: string\n conversationId?: string\n sequence?: string\n systemKind?: string | null\n /** Non-successful ending owned by the persisted assistant row. */\n turnOutcome?: 'failed' | 'stopped'\n attachments?: ChatAttachment[]\n toolActivities?: ChatToolActivityData[]\n issue?: ChatMessageIssue\n}\n\nexport interface TextConnectionState {\n isActive: boolean\n isConnected: boolean\n isThinking: boolean\n connectionStatus: 'connecting' | 'connected' | 'disconnected' | 'error'\n error?: string\n /**\n * Transient per-turn work description from `working_state` SSE frames.\n * Render as live chrome, never as a transcript message.\n */\n workingDescription?: string\n /**\n * Transient per-turn tool activity from `tool_activity` SSE frames.\n * Render as live chrome/details, never as transcript content.\n */\n toolActivities?: ChatToolActivityData[]\n /**\n * Keeps a non-successful live journal at the turn boundary. Cleared on the\n * next send; persisted rows carry `failed` for salvaged partial replies and\n * `stopped` for interruption, while system rows are failed by definition.\n */\n turnOutcome?: 'failed' | 'stopped'\n /**\n * Durable send block from a server issue that retrying cannot fix in this\n * session. Stays set until the controller is recreated or upstream state\n * changes and the chat reloads.\n */\n sendBlockedReason?: 'account' | 'bot_deleted'\n /**\n * Transient turn failure from an `error` SSE frame the server did NOT\n * persist. Live chrome like `workingDescription` — never a transcript\n * row, because a message-shaped render would vanish on reload. Cleared\n * on the next send or completed turn.\n */\n transientIssue?: {\n code: string\n message: string\n actionLabel?: string\n actionUrl?: string\n help?: string\n }\n}\n\n// Bot mode configuration\nexport const BOT_MODES = [\n {\n mode: 'self' as const,\n label: 'Overview',\n icon: 'i-tabler-user-square-rounded',\n },\n {\n mode: 'talk' as const,\n label: 'Talk',\n icon: 'i-tabler-phone',\n },\n {\n mode: 'chat' as const,\n label: 'Chat',\n icon: 'i-tabler-message-circle',\n },\n {\n mode: 'info' as const,\n label: 'About',\n icon: 'i-tabler-user-circle',\n },\n] as const\n\n// Bot modes from web project\nexport type BotMode = (typeof BOT_MODES)[number]['mode']\n","<script lang=\"ts\" setup>\n// SDK-local copy of src/ui/effects/EffectTransitionList.vue — the SDK package\n// must not import app source, so the primitives it needs live here.\nconst { disabled = false, mode: _mode = 'block' } = defineProps<{ disabled?: boolean, mode?: 'block' | 'inline' }>()\n</script>\n\n<template>\n <TransitionGroup :name=\"!disabled ? 'nlist' : ''\">\n <slot />\n </TransitionGroup>\n</template>\n\n<style>\n.nlist-enter-active,\n.nlist-leave-active,\n.nlist-move {\n transition: all 600ms cubic-bezier(0.68, -0.55, 0.27, 1.55);\n}\n\n.nlist-enter-from {\n opacity: 0;\n transform: translateX(-30px) scale(0.9);\n}\n\n.nlist-enter-to {\n opacity: 1;\n transform: translateX(0) scale(1);\n}\n\n.nlist-leave-active {\n position: absolute;\n}\n\n.nlist-leave-to {\n opacity: 0;\n transform: scale(0.9);\n}\n</style>\n","<script lang=\"ts\" setup>\n// SDK-local copy of src/ui/effects/EffectTransitionList.vue — the SDK package\n// must not import app source, so the primitives it needs live here.\nconst { disabled = false, mode: _mode = 'block' } = defineProps<{ disabled?: boolean, mode?: 'block' | 'inline' }>()\n</script>\n\n<template>\n <TransitionGroup :name=\"!disabled ? 'nlist' : ''\">\n <slot />\n </TransitionGroup>\n</template>\n\n<style>\n.nlist-enter-active,\n.nlist-leave-active,\n.nlist-move {\n transition: all 600ms cubic-bezier(0.68, -0.55, 0.27, 1.55);\n}\n\n.nlist-enter-from {\n opacity: 0;\n transform: translateX(-30px) scale(0.9);\n}\n\n.nlist-enter-to {\n opacity: 1;\n transform: translateX(0) scale(1);\n}\n\n.nlist-leave-active {\n position: absolute;\n}\n\n.nlist-leave-to {\n opacity: 0;\n transform: scale(0.9);\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport { computed, ref, watch } from 'vue'\nimport EffectTransitionList from '../../ui/EffectTransitionList.vue'\nimport ElBotButton from './ElBotButton.vue'\nimport BotInputEmail from './BotInputEmail.vue'\nimport BotInputOneTimeCode from './BotInputOneTimeCode.vue'\n\nconst { sdk } = defineProps<{ sdk: PageLinesSDK }>()\n\nconst form = ref({ email: '', code: '' })\nconst step = ref<'email' | 'code'>('email')\nconst isSubmitting = ref(false)\n\n// Engine array for step configuration\nconst stepConfig = {\n email: {\n title: 'Enter Your Email',\n button: { label: 'Continue', disabled: () => !form.value.email || isSubmitting.value },\n action: async () => {\n if (isSubmitting.value) return\n isSubmitting.value = true\n try {\n const success = await sdk.auth.requestAuthCode({ email: form.value.email })\n if (success)\n step.value = 'code'\n } finally {\n isSubmitting.value = false\n }\n },\n },\n code: {\n title: 'Enter Verification Code',\n button: { label: 'Verify', disabled: () => form.value.code.length !== 6 || isSubmitting.value },\n action: async () => {\n if (isSubmitting.value) return\n isSubmitting.value = true\n try {\n await sdk.auth.loginWithCode({ email: form.value.email, code: form.value.code })\n } finally {\n isSubmitting.value = false\n }\n },\n },\n}\n\nconst currentStep = computed(() => stepConfig[step.value])\n\n// Watch for successful authentication - UI will update when activeUser becomes defined\nwatch(() => sdk.activeUser.value, (newUser) => {\n if (newUser && step.value === 'code') {\n // Auth succeeded - parent component will handle UI transition\n // This log helps debug the auth flow\n console.log('[ElAuthGate] Authentication successful', { email: newUser.email })\n }\n})\n</script>\n\n<template>\n <div data-test=\"auth-form\" :data-test-mode=\"step\" class=\"flex flex-col items-center justify-center h-full p-6\">\n <div class=\"w-full max-w-xs space-y-12\">\n <p v-if=\"sdk.error.value\" class=\"text-xs text-theme-400 text-center\">\n {{ sdk.error.value }}\n </p>\n\n <h3 class=\"text-base font-light text-white text-center\">\n {{ currentStep.title }}\n </h3>\n\n <div class=\"space-y-6 relative\">\n <EffectTransitionList>\n <div v-if=\"step === 'email'\" key=\"email-field\" class=\"w-full\">\n <BotInputEmail\n v-model=\"form.email\"\n data-test=\"auth-email-input\"\n @keyup.enter=\"currentStep.action\"\n />\n </div>\n <div v-else key=\"code-field\" class=\"w-full\">\n <BotInputOneTimeCode\n v-model=\"form.code\"\n :length=\"6\"\n :focus-first=\"true\"\n data-test=\"auth-code-input\"\n @auto-submit=\"currentStep.action\"\n />\n </div>\n\n <div :key=\"currentStep.button.label\" class=\"space-y-4 w-full\">\n <ElBotButton\n theme=\"primary\"\n size=\"md\"\n class=\"w-full\"\n data-test=\"auth-submit\"\n :loading=\"sdk.loading.value\"\n :disabled=\"currentStep.button.disabled() || sdk.loading.value\"\n @click=\"currentStep.action\"\n >\n {{ currentStep.button.label }}\n </ElBotButton>\n\n <button\n v-if=\"step === 'code'\"\n class=\"w-full text-xs text-white/50 hover:text-white/70 transition-colors py-2\"\n @click=\"step = 'email'\"\n >\n Change Email\n </button>\n </div>\n </EffectTransitionList>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport { computed, ref, watch } from 'vue'\nimport EffectTransitionList from '../../ui/EffectTransitionList.vue'\nimport ElBotButton from './ElBotButton.vue'\nimport BotInputEmail from './BotInputEmail.vue'\nimport BotInputOneTimeCode from './BotInputOneTimeCode.vue'\n\nconst { sdk } = defineProps<{ sdk: PageLinesSDK }>()\n\nconst form = ref({ email: '', code: '' })\nconst step = ref<'email' | 'code'>('email')\nconst isSubmitting = ref(false)\n\n// Engine array for step configuration\nconst stepConfig = {\n email: {\n title: 'Enter Your Email',\n button: { label: 'Continue', disabled: () => !form.value.email || isSubmitting.value },\n action: async () => {\n if (isSubmitting.value) return\n isSubmitting.value = true\n try {\n const success = await sdk.auth.requestAuthCode({ email: form.value.email })\n if (success)\n step.value = 'code'\n } finally {\n isSubmitting.value = false\n }\n },\n },\n code: {\n title: 'Enter Verification Code',\n button: { label: 'Verify', disabled: () => form.value.code.length !== 6 || isSubmitting.value },\n action: async () => {\n if (isSubmitting.value) return\n isSubmitting.value = true\n try {\n await sdk.auth.loginWithCode({ email: form.value.email, code: form.value.code })\n } finally {\n isSubmitting.value = false\n }\n },\n },\n}\n\nconst currentStep = computed(() => stepConfig[step.value])\n\n// Watch for successful authentication - UI will update when activeUser becomes defined\nwatch(() => sdk.activeUser.value, (newUser) => {\n if (newUser && step.value === 'code') {\n // Auth succeeded - parent component will handle UI transition\n // This log helps debug the auth flow\n console.log('[ElAuthGate] Authentication successful', { email: newUser.email })\n }\n})\n</script>\n\n<template>\n <div data-test=\"auth-form\" :data-test-mode=\"step\" class=\"flex flex-col items-center justify-center h-full p-6\">\n <div class=\"w-full max-w-xs space-y-12\">\n <p v-if=\"sdk.error.value\" class=\"text-xs text-theme-400 text-center\">\n {{ sdk.error.value }}\n </p>\n\n <h3 class=\"text-base font-light text-white text-center\">\n {{ currentStep.title }}\n </h3>\n\n <div class=\"space-y-6 relative\">\n <EffectTransitionList>\n <div v-if=\"step === 'email'\" key=\"email-field\" class=\"w-full\">\n <BotInputEmail\n v-model=\"form.email\"\n data-test=\"auth-email-input\"\n @keyup.enter=\"currentStep.action\"\n />\n </div>\n <div v-else key=\"code-field\" class=\"w-full\">\n <BotInputOneTimeCode\n v-model=\"form.code\"\n :length=\"6\"\n :focus-first=\"true\"\n data-test=\"auth-code-input\"\n @auto-submit=\"currentStep.action\"\n />\n </div>\n\n <div :key=\"currentStep.button.label\" class=\"space-y-4 w-full\">\n <ElBotButton\n theme=\"primary\"\n size=\"md\"\n class=\"w-full\"\n data-test=\"auth-submit\"\n :loading=\"sdk.loading.value\"\n :disabled=\"currentStep.button.disabled() || sdk.loading.value\"\n @click=\"currentStep.action\"\n >\n {{ currentStep.button.label }}\n </ElBotButton>\n\n <button\n v-if=\"step === 'code'\"\n class=\"w-full text-xs text-white/50 hover:text-white/70 transition-colors py-2\"\n @click=\"step = 'email'\"\n >\n Change Email\n </button>\n </div>\n </EffectTransitionList>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { Bot } from '../schema'\nimport { SOCIAL_PLATFORMS } from '../../constants/socialPlatforms'\nimport ElModeHeader from './ElModeHeader.vue'\n\nconst { bot, isOnline = false } = defineProps<{\n bot: Bot\n isOnline?: boolean\n}>()\n</script>\n\n<template>\n <div class=\"flex-1 flex flex-col min-h-0 py-6 space-y-6 h-full overflow-scroll [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden relative\">\n <!-- Name/Avatar Header -->\n <ElModeHeader :bot=\"bot\" :is-online=\"isOnline\" />\n\n <div class=\"flex-1 space-y-6 pb-12\">\n\n\n <!-- About Section -->\n <div v-if=\"bot.summary.value\" class=\"text-sm bg-white/10 backdrop-blur-sm rounded-2xl p-4 border border-white/20 space-y-3\">\n <h3 class=\"font-medium text-white/50\">\n About\n </h3>\n <p class=\"text-white/70 leading-relaxed whitespace-pre-wrap\">{{ bot.summary.value }}</p>\n </div>\n\n <!-- Email Contact -->\n <div v-if=\"bot.email.value\" class=\"space-y-3\">\n <h3 class=\"text-sm font-medium text-white/90\">\n Contact\n </h3>\n <a\n :href=\"`mailto:${bot.email.value}`\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"relative inline-flex items-center justify-center gap-2 rounded-full px-4 py-2 font-medium transition-colors duration-200 focus:outline-none active:opacity-80 cursor-pointer bg-white/5 hover:bg-white/10 border border-white/10 text-white/80 text-sm justify-start h-10 w-full\"\n >\n <span class=\"i-heroicons-envelope flex items-center size-[1.1em] mt-[-.07em]\" />\n Email\n </a>\n </div>\n\n <!-- Social Accounts -->\n <div v-if=\"bot.accounts.value && bot.accounts.value.length > 0\" class=\"space-y-3\">\n <h3 class=\"text-sm font-medium text-white/90\">\n Links\n </h3>\n <div class=\"grid grid-cols-2 gap-3\">\n <a\n v-for=\"account in bot.accounts.value\"\n :key=\"`${account.platform}-${account.handle}`\"\n :href=\"SOCIAL_PLATFORMS[account.platform].getUrl(account.handle)\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"relative inline-flex items-center justify-center gap-2 rounded-full px-4 py-2 font-medium transition-colors duration-200 focus:outline-none active:opacity-80 cursor-pointer bg-white/10 hover:bg-white/20 border border-white/20 text-white/80 text-sm\"\n >\n <span class=\"flex items-center size-[1.1em] mt-[-.07em]\" :class=\"SOCIAL_PLATFORMS[account.platform].icon\" />\n {{ SOCIAL_PLATFORMS[account.platform].label }}\n </a>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { Bot } from '../schema'\nimport { SOCIAL_PLATFORMS } from '../../constants/socialPlatforms'\nimport ElModeHeader from './ElModeHeader.vue'\n\nconst { bot, isOnline = false } = defineProps<{\n bot: Bot\n isOnline?: boolean\n}>()\n</script>\n\n<template>\n <div class=\"flex-1 flex flex-col min-h-0 py-6 space-y-6 h-full overflow-scroll [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden relative\">\n <!-- Name/Avatar Header -->\n <ElModeHeader :bot=\"bot\" :is-online=\"isOnline\" />\n\n <div class=\"flex-1 space-y-6 pb-12\">\n\n\n <!-- About Section -->\n <div v-if=\"bot.summary.value\" class=\"text-sm bg-white/10 backdrop-blur-sm rounded-2xl p-4 border border-white/20 space-y-3\">\n <h3 class=\"font-medium text-white/50\">\n About\n </h3>\n <p class=\"text-white/70 leading-relaxed whitespace-pre-wrap\">{{ bot.summary.value }}</p>\n </div>\n\n <!-- Email Contact -->\n <div v-if=\"bot.email.value\" class=\"space-y-3\">\n <h3 class=\"text-sm font-medium text-white/90\">\n Contact\n </h3>\n <a\n :href=\"`mailto:${bot.email.value}`\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"relative inline-flex items-center justify-center gap-2 rounded-full px-4 py-2 font-medium transition-colors duration-200 focus:outline-none active:opacity-80 cursor-pointer bg-white/5 hover:bg-white/10 border border-white/10 text-white/80 text-sm justify-start h-10 w-full\"\n >\n <span class=\"i-heroicons-envelope flex items-center size-[1.1em] mt-[-.07em]\" />\n Email\n </a>\n </div>\n\n <!-- Social Accounts -->\n <div v-if=\"bot.accounts.value && bot.accounts.value.length > 0\" class=\"space-y-3\">\n <h3 class=\"text-sm font-medium text-white/90\">\n Links\n </h3>\n <div class=\"grid grid-cols-2 gap-3\">\n <a\n v-for=\"account in bot.accounts.value\"\n :key=\"`${account.platform}-${account.handle}`\"\n :href=\"SOCIAL_PLATFORMS[account.platform].getUrl(account.handle)\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"relative inline-flex items-center justify-center gap-2 rounded-full px-4 py-2 font-medium transition-colors duration-200 focus:outline-none active:opacity-80 cursor-pointer bg-white/10 hover:bg-white/20 border border-white/20 text-white/80 text-sm\"\n >\n <span class=\"flex items-center size-[1.1em] mt-[-.07em]\" :class=\"SOCIAL_PLATFORMS[account.platform].icon\" />\n {{ SOCIAL_PLATFORMS[account.platform].label }}\n </a>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { Bot } from '@pagelines/core'\nimport { handleImageError } from '../utils'\n\ninterface Props {\n bot: Bot\n isOnline?: boolean\n}\n\nconst { bot, isOnline = false } = defineProps<Props>()\n\n</script>\n\n<template>\n <div class=\"flex flex-col items-center text-center gap-4\">\n <!-- Avatar with online indicator -->\n <div class=\"relative flex-shrink-0\">\n <div class=\"w-20 h-20 sm:w-24 sm:h-24 rounded-full overflow-hidden border-4 border-white\">\n <img\n :src=\"bot.avatarUrl.value\"\n :alt=\"bot.displayName.value\"\n class=\"w-full h-full object-cover\"\n @error=\"handleImageError\"\n />\n </div>\n\n <div class=\"absolute top-1.5 right-1.5\">\n <template v-if=\"isOnline\">\n <div class=\"size-4 bg-green-500 rounded-full ring-2 ring-white absolute animate-ping\" style=\"animation-duration: 3s;\" />\n <div class=\"size-4 bg-green-500 rounded-full ring-2 ring-white\" />\n </template>\n <div v-else class=\"size-4 bg-theme-400 rounded-full ring-2 ring-white\" />\n </div>\n </div>\n\n <!-- Name and title -->\n <div class=\"min-w-0\">\n <h1 class=\"text-3xl font-light text-white mb-2 truncate\">\n {{ bot.displayName.value }}\n </h1>\n <p class=\"text-base font-light text-white/60 line-clamp-1\">\n {{ bot.title.value }}\n </p>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { Bot } from '@pagelines/core'\nimport { handleImageError } from '../utils'\n\ninterface Props {\n bot: Bot\n isOnline?: boolean\n}\n\nconst { bot, isOnline = false } = defineProps<Props>()\n\n</script>\n\n<template>\n <div class=\"flex flex-col items-center text-center gap-4\">\n <!-- Avatar with online indicator -->\n <div class=\"relative flex-shrink-0\">\n <div class=\"w-20 h-20 sm:w-24 sm:h-24 rounded-full overflow-hidden border-4 border-white\">\n <img\n :src=\"bot.avatarUrl.value\"\n :alt=\"bot.displayName.value\"\n class=\"w-full h-full object-cover\"\n @error=\"handleImageError\"\n />\n </div>\n\n <div class=\"absolute top-1.5 right-1.5\">\n <template v-if=\"isOnline\">\n <div class=\"size-4 bg-green-500 rounded-full ring-2 ring-white absolute animate-ping\" style=\"animation-duration: 3s;\" />\n <div class=\"size-4 bg-green-500 rounded-full ring-2 ring-white\" />\n </template>\n <div v-else class=\"size-4 bg-theme-400 rounded-full ring-2 ring-white\" />\n </div>\n </div>\n\n <!-- Name and title -->\n <div class=\"min-w-0\">\n <h1 class=\"text-3xl font-light text-white mb-2 truncate\">\n {{ bot.displayName.value }}\n </h1>\n <p class=\"text-base font-light text-white/60 line-clamp-1\">\n {{ bot.title.value }}\n </p>\n </div>\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport { onMounted, ref } from 'vue'\n\ndefineOptions({ name: 'SelfSidebarClose' })\n\ndefineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst inView = ref(false)\n\nonMounted(() => {\n setTimeout(() => {\n inView.value = true\n }, 100)\n})\n</script>\n\n<template>\n <a\n class=\"close block cursor-pointer w-[60px] h-[60px] rounded-full transition-all duration-1000 ease-[cubic-bezier(0.25,1,0.33,1)] hover:scale-110 active:scale-90 hover:rotate-90\"\n @click=\"$emit('click', $event)\"\n >\n <!-- Background circle (invisible, for hover area) -->\n <span class=\"absolute inset-0 rounded-full transition-all\" />\n\n <!-- Close lines container -->\n <span class=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[28px] h-[28px] overflow-hidden\">\n <!-- Line 1 - animates from bottom-left to center, rotates 45deg -->\n <span\n class=\"absolute h-full w-[3px] rounded-[5px] left-[13px] transition-all duration-[400ms] ease-[cubic-bezier(0.52,0.01,0.16,1)]\"\n :class=\"inView ? 'translate-y-0 translate-x-0 rotate-45' : 'translate-y-[30px] -translate-x-[30px] rotate-0'\"\n style=\"background-color: currentColor; transition-delay: 0.15s\"\n />\n\n <!-- Line 2 - animates from top-left to center, rotates -45deg -->\n <span\n class=\"absolute h-full w-[3px] rounded-[5px] left-[13px] transition-all duration-[400ms] ease-[cubic-bezier(0.52,0.01,0.16,1)]\"\n :class=\"inView ? 'translate-y-0 translate-x-0 -rotate-45' : '-translate-y-[30px] -translate-x-[30px] rotate-0'\"\n style=\"background-color: currentColor; transition-delay: 0.45s\"\n />\n </span>\n </a>\n</template>\n","<script lang=\"ts\" setup>\nimport { onMounted, ref } from 'vue'\n\ndefineOptions({ name: 'SelfSidebarClose' })\n\ndefineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst inView = ref(false)\n\nonMounted(() => {\n setTimeout(() => {\n inView.value = true\n }, 100)\n})\n</script>\n\n<template>\n <a\n class=\"close block cursor-pointer w-[60px] h-[60px] rounded-full transition-all duration-1000 ease-[cubic-bezier(0.25,1,0.33,1)] hover:scale-110 active:scale-90 hover:rotate-90\"\n @click=\"$emit('click', $event)\"\n >\n <!-- Background circle (invisible, for hover area) -->\n <span class=\"absolute inset-0 rounded-full transition-all\" />\n\n <!-- Close lines container -->\n <span class=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[28px] h-[28px] overflow-hidden\">\n <!-- Line 1 - animates from bottom-left to center, rotates 45deg -->\n <span\n class=\"absolute h-full w-[3px] rounded-[5px] left-[13px] transition-all duration-[400ms] ease-[cubic-bezier(0.52,0.01,0.16,1)]\"\n :class=\"inView ? 'translate-y-0 translate-x-0 rotate-45' : 'translate-y-[30px] -translate-x-[30px] rotate-0'\"\n style=\"background-color: currentColor; transition-delay: 0.15s\"\n />\n\n <!-- Line 2 - animates from top-left to center, rotates -45deg -->\n <span\n class=\"absolute h-full w-[3px] rounded-[5px] left-[13px] transition-all duration-[400ms] ease-[cubic-bezier(0.52,0.01,0.16,1)]\"\n :class=\"inView ? 'translate-y-0 translate-x-0 -rotate-45' : '-translate-y-[30px] -translate-x-[30px] rotate-0'\"\n style=\"background-color: currentColor; transition-delay: 0.45s\"\n />\n </span>\n </a>\n</template>\n","<script lang=\"ts\" setup>\nimport type { NavItem } from '@pagelines/core'\nimport { computed } from 'vue'\nimport BotSidebarClose from './BotSidebarClose.vue'\n\ndefineOptions({ name: 'ElSidebar', inheritAttrs: false })\n\nconst props = defineProps<{\n modelValue: boolean\n items: NavItem[]\n position?: 'left' | 'right'\n title?: string\n widthClasses?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nconst position = props.position || 'left'\nconst widthClasses = props.widthClasses || 'w-[80%] max-w-[300px]'\n\nconst isOpen = computed({\n get: () => props.modelValue,\n set: (value) => emit('update:modelValue', value),\n})\n\nconst visibleItems = computed(() => props.items.filter((item) => !item.isHidden))\n\nfunction handleItemClick(item: NavItem) {\n if (item.isDisabled)\n return\n\n if (item.onClick) {\n item.onClick({ item, event: new MouseEvent('click') })\n } else if (item.href) {\n if (item.href.includes('http')) {\n window.open(item.href, item.target || '_self')?.focus()\n } else {\n window.location.href = item.href\n }\n }\n\n isOpen.value = false\n}\n\n// Position-specific classes\nconst transitionClasses = computed(() => {\n if (position === 'left') {\n return {\n enter: '-translate-x-full',\n leave: '-translate-x-full',\n position: 'justify-start',\n closeButton: '-right-16',\n }\n } else {\n return {\n enter: 'translate-x-full',\n leave: 'translate-x-full',\n position: 'justify-end',\n closeButton: '-left-16',\n }\n }\n})\n</script>\n\n<template>\n <!-- Backdrop -->\n <Transition\n enter-active-class=\"transition-opacity duration-300 ease-out\"\n leave-active-class=\"transition-opacity duration-200 ease-in\"\n enter-from-class=\"opacity-0\"\n enter-to-class=\"opacity-100\"\n leave-from-class=\"opacity-100\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"isOpen\"\n class=\"absolute inset-0 z-40 bg-black/50 backdrop-blur-sm\"\n @click=\"isOpen = false\"\n />\n </Transition>\n\n <!-- Sidebar -->\n <Transition\n enter-active-class=\"transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)]\"\n leave-active-class=\"transition-all duration-400 ease-[cubic-bezier(0.25,1,0.33,1)]\"\n :enter-from-class=\"transitionClasses.enter\"\n enter-to-class=\"translate-x-0\"\n leave-from-class=\"translate-x-0\"\n :leave-to-class=\"transitionClasses.leave\"\n >\n <div\n v-if=\"isOpen\"\n class=\"absolute inset-0 z-50 flex\"\n :class=\"transitionClasses.position\"\n @click=\"isOpen = false\"\n >\n <!-- Menu Panel -->\n <div\n class=\"relative h-full shadow-2xl bg-black/30 backdrop-blur-xl flex flex-col justify-center\"\n :class=\"widthClasses\"\n @click.stop\n >\n <BotSidebarClose\n class=\"absolute top-4 z-10 text-white\"\n :class=\"transitionClasses.closeButton\"\n @click=\"isOpen = false\"\n />\n\n <!-- Title -->\n <div v-if=\"title\" class=\"px-9 pt-12 pb-4\">\n <h3 class=\"text-base font-medium text-theme-400\">\n {{ title }}\n </h3>\n </div>\n\n <!-- Header Slot -->\n <div v-if=\"$slots.header\" class=\"px-4 pb-8 border-b border-white/10\">\n <slot name=\"header\" />\n </div>\n\n <!-- Menu Items -->\n <div class=\"flex-1 p-6 space-y-2 overflow-y-auto\" :class=\"{ 'pt-6': !title && !$slots.header, 'pt-4': title || $slots.header }\">\n <TransitionGroup\n enter-active-class=\"transition-all duration-400 ease-[cubic-bezier(0.25,1,0.33,1)]\"\n leave-active-class=\"transition-all duration-200 ease-[cubic-bezier(0.25,1,0.33,1)]\"\n :enter-from-class=\"position === 'left' ? '-translate-x-4 opacity-0' : 'translate-x-4 opacity-0'\"\n enter-to-class=\"translate-x-0 opacity-100\"\n leave-from-class=\"translate-x-0 opacity-100\"\n :leave-to-class=\"position === 'left' ? '-translate-x-4 opacity-0' : 'translate-x-4 opacity-0'\"\n >\n <button\n v-for=\"(item, index) in visibleItems\"\n :key=\"item.key || item.label || index\"\n :style=\"{ transitionDelay: `${index * 40}ms` }\"\n class=\"cursor-pointer w-full text-left p-3 rounded-xl transition-all duration-200 ease-[cubic-bezier(0.25,1,0.33,1)] group\"\n :class=\"[\n item.isActive\n ? 'bg-primary-500/20 border border-primary-500/40'\n : 'hover:bg-white/10',\n item.isDisabled && 'opacity-50 cursor-not-allowed',\n ]\"\n :disabled=\"item.isDisabled\"\n @click=\"handleItemClick(item)\"\n >\n <div class=\"flex items-center gap-3\">\n <i\n v-if=\"item.icon?.src\"\n class=\"size-5 flex-shrink-0 transition-transform duration-200 ease-[cubic-bezier(0.25,1,0.33,1)] group-hover:scale-110\"\n :class=\"[\n item.icon.src,\n item.isActive ? 'text-primary-400' : 'text-white/70 group-hover:text-white',\n ]\"\n />\n <div class=\"flex-1\">\n <div\n class=\"font-medium text-sm\"\n :class=\"item.isActive ? 'text-primary-300' : 'text-white'\"\n >\n {{ item.label }}\n </div>\n <div v-if=\"item.subLabel\" class=\"text-xs text-white/50 mt-0.5\">\n {{ item.subLabel }}\n </div>\n </div>\n </div>\n </button>\n </TransitionGroup>\n </div>\n\n <!-- Footer -->\n <div class=\"p-6\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n</template>\n","<script lang=\"ts\" setup>\nimport type { NavItem } from '@pagelines/core'\nimport { computed } from 'vue'\nimport BotSidebarClose from './BotSidebarClose.vue'\n\ndefineOptions({ name: 'ElSidebar', inheritAttrs: false })\n\nconst props = defineProps<{\n modelValue: boolean\n items: NavItem[]\n position?: 'left' | 'right'\n title?: string\n widthClasses?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nconst position = props.position || 'left'\nconst widthClasses = props.widthClasses || 'w-[80%] max-w-[300px]'\n\nconst isOpen = computed({\n get: () => props.modelValue,\n set: (value) => emit('update:modelValue', value),\n})\n\nconst visibleItems = computed(() => props.items.filter((item) => !item.isHidden))\n\nfunction handleItemClick(item: NavItem) {\n if (item.isDisabled)\n return\n\n if (item.onClick) {\n item.onClick({ item, event: new MouseEvent('click') })\n } else if (item.href) {\n if (item.href.includes('http')) {\n window.open(item.href, item.target || '_self')?.focus()\n } else {\n window.location.href = item.href\n }\n }\n\n isOpen.value = false\n}\n\n// Position-specific classes\nconst transitionClasses = computed(() => {\n if (position === 'left') {\n return {\n enter: '-translate-x-full',\n leave: '-translate-x-full',\n position: 'justify-start',\n closeButton: '-right-16',\n }\n } else {\n return {\n enter: 'translate-x-full',\n leave: 'translate-x-full',\n position: 'justify-end',\n closeButton: '-left-16',\n }\n }\n})\n</script>\n\n<template>\n <!-- Backdrop -->\n <Transition\n enter-active-class=\"transition-opacity duration-300 ease-out\"\n leave-active-class=\"transition-opacity duration-200 ease-in\"\n enter-from-class=\"opacity-0\"\n enter-to-class=\"opacity-100\"\n leave-from-class=\"opacity-100\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"isOpen\"\n class=\"absolute inset-0 z-40 bg-black/50 backdrop-blur-sm\"\n @click=\"isOpen = false\"\n />\n </Transition>\n\n <!-- Sidebar -->\n <Transition\n enter-active-class=\"transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)]\"\n leave-active-class=\"transition-all duration-400 ease-[cubic-bezier(0.25,1,0.33,1)]\"\n :enter-from-class=\"transitionClasses.enter\"\n enter-to-class=\"translate-x-0\"\n leave-from-class=\"translate-x-0\"\n :leave-to-class=\"transitionClasses.leave\"\n >\n <div\n v-if=\"isOpen\"\n class=\"absolute inset-0 z-50 flex\"\n :class=\"transitionClasses.position\"\n @click=\"isOpen = false\"\n >\n <!-- Menu Panel -->\n <div\n class=\"relative h-full shadow-2xl bg-black/30 backdrop-blur-xl flex flex-col justify-center\"\n :class=\"widthClasses\"\n @click.stop\n >\n <BotSidebarClose\n class=\"absolute top-4 z-10 text-white\"\n :class=\"transitionClasses.closeButton\"\n @click=\"isOpen = false\"\n />\n\n <!-- Title -->\n <div v-if=\"title\" class=\"px-9 pt-12 pb-4\">\n <h3 class=\"text-base font-medium text-theme-400\">\n {{ title }}\n </h3>\n </div>\n\n <!-- Header Slot -->\n <div v-if=\"$slots.header\" class=\"px-4 pb-8 border-b border-white/10\">\n <slot name=\"header\" />\n </div>\n\n <!-- Menu Items -->\n <div class=\"flex-1 p-6 space-y-2 overflow-y-auto\" :class=\"{ 'pt-6': !title && !$slots.header, 'pt-4': title || $slots.header }\">\n <TransitionGroup\n enter-active-class=\"transition-all duration-400 ease-[cubic-bezier(0.25,1,0.33,1)]\"\n leave-active-class=\"transition-all duration-200 ease-[cubic-bezier(0.25,1,0.33,1)]\"\n :enter-from-class=\"position === 'left' ? '-translate-x-4 opacity-0' : 'translate-x-4 opacity-0'\"\n enter-to-class=\"translate-x-0 opacity-100\"\n leave-from-class=\"translate-x-0 opacity-100\"\n :leave-to-class=\"position === 'left' ? '-translate-x-4 opacity-0' : 'translate-x-4 opacity-0'\"\n >\n <button\n v-for=\"(item, index) in visibleItems\"\n :key=\"item.key || item.label || index\"\n :style=\"{ transitionDelay: `${index * 40}ms` }\"\n class=\"cursor-pointer w-full text-left p-3 rounded-xl transition-all duration-200 ease-[cubic-bezier(0.25,1,0.33,1)] group\"\n :class=\"[\n item.isActive\n ? 'bg-primary-500/20 border border-primary-500/40'\n : 'hover:bg-white/10',\n item.isDisabled && 'opacity-50 cursor-not-allowed',\n ]\"\n :disabled=\"item.isDisabled\"\n @click=\"handleItemClick(item)\"\n >\n <div class=\"flex items-center gap-3\">\n <i\n v-if=\"item.icon?.src\"\n class=\"size-5 flex-shrink-0 transition-transform duration-200 ease-[cubic-bezier(0.25,1,0.33,1)] group-hover:scale-110\"\n :class=\"[\n item.icon.src,\n item.isActive ? 'text-primary-400' : 'text-white/70 group-hover:text-white',\n ]\"\n />\n <div class=\"flex-1\">\n <div\n class=\"font-medium text-sm\"\n :class=\"item.isActive ? 'text-primary-300' : 'text-white'\"\n >\n {{ item.label }}\n </div>\n <div v-if=\"item.subLabel\" class=\"text-xs text-white/50 mt-0.5\">\n {{ item.subLabel }}\n </div>\n </div>\n </div>\n </button>\n </TransitionGroup>\n </div>\n\n <!-- Footer -->\n <div class=\"p-6\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n</template>\n","<script lang=\"ts\" setup>\nimport type { BotMode } from '../schema'\nimport type { BotChatController } from '../BotController'\nimport type { NavItem } from '@pagelines/core'\nimport { computed } from 'vue'\nimport { BOT_MODES } from '../schema'\nimport ElSidebar from './ElSidebar.vue'\n\ndefineOptions({ name: 'BotModeSidebar' })\n\nconst props = defineProps<{\n modelValue: boolean\n chatController?: BotChatController\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nconst isOpen = computed({\n get: () => props.modelValue,\n set: (value) => emit('update:modelValue', value),\n})\n\nconst currentMode = computed(() => props.chatController?.botMode?.value ?? 'self')\n\nconst modeItems = computed<NavItem[]>(() => BOT_MODES.map((mode) => ({\n key: mode.mode,\n icon: { src: mode.icon },\n label: mode.label,\n isActive: currentMode.value === mode.mode,\n onClick: () => {\n props.chatController?.setMode(mode.mode as BotMode)\n },\n})))\n</script>\n\n<template>\n <ElSidebar\n v-model=\"isOpen\"\n :items=\"modeItems\"\n position=\"right\"\n title=\"Mode\"\n width-classes=\"w-[80%] max-w-[255px]\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport type { BotMode } from '../schema'\nimport type { BotChatController } from '../BotController'\nimport type { NavItem } from '@pagelines/core'\nimport { computed } from 'vue'\nimport { BOT_MODES } from '../schema'\nimport ElSidebar from './ElSidebar.vue'\n\ndefineOptions({ name: 'BotModeSidebar' })\n\nconst props = defineProps<{\n modelValue: boolean\n chatController?: BotChatController\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nconst isOpen = computed({\n get: () => props.modelValue,\n set: (value) => emit('update:modelValue', value),\n})\n\nconst currentMode = computed(() => props.chatController?.botMode?.value ?? 'self')\n\nconst modeItems = computed<NavItem[]>(() => BOT_MODES.map((mode) => ({\n key: mode.mode,\n icon: { src: mode.icon },\n label: mode.label,\n isActive: currentMode.value === mode.mode,\n onClick: () => {\n props.chatController?.setMode(mode.mode as BotMode)\n },\n})))\n</script>\n\n<template>\n <ElSidebar\n v-model=\"isOpen\"\n :items=\"modeItems\"\n position=\"right\"\n title=\"Mode\"\n width-classes=\"w-[80%] max-w-[255px]\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { NavItem } from '@pagelines/core'\nimport { Bot } from '../schema'\nimport { computed } from 'vue'\nimport ElSidebar from './ElSidebar.vue'\n\ndefineOptions({ name: 'BotSidebar' })\n\nconst props = defineProps<{\n modelValue: boolean\n bot: Bot\n sdk: PageLinesSDK\n title?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nconst isOpen = computed({\n get: () => props.modelValue,\n set: (value) => emit('update:modelValue', value),\n})\n\nconst menuItems = computed<NavItem[]>(() => {\n const items: NavItem[] = [\n {\n key: 'share',\n icon: { src: 'i-tabler-share' },\n label: 'Share this assistant',\n onClick: () => {\n const url = `${window.location.origin}/@${props.bot.handle.value || props.bot.botId.value}`\n // TODO: Show notification that URL was copied (SDK has no notify host).\n navigator.clipboard.writeText(url).catch((err) => {\n console.error('ElBotSidebar: clipboard.writeText rejected', err)\n })\n },\n },\n {\n key: 'profile',\n icon: { src: 'i-tabler-user' },\n label: 'View full profile',\n onClick: () => {\n window.open(`/@${props.bot.handle.value || props.bot.botId.value}`, '_blank')\n },\n },\n {\n key: 'create',\n icon: { src: 'i-tabler-sparkles' },\n label: 'Create your own',\n onClick: () => {\n window.open('/auth', '_blank')\n },\n },\n ]\n\n // Add logout option if user is authenticated\n if (props.sdk.activeUser.value) {\n items.push({\n key: 'logout',\n icon: { src: 'i-tabler-logout' },\n label: 'Logout',\n onClick: async () => {\n await props.sdk.auth.logout()\n },\n })\n }\n\n return items\n})\n</script>\n\n<template>\n <ElSidebar\n v-model=\"isOpen\"\n :items=\"menuItems\"\n position=\"left\"\n :title=\"title || 'Menu'\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { NavItem } from '@pagelines/core'\nimport { Bot } from '../schema'\nimport { computed } from 'vue'\nimport ElSidebar from './ElSidebar.vue'\n\ndefineOptions({ name: 'BotSidebar' })\n\nconst props = defineProps<{\n modelValue: boolean\n bot: Bot\n sdk: PageLinesSDK\n title?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nconst isOpen = computed({\n get: () => props.modelValue,\n set: (value) => emit('update:modelValue', value),\n})\n\nconst menuItems = computed<NavItem[]>(() => {\n const items: NavItem[] = [\n {\n key: 'share',\n icon: { src: 'i-tabler-share' },\n label: 'Share this assistant',\n onClick: () => {\n const url = `${window.location.origin}/@${props.bot.handle.value || props.bot.botId.value}`\n // TODO: Show notification that URL was copied (SDK has no notify host).\n navigator.clipboard.writeText(url).catch((err) => {\n console.error('ElBotSidebar: clipboard.writeText rejected', err)\n })\n },\n },\n {\n key: 'profile',\n icon: { src: 'i-tabler-user' },\n label: 'View full profile',\n onClick: () => {\n window.open(`/@${props.bot.handle.value || props.bot.botId.value}`, '_blank')\n },\n },\n {\n key: 'create',\n icon: { src: 'i-tabler-sparkles' },\n label: 'Create your own',\n onClick: () => {\n window.open('/auth', '_blank')\n },\n },\n ]\n\n // Add logout option if user is authenticated\n if (props.sdk.activeUser.value) {\n items.push({\n key: 'logout',\n icon: { src: 'i-tabler-logout' },\n label: 'Logout',\n onClick: async () => {\n await props.sdk.auth.logout()\n },\n })\n }\n\n return items\n})\n</script>\n\n<template>\n <ElSidebar\n v-model=\"isOpen\"\n :items=\"menuItems\"\n position=\"left\"\n :title=\"title || 'Menu'\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport type { BotChatControllerSettings } from '../BotController'\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { ButtonIconPreset } from '../../widget/PLWidget'\nimport type { ColorName } from '@pagelines/core'\nimport { Bot } from '../schema'\nimport { computed, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'\nimport { SOCIAL_PLATFORMS } from '../../constants/socialPlatforms'\nimport FSpinner from '../../ui/FSpinner.vue'\nimport { getColorSchemeOklch } from '@pagelines/core'\nimport { BOT_MODES } from '../schema'\nimport { BotChatController } from '../BotController'\nimport { parseButtonTemplate } from '../utils'\nimport ElAuthGate from './ElAuthGate.vue'\nimport ElModeHeader from './ElModeHeader.vue'\nimport ElBotAbout from './ElBotAbout.vue'\nimport ElBotButton from './ElBotButton.vue'\nimport ElBotChat from './ElBotChat.vue'\nimport ElBotHeader from './ElBotHeader.vue'\nimport ElBotModeSidebar from './ElBotModeSidebar.vue'\nimport ElBotSidebar from './ElBotSidebar.vue'\n\nconst {\n sdk,\n bot,\n context,\n firstMessage,\n buttonText,\n buttonIcon,\n hasClose = false,\n isActive = true,\n loading = false,\n theme = 'green',\n requireAuth = false,\n chatOnly = false,\n bare = false,\n emptyStateMessage,\n createVoiceClientFn,\n} = defineProps<{\n sdk: PageLinesSDK\n bot: Bot\n context?: string\n firstMessage?: string\n buttonText?: string\n buttonIcon?: ButtonIconPreset\n hasClose?: boolean\n isActive?: boolean\n loading?: boolean\n theme?: ColorName\n requireAuth?: boolean\n chatOnly?: boolean\n /** Render chat without profile chrome so a host page can provide it. */\n bare?: boolean\n emptyStateMessage?: string\n /** Voice transport, supplied by hosts that ship it. See the note in createChatController. */\n createVoiceClientFn?: BotChatControllerSettings['createVoiceClientFn']\n}>()\n\ndefineSlots<{\n 'empty-heading': (props: { bot: Bot, isLight: boolean }) => any\n}>()\n\nconst emit = defineEmits<{\n close: [value: string]\n error: [message: string]\n turnStarted: []\n turnCompleted: [conversationId: string]\n}>()\n\nconst chatController = shallowRef<BotChatController>()\nconst isSidebarOpen = ref(false)\nconst isModeSidebarOpen = ref(false)\nconst initError = ref<string>()\nconst rootElement = ref<HTMLElement>()\n\nconst botMode = computed(() => chatController.value?.botMode?.value ?? 'self')\nconst isOnline = computed(() => chatController.value?.textState.value.isConnected ?? false)\n\n// Check if user is authenticated\nconst isAuthenticated = computed(() => sdk.activeUser.value !== undefined)\n\n// Current mode for button display\nconst currentMode = computed(() => BOT_MODES.find((btn) => btn.mode === botMode.value))\n\nfunction createChatController() {\n if (chatController.value) {\n chatController.value.destroy()\n }\n\n try {\n chatController.value = new BotChatController({\n sdk,\n bot,\n context,\n firstMessage,\n // No voice wiring here on purpose: this component is reachable from the\n // embeddable widget (PLWidget lazy-loads its modal/inline modes, and the\n // IIFE build inlines those), so any static edge to the LiveKit transport\n // lands a WebRTC stack on every host page. Hosts that do voice pass\n // `createVoiceClientFn` down themselves.\n ...(createVoiceClientFn ? { createVoiceClientFn } : {}),\n onTurnStarted: () => emit('turnStarted'),\n onTurnCompleted: conversationId => emit('turnCompleted', conversationId),\n })\n } catch (error) {\n console.error('BotChatController creation failed:', error)\n throw error\n }\n}\n\ntry {\n createChatController()\n} catch (error) {\n const message = error instanceof Error ? error.message : 'Couldn\\'t initialize your assistant'\n initError.value = message\n emit('error', message)\n}\n\n// Set theme CSS variables\nfunction applyTheme(themeName: ColorName) {\n if (!rootElement.value)\n return\n\n const colorScheme = getColorSchemeOklch(themeName)\n\n // Set --primary-* CSS variables on component root for Shadow DOM compatibility\n Object.entries(colorScheme).forEach(([scale, value]) => {\n rootElement.value!.style.setProperty(`--primary-${scale}`, value)\n })\n}\n\nonMounted(() => {\n try {\n applyTheme(theme)\n\n // In chatOnly mode, jump straight to chat\n if (chatOnly && chatController.value) {\n chatController.value.setMode('chat')\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Couldn\\'t initialize your assistant'\n initError.value = message\n emit('error', message)\n }\n})\n\nonUnmounted(() => {\n if (chatController.value) {\n chatController.value.destroy()\n }\n})\n\n// Watch theme changes and reapply\nwatch(() => theme, (newTheme) => {\n applyTheme(newTheme)\n})\n\n// Reset to self mode when user logs out\nwatch(() => sdk.activeUser.value, (newUser, oldUser) => {\n // User logged out (had user, now undefined)\n if (oldUser && !newUser && chatController.value) {\n chatController.value.setMode('self')\n }\n})\n\nconst isLowQuality = computed(() => {\n return !!(bot.cover.value?.src && bot.cover.value?.quality === 'low') || !!(bot.avatar.value?.src && bot.avatar.value?.quality === 'low')\n})\n\nconst backdropClass = computed(() => {\n const out = [isLowQuality.value ? 'backdrop-blur-sm' : '']\n\n if(isLowQuality.value && botMode.value === 'self') {\n out.push('from-black/80 via-black/60 to-black/80')\n }\n else if (botMode.value === 'self') {\n out.push('from-black/70 via-black/50 to-black/80')\n }\n else {\n out.push('from-black/90 via-black/90 to-black/100')\n }\n\n return out.join(' ')\n})\n\n// Icon preset mapping\nconst ICON_MAP: Record<ButtonIconPreset, string> = {\n phone: 'i-heroicons-phone',\n calendar: 'i-heroicons-calendar',\n question: 'i-heroicons-question-mark-circle',\n message: 'i-heroicons-chat-bubble-left-right',\n sparkles: 'i-heroicons-sparkles',\n}\n\n// Resolve button text with template variables\nconst resolvedButtonText = computed(() => {\n return parseButtonTemplate({\n template: buttonText || 'Talk to {name}',\n bot: bot.toData(),\n })\n})\n\n// Resolve button icon from preset or default to phone\nconst resolvedButtonIcon = computed(() => {\n return ICON_MAP[buttonIcon || 'phone'] || ICON_MAP.phone\n})\n</script>\n\n<template>\n <div\n ref=\"rootElement\"\n :key=\"bot.avatarUrl.value\"\n class=\"pagelines-sdk @container/bot pagelines-bot w-full h-full overflow-hidden relative\"\n data-test=\"bot-chat\"\n >\n <div v-if=\"loading\" class=\"absolute inset-0 flex items-center justify-center bg-gradient-to-br from-theme-800 to-theme-950 rounded-3xl z-10\">\n <FSpinner class=\"text-white size-8\" />\n </div>\n\n <!-- bare: no background at any layer — the host page owns the canvas\n (the app's chat surface is white); any paint here shows as a\n stripe against the host canvas. -->\n <div\n v-else-if=\"bot && !initError\"\n class=\"absolute inset-0\"\n :class=\"bare ? '' : 'bg-cover bg-center bg-no-repeat'\"\n :style=\"bare ? undefined : { backgroundImage: `url(${bot.avatarUrl.value})` }\"\n :data-quality=\"bot.avatar.value?.quality || 'none'\"\n >\n <div\n v-if=\"!bare\"\n class=\"absolute inset-0 bg-gradient-to-br z-0\"\n :class=\"backdropClass\"\n />\n <div\n class=\"relative z-10 flex flex-col h-full transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)] will-change-transform\"\n :class=\"isActive ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-2'\"\n >\n <div v-if=\"!bare || hasClose\" class=\"relative z-30 p-2\" :class=\"!bare && botMode !== 'self' ? 'backdrop-blur-lg' : ''\">\n <!-- A bare chat embed supplies its own surrounding header. -->\n <div v-if=\"chatOnly\" class=\"flex items-center\" :class=\"bare ? 'justify-end' : ''\">\n <div v-if=\"!bare\" class=\"flex flex-1 items-center gap-3 pl-2\">\n <img\n :src=\"bot.avatarUrl.value\"\n :alt=\"bot.displayName.value\"\n class=\"size-8 rounded-full object-cover\"\n />\n <span class=\"text-sm font-medium text-white/90\">{{ bot.displayName.value }}</span>\n </div>\n <div v-if=\"hasClose\" class=\"flex justify-end\">\n <button\n class=\"flex cursor-pointer items-center rounded-2xl p-3 transition-colors\"\n :class=\"bare ? 'text-theme-500 hover:bg-theme-50' : 'text-white/70 hover:bg-white/10'\"\n @click.stop=\"emit('close', 'button')\"\n >\n <i class=\"size-6 i-tabler-x\" />\n </button>\n </div>\n </div>\n\n <!-- Full header with mode selector and sidebars -->\n <div v-else class=\"flex items-center\" :class=\"hasClose ? '' : 'justify-between'\">\n <!-- Left side: Sidebar toggle with user avatar -->\n <div :class=\"hasClose ? 'flex-1 basis-0' : ''\">\n <button\n class=\"cursor-pointer p-2 flex items-center gap-2 rounded-2xl text-white/70 hover:bg-white/10 transition-all duration-300 ease-[cubic-bezier(0.25,1,0.33,1)] hover:scale-105 active:scale-95\"\n @click=\"isSidebarOpen = true\"\n >\n <i class=\"i-tabler-menu size-7\" />\n </button>\n </div>\n\n <!-- Center: Mode selector button (centered when hasClose=true) -->\n <button\n class=\"flex items-center gap-2 px-3.5 py-3 rounded-2xl text-white/90 hover:bg-white/10 transition-all cursor-pointer flex-grow-0\"\n :class=\"{ 'bg-white/10': isModeSidebarOpen }\"\n @click=\"isModeSidebarOpen = true\"\n >\n <i :class=\"currentMode?.icon\" class=\"size-4 opacity-60\" />\n <span class=\"text-sm\">{{ currentMode?.label }}</span>\n <i class=\"i-tabler-chevron-down size-4\" />\n </button>\n\n <!-- Right side: Close button (only in widget mode) -->\n <div v-if=\"hasClose\" class=\"flex-1 basis-0 flex justify-end\">\n <button\n class=\"cursor-pointer flex items-center p-3 rounded-2xl text-white/70 hover:bg-white/10 transition-colors\"\n @click.stop=\"emit('close', 'button')\"\n >\n <i class=\"size-6 i-tabler-x\" />\n </button>\n </div>\n </div>\n </div>\n\n <!-- chatOnly: skip all modes, show chat directly -->\n <!-- bare: the host page owns the canvas (the app's chat surface is\n white); a mismatched paint here reads as a stripe against it. -->\n <div\n v-if=\"chatOnly\"\n class=\"relative z-20 flex min-h-0 w-full flex-1 flex-col\"\n :class=\"bare ? '' : 'px-4'\"\n >\n <div class=\"min-h-0 w-full flex-1\" :class=\"bare ? '' : 'mx-auto max-w-md'\">\n <ElBotChat\n :chat-controller=\"chatController\"\n :bot=\"bot\"\n :scope=\"isAuthenticated ? 'private' : 'public'\"\n :empty-state-message=\"emptyStateMessage\"\n :variant=\"bare ? 'light' : 'dark'\"\n :show-header=\"!bare\"\n :centered=\"bare\"\n >\n <template v-if=\"$slots['empty-heading']\" #empty-heading=\"headingProps\">\n <slot name=\"empty-heading\" v-bind=\"headingProps\" />\n </template>\n </ElBotChat>\n </div>\n </div>\n\n <!-- Full bot interface modes -->\n <template v-else>\n <div\n v-if=\"botMode === 'self'\"\n class=\"h-full pb-12 flex-1 flex flex-col relative z-20 min-h-0 px-4 @[480px]/bot:px-6 max-w-md mx-auto w-full\"\n >\n <!-- Top spacer -->\n <div class=\"flex-1 basis-0 mb-12\" />\n\n <!-- Avatar header -->\n <ElBotHeader :bot=\"bot\" :is-online=\"isOnline\" />\n\n <!-- Bottom section with button and social links -->\n <div class=\"flex-1 basis-0 flex flex-col justify-start pt-8 gap-7\">\n <ElBotButton\n theme=\"primary\"\n size=\"lg\"\n class=\"w-full\"\n :icon=\"resolvedButtonIcon\"\n data-test=\"voice-button\"\n @click=\"chatController?.setMode('talk')\"\n >\n {{ resolvedButtonText }}\n </ElBotButton>\n\n <!-- Social icon links -->\n <div v-if=\"bot.accounts.value && bot.accounts.value.length > 0\" class=\"flex items-center justify-center gap-3\">\n <a\n v-for=\"account in (bot.accounts.value || []).filter(a => SOCIAL_PLATFORMS[a.platform])\"\n :key=\"`${account.platform}-${account.handle}`\"\n :href=\"SOCIAL_PLATFORMS[account.platform].getUrl(account.handle)\"\n target=\"_blank\"\n class=\"size-12 rounded-full text-white/60 hover:text-white hover:bg-white/5 border border-white/0 hover:border-white/10 flex items-center justify-center transition-all duration-200 hover:scale-105\"\n >\n <i :class=\"SOCIAL_PLATFORMS[account.platform].icon\" class=\"size-5 \" />\n </a>\n </div>\n </div>\n </div>\n <div\n v-else-if=\"botMode === 'talk'\"\n class=\"flex-1 flex flex-col relative z-20 min-h-0 w-full gap-4 px-4\"\n >\n <ElAuthGate v-if=\"requireAuth && !isAuthenticated\" :sdk=\"sdk\" />\n <template v-else>\n <!-- Sticky header with backdrop blur - full width -->\n <div>\n <div class=\"max-w-md mx-auto\">\n <ElModeHeader :bot=\"bot\" :is-online=\"isOnline\" />\n </div>\n </div>\n <ElBotChat\n :chat-controller=\"chatController\"\n :bot=\"bot\"\n />\n </template>\n </div>\n <div\n v-else\n class=\"flex-1 flex flex-col relative z-20 min-h-0 w-full px-4 @[480px]/bot:px-6\"\n >\n <div class=\"flex-1 min-h-0 max-w-md mx-auto w-full\">\n <template v-if=\"botMode === 'chat'\">\n <ElAuthGate v-if=\"requireAuth && !isAuthenticated\" :sdk=\"sdk\" />\n <ElBotChat\n v-else\n :chat-controller=\"chatController\"\n :bot=\"bot\"\n show-header\n />\n </template>\n <ElBotAbout\n v-else-if=\"botMode === 'info'\"\n :bot=\"bot\"\n :is-online=\"isOnline\"\n />\n </div>\n </div>\n </template>\n\n </div>\n </div>\n <div v-else-if=\"initError\" class=\"bg-gradient-to-br from-theme-800 to-theme-950 text-white flex items-center justify-center h-full p-8\">\n <div class=\"text-center max-w-md space-y-4\">\n <div class=\"flex justify-center\">\n <div class=\"rounded-full bg-red-500/20 flex items-center justify-center size-10\">\n <i class=\"i-tabler-alert-circle size-6 text-red-400\" />\n </div>\n </div>\n <h3 class=\"text-lg font-medium\">\n Bot Error\n </h3>\n <p class=\"text-sm text-white/70 leading-relaxed\">\n {{ initError }}\n </p>\n </div>\n </div>\n <div v-else class=\"bg-white/10 backdrop-blur-sm text-white/70 flex items-center justify-center h-full\">\n Couldn't load your assistant. Please try again later.\n </div>\n\n <!-- Bot Sidebar (left) — hidden in chatOnly mode -->\n <ElBotSidebar\n v-if=\"!chatOnly\"\n v-model=\"isSidebarOpen\"\n :bot=\"bot\"\n :sdk=\"sdk\"\n :title=\"bot.displayName.value\"\n data-test=\"bot-sidebar\"\n />\n\n <!-- Mode Sidebar (right) — hidden in chatOnly mode -->\n <ElBotModeSidebar\n v-if=\"!chatOnly\"\n v-model=\"isModeSidebarOpen\"\n :chat-controller=\"chatController\"\n data-test=\"bot-mode-sidebar\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { BotChatControllerSettings } from '../BotController'\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { ButtonIconPreset } from '../../widget/PLWidget'\nimport type { ColorName } from '@pagelines/core'\nimport { Bot } from '../schema'\nimport { computed, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'\nimport { SOCIAL_PLATFORMS } from '../../constants/socialPlatforms'\nimport FSpinner from '../../ui/FSpinner.vue'\nimport { getColorSchemeOklch } from '@pagelines/core'\nimport { BOT_MODES } from '../schema'\nimport { BotChatController } from '../BotController'\nimport { parseButtonTemplate } from '../utils'\nimport ElAuthGate from './ElAuthGate.vue'\nimport ElModeHeader from './ElModeHeader.vue'\nimport ElBotAbout from './ElBotAbout.vue'\nimport ElBotButton from './ElBotButton.vue'\nimport ElBotChat from './ElBotChat.vue'\nimport ElBotHeader from './ElBotHeader.vue'\nimport ElBotModeSidebar from './ElBotModeSidebar.vue'\nimport ElBotSidebar from './ElBotSidebar.vue'\n\nconst {\n sdk,\n bot,\n context,\n firstMessage,\n buttonText,\n buttonIcon,\n hasClose = false,\n isActive = true,\n loading = false,\n theme = 'green',\n requireAuth = false,\n chatOnly = false,\n bare = false,\n emptyStateMessage,\n createVoiceClientFn,\n} = defineProps<{\n sdk: PageLinesSDK\n bot: Bot\n context?: string\n firstMessage?: string\n buttonText?: string\n buttonIcon?: ButtonIconPreset\n hasClose?: boolean\n isActive?: boolean\n loading?: boolean\n theme?: ColorName\n requireAuth?: boolean\n chatOnly?: boolean\n /** Render chat without profile chrome so a host page can provide it. */\n bare?: boolean\n emptyStateMessage?: string\n /** Voice transport, supplied by hosts that ship it. See the note in createChatController. */\n createVoiceClientFn?: BotChatControllerSettings['createVoiceClientFn']\n}>()\n\ndefineSlots<{\n 'empty-heading': (props: { bot: Bot, isLight: boolean }) => any\n}>()\n\nconst emit = defineEmits<{\n close: [value: string]\n error: [message: string]\n turnStarted: []\n turnCompleted: [conversationId: string]\n}>()\n\nconst chatController = shallowRef<BotChatController>()\nconst isSidebarOpen = ref(false)\nconst isModeSidebarOpen = ref(false)\nconst initError = ref<string>()\nconst rootElement = ref<HTMLElement>()\n\nconst botMode = computed(() => chatController.value?.botMode?.value ?? 'self')\nconst isOnline = computed(() => chatController.value?.textState.value.isConnected ?? false)\n\n// Check if user is authenticated\nconst isAuthenticated = computed(() => sdk.activeUser.value !== undefined)\n\n// Current mode for button display\nconst currentMode = computed(() => BOT_MODES.find((btn) => btn.mode === botMode.value))\n\nfunction createChatController() {\n if (chatController.value) {\n chatController.value.destroy()\n }\n\n try {\n chatController.value = new BotChatController({\n sdk,\n bot,\n context,\n firstMessage,\n // No voice wiring here on purpose: this component is reachable from the\n // embeddable widget (PLWidget lazy-loads its modal/inline modes, and the\n // IIFE build inlines those), so any static edge to the LiveKit transport\n // lands a WebRTC stack on every host page. Hosts that do voice pass\n // `createVoiceClientFn` down themselves.\n ...(createVoiceClientFn ? { createVoiceClientFn } : {}),\n onTurnStarted: () => emit('turnStarted'),\n onTurnCompleted: conversationId => emit('turnCompleted', conversationId),\n })\n } catch (error) {\n console.error('BotChatController creation failed:', error)\n throw error\n }\n}\n\ntry {\n createChatController()\n} catch (error) {\n const message = error instanceof Error ? error.message : 'Couldn\\'t initialize your assistant'\n initError.value = message\n emit('error', message)\n}\n\n// Set theme CSS variables\nfunction applyTheme(themeName: ColorName) {\n if (!rootElement.value)\n return\n\n const colorScheme = getColorSchemeOklch(themeName)\n\n // Set --primary-* CSS variables on component root for Shadow DOM compatibility\n Object.entries(colorScheme).forEach(([scale, value]) => {\n rootElement.value!.style.setProperty(`--primary-${scale}`, value)\n })\n}\n\nonMounted(() => {\n try {\n applyTheme(theme)\n\n // In chatOnly mode, jump straight to chat\n if (chatOnly && chatController.value) {\n chatController.value.setMode('chat')\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Couldn\\'t initialize your assistant'\n initError.value = message\n emit('error', message)\n }\n})\n\nonUnmounted(() => {\n if (chatController.value) {\n chatController.value.destroy()\n }\n})\n\n// Watch theme changes and reapply\nwatch(() => theme, (newTheme) => {\n applyTheme(newTheme)\n})\n\n// Reset to self mode when user logs out\nwatch(() => sdk.activeUser.value, (newUser, oldUser) => {\n // User logged out (had user, now undefined)\n if (oldUser && !newUser && chatController.value) {\n chatController.value.setMode('self')\n }\n})\n\nconst isLowQuality = computed(() => {\n return !!(bot.cover.value?.src && bot.cover.value?.quality === 'low') || !!(bot.avatar.value?.src && bot.avatar.value?.quality === 'low')\n})\n\nconst backdropClass = computed(() => {\n const out = [isLowQuality.value ? 'backdrop-blur-sm' : '']\n\n if(isLowQuality.value && botMode.value === 'self') {\n out.push('from-black/80 via-black/60 to-black/80')\n }\n else if (botMode.value === 'self') {\n out.push('from-black/70 via-black/50 to-black/80')\n }\n else {\n out.push('from-black/90 via-black/90 to-black/100')\n }\n\n return out.join(' ')\n})\n\n// Icon preset mapping\nconst ICON_MAP: Record<ButtonIconPreset, string> = {\n phone: 'i-heroicons-phone',\n calendar: 'i-heroicons-calendar',\n question: 'i-heroicons-question-mark-circle',\n message: 'i-heroicons-chat-bubble-left-right',\n sparkles: 'i-heroicons-sparkles',\n}\n\n// Resolve button text with template variables\nconst resolvedButtonText = computed(() => {\n return parseButtonTemplate({\n template: buttonText || 'Talk to {name}',\n bot: bot.toData(),\n })\n})\n\n// Resolve button icon from preset or default to phone\nconst resolvedButtonIcon = computed(() => {\n return ICON_MAP[buttonIcon || 'phone'] || ICON_MAP.phone\n})\n</script>\n\n<template>\n <div\n ref=\"rootElement\"\n :key=\"bot.avatarUrl.value\"\n class=\"pagelines-sdk @container/bot pagelines-bot w-full h-full overflow-hidden relative\"\n data-test=\"bot-chat\"\n >\n <div v-if=\"loading\" class=\"absolute inset-0 flex items-center justify-center bg-gradient-to-br from-theme-800 to-theme-950 rounded-3xl z-10\">\n <FSpinner class=\"text-white size-8\" />\n </div>\n\n <!-- bare: no background at any layer — the host page owns the canvas\n (the app's chat surface is white); any paint here shows as a\n stripe against the host canvas. -->\n <div\n v-else-if=\"bot && !initError\"\n class=\"absolute inset-0\"\n :class=\"bare ? '' : 'bg-cover bg-center bg-no-repeat'\"\n :style=\"bare ? undefined : { backgroundImage: `url(${bot.avatarUrl.value})` }\"\n :data-quality=\"bot.avatar.value?.quality || 'none'\"\n >\n <div\n v-if=\"!bare\"\n class=\"absolute inset-0 bg-gradient-to-br z-0\"\n :class=\"backdropClass\"\n />\n <div\n class=\"relative z-10 flex flex-col h-full transition-all duration-500 ease-[cubic-bezier(0.25,1,0.33,1)] will-change-transform\"\n :class=\"isActive ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-2'\"\n >\n <div v-if=\"!bare || hasClose\" class=\"relative z-30 p-2\" :class=\"!bare && botMode !== 'self' ? 'backdrop-blur-lg' : ''\">\n <!-- A bare chat embed supplies its own surrounding header. -->\n <div v-if=\"chatOnly\" class=\"flex items-center\" :class=\"bare ? 'justify-end' : ''\">\n <div v-if=\"!bare\" class=\"flex flex-1 items-center gap-3 pl-2\">\n <img\n :src=\"bot.avatarUrl.value\"\n :alt=\"bot.displayName.value\"\n class=\"size-8 rounded-full object-cover\"\n />\n <span class=\"text-sm font-medium text-white/90\">{{ bot.displayName.value }}</span>\n </div>\n <div v-if=\"hasClose\" class=\"flex justify-end\">\n <button\n class=\"flex cursor-pointer items-center rounded-2xl p-3 transition-colors\"\n :class=\"bare ? 'text-theme-500 hover:bg-theme-50' : 'text-white/70 hover:bg-white/10'\"\n @click.stop=\"emit('close', 'button')\"\n >\n <i class=\"size-6 i-tabler-x\" />\n </button>\n </div>\n </div>\n\n <!-- Full header with mode selector and sidebars -->\n <div v-else class=\"flex items-center\" :class=\"hasClose ? '' : 'justify-between'\">\n <!-- Left side: Sidebar toggle with user avatar -->\n <div :class=\"hasClose ? 'flex-1 basis-0' : ''\">\n <button\n class=\"cursor-pointer p-2 flex items-center gap-2 rounded-2xl text-white/70 hover:bg-white/10 transition-all duration-300 ease-[cubic-bezier(0.25,1,0.33,1)] hover:scale-105 active:scale-95\"\n @click=\"isSidebarOpen = true\"\n >\n <i class=\"i-tabler-menu size-7\" />\n </button>\n </div>\n\n <!-- Center: Mode selector button (centered when hasClose=true) -->\n <button\n class=\"flex items-center gap-2 px-3.5 py-3 rounded-2xl text-white/90 hover:bg-white/10 transition-all cursor-pointer flex-grow-0\"\n :class=\"{ 'bg-white/10': isModeSidebarOpen }\"\n @click=\"isModeSidebarOpen = true\"\n >\n <i :class=\"currentMode?.icon\" class=\"size-4 opacity-60\" />\n <span class=\"text-sm\">{{ currentMode?.label }}</span>\n <i class=\"i-tabler-chevron-down size-4\" />\n </button>\n\n <!-- Right side: Close button (only in widget mode) -->\n <div v-if=\"hasClose\" class=\"flex-1 basis-0 flex justify-end\">\n <button\n class=\"cursor-pointer flex items-center p-3 rounded-2xl text-white/70 hover:bg-white/10 transition-colors\"\n @click.stop=\"emit('close', 'button')\"\n >\n <i class=\"size-6 i-tabler-x\" />\n </button>\n </div>\n </div>\n </div>\n\n <!-- chatOnly: skip all modes, show chat directly -->\n <!-- bare: the host page owns the canvas (the app's chat surface is\n white); a mismatched paint here reads as a stripe against it. -->\n <div\n v-if=\"chatOnly\"\n class=\"relative z-20 flex min-h-0 w-full flex-1 flex-col\"\n :class=\"bare ? '' : 'px-4'\"\n >\n <div class=\"min-h-0 w-full flex-1\" :class=\"bare ? '' : 'mx-auto max-w-md'\">\n <ElBotChat\n :chat-controller=\"chatController\"\n :bot=\"bot\"\n :scope=\"isAuthenticated ? 'private' : 'public'\"\n :empty-state-message=\"emptyStateMessage\"\n :variant=\"bare ? 'light' : 'dark'\"\n :show-header=\"!bare\"\n :centered=\"bare\"\n >\n <template v-if=\"$slots['empty-heading']\" #empty-heading=\"headingProps\">\n <slot name=\"empty-heading\" v-bind=\"headingProps\" />\n </template>\n </ElBotChat>\n </div>\n </div>\n\n <!-- Full bot interface modes -->\n <template v-else>\n <div\n v-if=\"botMode === 'self'\"\n class=\"h-full pb-12 flex-1 flex flex-col relative z-20 min-h-0 px-4 @[480px]/bot:px-6 max-w-md mx-auto w-full\"\n >\n <!-- Top spacer -->\n <div class=\"flex-1 basis-0 mb-12\" />\n\n <!-- Avatar header -->\n <ElBotHeader :bot=\"bot\" :is-online=\"isOnline\" />\n\n <!-- Bottom section with button and social links -->\n <div class=\"flex-1 basis-0 flex flex-col justify-start pt-8 gap-7\">\n <ElBotButton\n theme=\"primary\"\n size=\"lg\"\n class=\"w-full\"\n :icon=\"resolvedButtonIcon\"\n data-test=\"voice-button\"\n @click=\"chatController?.setMode('talk')\"\n >\n {{ resolvedButtonText }}\n </ElBotButton>\n\n <!-- Social icon links -->\n <div v-if=\"bot.accounts.value && bot.accounts.value.length > 0\" class=\"flex items-center justify-center gap-3\">\n <a\n v-for=\"account in (bot.accounts.value || []).filter(a => SOCIAL_PLATFORMS[a.platform])\"\n :key=\"`${account.platform}-${account.handle}`\"\n :href=\"SOCIAL_PLATFORMS[account.platform].getUrl(account.handle)\"\n target=\"_blank\"\n class=\"size-12 rounded-full text-white/60 hover:text-white hover:bg-white/5 border border-white/0 hover:border-white/10 flex items-center justify-center transition-all duration-200 hover:scale-105\"\n >\n <i :class=\"SOCIAL_PLATFORMS[account.platform].icon\" class=\"size-5 \" />\n </a>\n </div>\n </div>\n </div>\n <div\n v-else-if=\"botMode === 'talk'\"\n class=\"flex-1 flex flex-col relative z-20 min-h-0 w-full gap-4 px-4\"\n >\n <ElAuthGate v-if=\"requireAuth && !isAuthenticated\" :sdk=\"sdk\" />\n <template v-else>\n <!-- Sticky header with backdrop blur - full width -->\n <div>\n <div class=\"max-w-md mx-auto\">\n <ElModeHeader :bot=\"bot\" :is-online=\"isOnline\" />\n </div>\n </div>\n <ElBotChat\n :chat-controller=\"chatController\"\n :bot=\"bot\"\n />\n </template>\n </div>\n <div\n v-else\n class=\"flex-1 flex flex-col relative z-20 min-h-0 w-full px-4 @[480px]/bot:px-6\"\n >\n <div class=\"flex-1 min-h-0 max-w-md mx-auto w-full\">\n <template v-if=\"botMode === 'chat'\">\n <ElAuthGate v-if=\"requireAuth && !isAuthenticated\" :sdk=\"sdk\" />\n <ElBotChat\n v-else\n :chat-controller=\"chatController\"\n :bot=\"bot\"\n show-header\n />\n </template>\n <ElBotAbout\n v-else-if=\"botMode === 'info'\"\n :bot=\"bot\"\n :is-online=\"isOnline\"\n />\n </div>\n </div>\n </template>\n\n </div>\n </div>\n <div v-else-if=\"initError\" class=\"bg-gradient-to-br from-theme-800 to-theme-950 text-white flex items-center justify-center h-full p-8\">\n <div class=\"text-center max-w-md space-y-4\">\n <div class=\"flex justify-center\">\n <div class=\"rounded-full bg-red-500/20 flex items-center justify-center size-10\">\n <i class=\"i-tabler-alert-circle size-6 text-red-400\" />\n </div>\n </div>\n <h3 class=\"text-lg font-medium\">\n Bot Error\n </h3>\n <p class=\"text-sm text-white/70 leading-relaxed\">\n {{ initError }}\n </p>\n </div>\n </div>\n <div v-else class=\"bg-white/10 backdrop-blur-sm text-white/70 flex items-center justify-center h-full\">\n Couldn't load your assistant. Please try again later.\n </div>\n\n <!-- Bot Sidebar (left) — hidden in chatOnly mode -->\n <ElBotSidebar\n v-if=\"!chatOnly\"\n v-model=\"isSidebarOpen\"\n :bot=\"bot\"\n :sdk=\"sdk\"\n :title=\"bot.displayName.value\"\n data-test=\"bot-sidebar\"\n />\n\n <!-- Mode Sidebar (right) — hidden in chatOnly mode -->\n <ElBotModeSidebar\n v-if=\"!chatOnly\"\n v-model=\"isModeSidebarOpen\"\n :chat-controller=\"chatController\"\n data-test=\"bot-mode-sidebar\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { ButtonIconPreset } from '../../widget/PLWidget'\nimport type { Bot } from '../schema'\nimport BotChat from './BotChat.vue'\nimport BotWrap from './BotWrap.vue'\n\nconst props = defineProps<{\n sdk?: PageLinesSDK\n bot?: Bot\n handle?: string\n context?: string\n clientContext?: string\n firstMessage?: string\n buttonText?: string\n buttonIcon?: ButtonIconPreset\n hasClose?: boolean\n chatOnly?: boolean\n bare?: boolean\n apiBase?: string\n emptyStateMessage?: string\n}>()\n\ndefineSlots<{\n 'empty-heading': (props: { bot: Bot, isLight: boolean }) => any\n}>()\n\nconst emit = defineEmits<{\n close: [value: string]\n error: [message: string]\n turnStarted: []\n turnCompleted: [conversationId: string]\n}>()\n\n// Template contract: slotProps.xxx = data resolved by BotWrap (sdk, bot,\n// context, firstMessage); props.xxx = rendering config passed through\n// unchanged (buttonText, buttonIcon, hasClose, chatOnly).\n</script>\n\n<template>\n <BotWrap\n v-slot=\"slotProps\"\n v-bind=\"props\"\n class=\"bot-provider size-full relative\"\n >\n <BotChat\n :sdk=\"slotProps.sdk\"\n :bot=\"slotProps.bot\"\n :context=\"slotProps.context\"\n :first-message=\"slotProps.firstMessage\"\n :button-text=\"props.buttonText\"\n :button-icon=\"props.buttonIcon\"\n :has-close=\"props.hasClose\"\n :chat-only=\"props.chatOnly\"\n :bare=\"props.bare\"\n :empty-state-message=\"props.emptyStateMessage\"\n :is-active=\"true\"\n class=\"size-full\"\n @close=\"emit('close', $event)\"\n @error=\"emit('error', $event)\"\n @turn-started=\"emit('turnStarted')\"\n @turn-completed=\"emit('turnCompleted', $event)\"\n >\n <template v-if=\"$slots['empty-heading']\" #empty-heading=\"headingProps\">\n <slot name=\"empty-heading\" v-bind=\"headingProps\" />\n </template>\n </BotChat>\n </BotWrap>\n</template>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { ButtonIconPreset } from '../../widget/PLWidget'\nimport type { Bot } from '../schema'\nimport BotChat from './BotChat.vue'\nimport BotWrap from './BotWrap.vue'\n\nconst props = defineProps<{\n sdk?: PageLinesSDK\n bot?: Bot\n handle?: string\n context?: string\n clientContext?: string\n firstMessage?: string\n buttonText?: string\n buttonIcon?: ButtonIconPreset\n hasClose?: boolean\n chatOnly?: boolean\n bare?: boolean\n apiBase?: string\n emptyStateMessage?: string\n}>()\n\ndefineSlots<{\n 'empty-heading': (props: { bot: Bot, isLight: boolean }) => any\n}>()\n\nconst emit = defineEmits<{\n close: [value: string]\n error: [message: string]\n turnStarted: []\n turnCompleted: [conversationId: string]\n}>()\n\n// Template contract: slotProps.xxx = data resolved by BotWrap (sdk, bot,\n// context, firstMessage); props.xxx = rendering config passed through\n// unchanged (buttonText, buttonIcon, hasClose, chatOnly).\n</script>\n\n<template>\n <BotWrap\n v-slot=\"slotProps\"\n v-bind=\"props\"\n class=\"bot-provider size-full relative\"\n >\n <BotChat\n :sdk=\"slotProps.sdk\"\n :bot=\"slotProps.bot\"\n :context=\"slotProps.context\"\n :first-message=\"slotProps.firstMessage\"\n :button-text=\"props.buttonText\"\n :button-icon=\"props.buttonIcon\"\n :has-close=\"props.hasClose\"\n :chat-only=\"props.chatOnly\"\n :bare=\"props.bare\"\n :empty-state-message=\"props.emptyStateMessage\"\n :is-active=\"true\"\n class=\"size-full\"\n @close=\"emit('close', $event)\"\n @error=\"emit('error', $event)\"\n @turn-started=\"emit('turnStarted')\"\n @turn-completed=\"emit('turnCompleted', $event)\"\n >\n <template v-if=\"$slots['empty-heading']\" #empty-heading=\"headingProps\">\n <slot name=\"empty-heading\" v-bind=\"headingProps\" />\n </template>\n </BotChat>\n </BotWrap>\n</template>\n"],"mappings":"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"}
@@ -1,15 +1,15 @@
1
1
  import "./rolldown-runtime.js";
2
- import { t as e } from "./AgentProvider.js";
2
+ import { t as e } from "./BotProvider.js";
3
3
  import { t } from "./useWidgetState.js";
4
4
  import { createBlock as n, defineComponent as r, openBlock as i, unref as a } from "vue";
5
5
  //#endregion
6
- //#region widget/ui/AgentWidgetInline.vue
6
+ //#region widget/ui/BotWidgetInline.vue
7
7
  var o = /* @__PURE__ */ r({
8
- __name: "AgentWidgetInline",
8
+ __name: "BotWidgetInline",
9
9
  props: {
10
10
  sdk: {},
11
11
  handle: {},
12
- agent: {},
12
+ bot: {},
13
13
  context: {},
14
14
  firstMessage: {},
15
15
  buttonText: {},
@@ -17,11 +17,11 @@ var o = /* @__PURE__ */ r({
17
17
  chatOnly: { type: Boolean }
18
18
  },
19
19
  setup(r, { expose: o }) {
20
- let { currentAgent: s, currentContext: c, currentFirstMessage: l, currentButtonText: u, currentButtonIcon: d, update: f } = t(r);
20
+ let { currentBot: s, currentContext: c, currentFirstMessage: l, currentButtonText: u, currentButtonIcon: d, update: f } = t(r);
21
21
  return o({ update: f }), (t, o) => (i(), n(e, {
22
22
  sdk: r.sdk,
23
23
  handle: r.handle,
24
- agent: a(s),
24
+ bot: a(s),
25
25
  context: a(c),
26
26
  "first-message": a(l),
27
27
  "button-text": a(u),
@@ -30,7 +30,7 @@ var o = /* @__PURE__ */ r({
30
30
  }, null, 8, [
31
31
  "sdk",
32
32
  "handle",
33
- "agent",
33
+ "bot",
34
34
  "context",
35
35
  "first-message",
36
36
  "button-text",
@@ -42,4 +42,4 @@ var o = /* @__PURE__ */ r({
42
42
  //#endregion
43
43
  export { o as default };
44
44
 
45
- //# sourceMappingURL=AgentWidgetInline.js.map
45
+ //# sourceMappingURL=BotWidgetInline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BotWidgetInline.js","names":[],"sources":["../widget/ui/BotWidgetInline.vue","../widget/ui/BotWidgetInline.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { Bot } from '../../bot/schema'\nimport type { ButtonIconPreset } from '../PLWidget'\nimport BotProvider from '../../bot/ui/BotProvider.vue'\nimport { useWidgetState } from '../composables/useWidgetState'\n\nconst props = defineProps<{\n sdk?: PageLinesSDK\n handle?: string\n bot?: Bot\n context?: string\n firstMessage?: string\n buttonText?: string\n buttonIcon?: ButtonIconPreset\n chatOnly?: boolean\n}>()\n\nconst { currentBot, currentContext, currentFirstMessage, currentButtonText, currentButtonIcon, update } = useWidgetState(props)\n\ndefineExpose({ update })\n</script>\n\n<template>\n <BotProvider\n :sdk=\"sdk\"\n :handle=\"handle\"\n :bot=\"currentBot\"\n :context=\"currentContext\"\n :first-message=\"currentFirstMessage\"\n :button-text=\"currentButtonText\"\n :button-icon=\"currentButtonIcon\"\n :chat-only=\"chatOnly\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { Bot } from '../../bot/schema'\nimport type { ButtonIconPreset } from '../PLWidget'\nimport BotProvider from '../../bot/ui/BotProvider.vue'\nimport { useWidgetState } from '../composables/useWidgetState'\n\nconst props = defineProps<{\n sdk?: PageLinesSDK\n handle?: string\n bot?: Bot\n context?: string\n firstMessage?: string\n buttonText?: string\n buttonIcon?: ButtonIconPreset\n chatOnly?: boolean\n}>()\n\nconst { currentBot, currentContext, currentFirstMessage, currentButtonText, currentButtonIcon, update } = useWidgetState(props)\n\ndefineExpose({ update })\n</script>\n\n<template>\n <BotProvider\n :sdk=\"sdk\"\n :handle=\"handle\"\n :bot=\"currentBot\"\n :context=\"currentContext\"\n :first-message=\"currentFirstMessage\"\n :button-text=\"currentButtonText\"\n :button-icon=\"currentButtonIcon\"\n :chat-only=\"chatOnly\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAkBA,IAAM,EAAE,eAAY,mBAAgB,wBAAqB,sBAAmB,sBAAmB,cAAW,EAAe,CAAK;SAE9H,EAAa,EAAE,UAAO,CAAC,mBAIrB,EASE,GAAA;GARC,KAAK,EAAA;GACL,QAAQ,EAAA;GACR,KAAK,EAAA,CAAA;GACL,SAAS,EAAA,CAAA;GACT,iBAAe,EAAA,CAAA;GACf,eAAa,EAAA,CAAA;GACb,eAAa,EAAA,CAAA;GACb,aAAW,EAAA"}
@@ -1,5 +1,5 @@
1
1
  import "./rolldown-runtime.js";
2
- import { t as e } from "./AgentProvider.js";
2
+ import { t as e } from "./BotProvider.js";
3
3
  import { t } from "./useWidgetState.js";
4
4
  import { Teleport as n, Transition as r, computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, createVNode as l, defineComponent as u, guardReactiveProps as d, nextTick as f, normalizeClass as p, normalizeProps as m, onMounted as h, onUnmounted as g, openBlock as _, ref as v, renderSlot as y, toDisplayString as b, unref as x, watch as S, withCtx as C, withModifiers as w } from "vue";
5
5
  //#region ui/FClose.vue?vue&type=script&setup=true&lang.ts
@@ -161,11 +161,11 @@ var T = ["aria-label"], E = { class: "absolute top-1/2 left-1/2 -translate-x-1/2
161
161
  }, 16)])])], 2)], 8, ["to", "disabled"])) : o("", !0);
162
162
  }
163
163
  }), M = /* @__PURE__ */ u({
164
- __name: "AgentWidgetModal",
164
+ __name: "BotWidgetModal",
165
165
  props: {
166
166
  sdk: {},
167
167
  handle: {},
168
- agent: {},
168
+ bot: {},
169
169
  context: {},
170
170
  firstMessage: {},
171
171
  buttonText: {},
@@ -174,7 +174,7 @@ var T = ["aria-label"], E = { class: "absolute top-1/2 left-1/2 -translate-x-1/2
174
174
  onClose: { type: Function }
175
175
  },
176
176
  setup(n, { expose: r }) {
177
- let i = n, { currentAgent: o, currentContext: s, currentFirstMessage: c, currentButtonText: u, currentButtonIcon: d, update: p } = t(i), m = v(!1);
177
+ let i = n, { currentBot: o, currentContext: s, currentFirstMessage: c, currentButtonText: u, currentButtonIcon: d, update: p } = t(i), m = v(!1);
178
178
  h(async () => {
179
179
  await f(), setTimeout(() => {
180
180
  m.value = !0;
@@ -203,7 +203,7 @@ var T = ["aria-label"], E = { class: "absolute top-1/2 left-1/2 -translate-x-1/2
203
203
  default: C(() => [l(e, {
204
204
  sdk: n.sdk,
205
205
  handle: n.handle,
206
- agent: x(o),
206
+ bot: x(o),
207
207
  context: x(s),
208
208
  "first-message": x(c),
209
209
  "button-text": x(u),
@@ -214,7 +214,7 @@ var T = ["aria-label"], E = { class: "absolute top-1/2 left-1/2 -translate-x-1/2
214
214
  }, null, 8, [
215
215
  "sdk",
216
216
  "handle",
217
- "agent",
217
+ "bot",
218
218
  "context",
219
219
  "first-message",
220
220
  "button-text",
@@ -228,4 +228,4 @@ var T = ["aria-label"], E = { class: "absolute top-1/2 left-1/2 -translate-x-1/2
228
228
  //#endregion
229
229
  export { M as default };
230
230
 
231
- //# sourceMappingURL=AgentWidgetModal.js.map
231
+ //# sourceMappingURL=BotWidgetModal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BotWidgetModal.js","names":["$emit","$slots"],"sources":["../ui/FClose.vue","../ui/FClose.vue","../ui/FModal.vue","../ui/FModal.vue","../widget/ui/BotWidgetModal.vue","../widget/ui/BotWidgetModal.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n// SDK-local copy of src/ui/common/FClose.vue — the SDK package must not\n// import app source, so the primitives it needs live here.\nimport { onMounted, ref } from 'vue'\n\ndefineOptions({ name: 'FClose' })\n\ndefineProps<{\n ariaLabel?: string\n}>()\n\ndefineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst inView = ref(false)\n\nonMounted(() => {\n setTimeout(() => {\n inView.value = true\n }, 100)\n})\n</script>\n\n<template>\n <button\n type=\"button\"\n :aria-label=\"ariaLabel || 'Close'\"\n class=\"close block cursor-pointer w-[60px] h-[60px] rounded-full transition-all duration-1000 ease-[cubic-bezier(0.25,1,0.33,1)] hover:scale-110 active:scale-90 hover:rotate-90\"\n @click=\"$emit('click', $event)\"\n >\n <!-- Background circle (invisible, for hover area) -->\n <span class=\"absolute inset-0 rounded-full transition-all\" />\n\n <!-- Close lines container -->\n <span class=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[28px] h-[28px] overflow-hidden\">\n <!-- Line 1 - animates from bottom-left to center, rotates 45deg -->\n <span\n class=\"absolute h-full w-[3px] rounded-[5px] left-[13px] transition-all duration-[400ms] ease-[cubic-bezier(0.52,0.01,0.16,1)]\"\n :class=\"inView ? 'translate-y-0 translate-x-0 rotate-45' : 'translate-y-[30px] -translate-x-[30px] rotate-0'\"\n style=\"background-color: currentColor; transition-delay: 0.15s\"\n />\n\n <!-- Line 2 - animates from top-left to center, rotates -45deg -->\n <span\n class=\"absolute h-full w-[3px] rounded-[5px] left-[13px] transition-all duration-[400ms] ease-[cubic-bezier(0.52,0.01,0.16,1)]\"\n :class=\"inView ? 'translate-y-0 translate-x-0 -rotate-45' : '-translate-y-[30px] -translate-x-[30px] rotate-0'\"\n style=\"background-color: currentColor; transition-delay: 0.45s\"\n />\n </span>\n </button>\n</template>\n","<script lang=\"ts\" setup>\n// SDK-local copy of src/ui/common/FClose.vue — the SDK package must not\n// import app source, so the primitives it needs live here.\nimport { onMounted, ref } from 'vue'\n\ndefineOptions({ name: 'FClose' })\n\ndefineProps<{\n ariaLabel?: string\n}>()\n\ndefineEmits<{\n click: [event: MouseEvent]\n}>()\n\nconst inView = ref(false)\n\nonMounted(() => {\n setTimeout(() => {\n inView.value = true\n }, 100)\n})\n</script>\n\n<template>\n <button\n type=\"button\"\n :aria-label=\"ariaLabel || 'Close'\"\n class=\"close block cursor-pointer w-[60px] h-[60px] rounded-full transition-all duration-1000 ease-[cubic-bezier(0.25,1,0.33,1)] hover:scale-110 active:scale-90 hover:rotate-90\"\n @click=\"$emit('click', $event)\"\n >\n <!-- Background circle (invisible, for hover area) -->\n <span class=\"absolute inset-0 rounded-full transition-all\" />\n\n <!-- Close lines container -->\n <span class=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[28px] h-[28px] overflow-hidden\">\n <!-- Line 1 - animates from bottom-left to center, rotates 45deg -->\n <span\n class=\"absolute h-full w-[3px] rounded-[5px] left-[13px] transition-all duration-[400ms] ease-[cubic-bezier(0.52,0.01,0.16,1)]\"\n :class=\"inView ? 'translate-y-0 translate-x-0 rotate-45' : 'translate-y-[30px] -translate-x-[30px] rotate-0'\"\n style=\"background-color: currentColor; transition-delay: 0.15s\"\n />\n\n <!-- Line 2 - animates from top-left to center, rotates -45deg -->\n <span\n class=\"absolute h-full w-[3px] rounded-[5px] left-[13px] transition-all duration-[400ms] ease-[cubic-bezier(0.52,0.01,0.16,1)]\"\n :class=\"inView ? 'translate-y-0 translate-x-0 -rotate-45' : '-translate-y-[30px] -translate-x-[30px] rotate-0'\"\n style=\"background-color: currentColor; transition-delay: 0.45s\"\n />\n </span>\n </button>\n</template>\n","<script lang=\"ts\" setup>\n// SDK-local copy of src/ui/common/FModal.vue — the SDK package must not\n// import app source, so the primitives it needs live here.\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\nimport FClose from './FClose.vue'\n\ndefineOptions({ name: 'FModal' })\n\nconst {\n vis = false,\n modalClass,\n styleClass,\n fullScreen = false,\n hasClose = false,\n title = '',\n transitionMode = 'modal',\n teleportTo = 'body',\n disableTeleport = false,\n} = defineProps<{\n vis?: boolean\n modalClass?: string\n styleClass?: string\n fullScreen?: boolean\n hasClose?: boolean\n title?: string\n transitionMode?: 'modal' | 'slideUp'\n teleportTo?: string | Element\n disableTeleport?: boolean\n}>()\n\nconst emit = defineEmits<{\n 'update:vis': [value: boolean]\n 'close': [value: boolean]\n 'escape': [value: boolean]\n}>()\n\nconst isMounted = ref(false)\n\nfunction close(args: { reason: 'escape' | 'reset' }): void {\n const { reason } = args\n emit('update:vis', false)\n emit('close', true)\n if (reason === 'escape')\n emit('escape', true)\n}\n\nconst classes = computed(() => {\n const cls = modalClass ? [modalClass] : ['max-w-screen-md p-24']\n const style = styleClass ? [styleClass] : ['bg-theme-0', 'shadow-xl']\n\n if (fullScreen)\n cls.push('fixed inset-0')\n else\n cls.push('rounded-2xl')\n\n return [\n 'relative',\n 'text-left',\n 'transform',\n 'transition-all',\n 'w-full',\n 'overflow-hidden',\n ...cls,\n ...style,\n ]\n})\n\nconst afterVisible = ref(false)\nconst cleanups: (() => void)[] = []\n\nfunction onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape' && vis)\n close({ reason: 'escape' })\n}\n\nonMounted(async () => {\n isMounted.value = true\n\n const unwatch = watch(\n () => vis,\n (vis) => {\n if (vis) {\n setTimeout(() => (afterVisible.value = true), 300)\n } else {\n afterVisible.value = false\n }\n },\n { immediate: true },\n )\n\n cleanups.push(unwatch)\n\n if (typeof document !== 'undefined') {\n document.addEventListener('keydown', onKeydown)\n cleanups.push(() => document.removeEventListener('keydown', onKeydown))\n }\n})\n\nonUnmounted(() => {\n cleanups.forEach((c) => c())\n})\n\nconst modalTransition = computed(() => {\n if (transitionMode === 'slideUp') {\n return {\n enterActiveClass: 'ease-[cubic-bezier(0.25,1,0.33,1)] duration-500',\n enterFromClass: 'opacity-0 translate-y-full scale-95',\n enterToClass: 'opacity-100 translate-y-0 scale-100',\n leaveActiveClass: 'ease-[cubic-bezier(0.25,1,0.33,1)] duration-500',\n leaveFromClass: 'opacity-100 translate-y-0 scale-100',\n leaveToClass: 'opacity-0 translate-y-full scale-95',\n }\n }\n return {\n enterActiveClass: 'ease-[cubic-bezier(0.25,1,0.33,1)] duration-500',\n enterFromClass: 'opacity-0 scale-75',\n enterToClass: 'opacity-100 translate-y-0 scale-100',\n leaveActiveClass: 'ease-[cubic-bezier(0.25,1,0.33,1)] duration-500',\n leaveFromClass: 'opacity-100 translate-y-0 scale-100',\n leaveToClass: 'opacity-0 scale-75',\n }\n})\n</script>\n\n<script lang=\"ts\">\nexport default {\n inheritAttrs: false,\n}\n</script>\n\n<template>\n <Teleport v-if=\"isMounted\" :to=\"teleportTo\" :disabled=\"disableTeleport\">\n <div\n class=\"fixed inset-0 z-50\"\n aria-labelledby=\"modal-title\"\n role=\"dialog\"\n aria-modal=\"true\"\n :class=\"!vis ? 'pointer-events-none' : ''\"\n >\n <Transition\n enter-active-class=\"ease-out duration-300\"\n enter-from-class=\"opacity-0\"\n enter-to-class=\"opacity-100\"\n leave-active-class=\"ease-in duration-200\"\n leave-from-class=\"opacity-100\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"vis\"\n class=\"fixed inset-0 bg-theme-800/60 active:bg-theme-800/80 cursor-pointer dark:bg-theme-600/90 backdrop-blur-sm transition-opacity\"\n @click=\"close({ reason: 'escape' })\"\n />\n </Transition>\n <div\n class=\"fixed inset-0 z-40 overflow-y-auto overscroll-contain no-scrollbar\"\n @click=\"close({ reason: 'escape' })\"\n >\n <!-- min-h-full, never h-full: a taller-than-viewport panel must grow this\n row so the outer layer scrolls; h-full + items-center centers the\n overflow and clips the modal top unreachably. p-4 = the 1em minimum\n viewport gap for tall modals. -->\n <div class=\"flex min-h-full items-center justify-center text-center p-4\">\n <Transition v-bind=\"modalTransition\">\n <div\n v-if=\"vis\"\n :class=\"classes\"\n class=\"w-full\"\n @click.stop\n >\n <div\n v-if=\"hasClose || title || $slots.actions\"\n :class=\"!title && (hasClose || $slots.actions) ? 'absolute top-0 right-0 z-10' : 'flex justify-between items-center'\"\n >\n <h2 v-if=\"title\" class=\"text-base p-4 font-semibold\">\n {{ title }}\n </h2>\n <div v-if=\"hasClose || $slots.actions\" class=\"flex items-center gap-2 px-2\">\n <slot name=\"actions\" />\n <FClose\n v-if=\"hasClose\"\n class=\"relative\"\n data-test-id=\"close-modal\"\n @click.stop=\"close({ reason: 'escape' })\"\n />\n </div>\n </div>\n <slot />\n </div>\n </Transition>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n","<script lang=\"ts\" setup>\n// SDK-local copy of src/ui/common/FModal.vue — the SDK package must not\n// import app source, so the primitives it needs live here.\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\nimport FClose from './FClose.vue'\n\ndefineOptions({ name: 'FModal' })\n\nconst {\n vis = false,\n modalClass,\n styleClass,\n fullScreen = false,\n hasClose = false,\n title = '',\n transitionMode = 'modal',\n teleportTo = 'body',\n disableTeleport = false,\n} = defineProps<{\n vis?: boolean\n modalClass?: string\n styleClass?: string\n fullScreen?: boolean\n hasClose?: boolean\n title?: string\n transitionMode?: 'modal' | 'slideUp'\n teleportTo?: string | Element\n disableTeleport?: boolean\n}>()\n\nconst emit = defineEmits<{\n 'update:vis': [value: boolean]\n 'close': [value: boolean]\n 'escape': [value: boolean]\n}>()\n\nconst isMounted = ref(false)\n\nfunction close(args: { reason: 'escape' | 'reset' }): void {\n const { reason } = args\n emit('update:vis', false)\n emit('close', true)\n if (reason === 'escape')\n emit('escape', true)\n}\n\nconst classes = computed(() => {\n const cls = modalClass ? [modalClass] : ['max-w-screen-md p-24']\n const style = styleClass ? [styleClass] : ['bg-theme-0', 'shadow-xl']\n\n if (fullScreen)\n cls.push('fixed inset-0')\n else\n cls.push('rounded-2xl')\n\n return [\n 'relative',\n 'text-left',\n 'transform',\n 'transition-all',\n 'w-full',\n 'overflow-hidden',\n ...cls,\n ...style,\n ]\n})\n\nconst afterVisible = ref(false)\nconst cleanups: (() => void)[] = []\n\nfunction onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape' && vis)\n close({ reason: 'escape' })\n}\n\nonMounted(async () => {\n isMounted.value = true\n\n const unwatch = watch(\n () => vis,\n (vis) => {\n if (vis) {\n setTimeout(() => (afterVisible.value = true), 300)\n } else {\n afterVisible.value = false\n }\n },\n { immediate: true },\n )\n\n cleanups.push(unwatch)\n\n if (typeof document !== 'undefined') {\n document.addEventListener('keydown', onKeydown)\n cleanups.push(() => document.removeEventListener('keydown', onKeydown))\n }\n})\n\nonUnmounted(() => {\n cleanups.forEach((c) => c())\n})\n\nconst modalTransition = computed(() => {\n if (transitionMode === 'slideUp') {\n return {\n enterActiveClass: 'ease-[cubic-bezier(0.25,1,0.33,1)] duration-500',\n enterFromClass: 'opacity-0 translate-y-full scale-95',\n enterToClass: 'opacity-100 translate-y-0 scale-100',\n leaveActiveClass: 'ease-[cubic-bezier(0.25,1,0.33,1)] duration-500',\n leaveFromClass: 'opacity-100 translate-y-0 scale-100',\n leaveToClass: 'opacity-0 translate-y-full scale-95',\n }\n }\n return {\n enterActiveClass: 'ease-[cubic-bezier(0.25,1,0.33,1)] duration-500',\n enterFromClass: 'opacity-0 scale-75',\n enterToClass: 'opacity-100 translate-y-0 scale-100',\n leaveActiveClass: 'ease-[cubic-bezier(0.25,1,0.33,1)] duration-500',\n leaveFromClass: 'opacity-100 translate-y-0 scale-100',\n leaveToClass: 'opacity-0 scale-75',\n }\n})\n</script>\n\n<script lang=\"ts\">\nexport default {\n inheritAttrs: false,\n}\n</script>\n\n<template>\n <Teleport v-if=\"isMounted\" :to=\"teleportTo\" :disabled=\"disableTeleport\">\n <div\n class=\"fixed inset-0 z-50\"\n aria-labelledby=\"modal-title\"\n role=\"dialog\"\n aria-modal=\"true\"\n :class=\"!vis ? 'pointer-events-none' : ''\"\n >\n <Transition\n enter-active-class=\"ease-out duration-300\"\n enter-from-class=\"opacity-0\"\n enter-to-class=\"opacity-100\"\n leave-active-class=\"ease-in duration-200\"\n leave-from-class=\"opacity-100\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"vis\"\n class=\"fixed inset-0 bg-theme-800/60 active:bg-theme-800/80 cursor-pointer dark:bg-theme-600/90 backdrop-blur-sm transition-opacity\"\n @click=\"close({ reason: 'escape' })\"\n />\n </Transition>\n <div\n class=\"fixed inset-0 z-40 overflow-y-auto overscroll-contain no-scrollbar\"\n @click=\"close({ reason: 'escape' })\"\n >\n <!-- min-h-full, never h-full: a taller-than-viewport panel must grow this\n row so the outer layer scrolls; h-full + items-center centers the\n overflow and clips the modal top unreachably. p-4 = the 1em minimum\n viewport gap for tall modals. -->\n <div class=\"flex min-h-full items-center justify-center text-center p-4\">\n <Transition v-bind=\"modalTransition\">\n <div\n v-if=\"vis\"\n :class=\"classes\"\n class=\"w-full\"\n @click.stop\n >\n <div\n v-if=\"hasClose || title || $slots.actions\"\n :class=\"!title && (hasClose || $slots.actions) ? 'absolute top-0 right-0 z-10' : 'flex justify-between items-center'\"\n >\n <h2 v-if=\"title\" class=\"text-base p-4 font-semibold\">\n {{ title }}\n </h2>\n <div v-if=\"hasClose || $slots.actions\" class=\"flex items-center gap-2 px-2\">\n <slot name=\"actions\" />\n <FClose\n v-if=\"hasClose\"\n class=\"relative\"\n data-test-id=\"close-modal\"\n @click.stop=\"close({ reason: 'escape' })\"\n />\n </div>\n </div>\n <slot />\n </div>\n </Transition>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { Bot } from '../../bot/schema'\nimport type { ButtonIconPreset } from '../PLWidget'\nimport { nextTick, onMounted, ref } from 'vue'\nimport FModal from '../../ui/FModal.vue'\nimport BotProvider from '../../bot/ui/BotProvider.vue'\nimport { useWidgetState } from '../composables/useWidgetState'\n\nconst props = defineProps<{\n sdk?: PageLinesSDK\n handle?: string\n bot?: Bot\n context?: string\n firstMessage?: string\n buttonText?: string\n buttonIcon?: ButtonIconPreset\n chatOnly?: boolean\n onClose?: () => void\n}>()\n\nconst { currentBot, currentContext, currentFirstMessage, currentButtonText, currentButtonIcon, update } = useWidgetState(props)\nconst isVisible = ref(false)\n\n// Trigger transition after mount\nonMounted(async () => {\n await nextTick()\n // Small delay to ensure DOM is ready and transition fires\n setTimeout(() => {\n isVisible.value = true\n }, 10)\n})\n\nfunction close() {\n isVisible.value = false\n // Wait for transition to complete before calling onClose\n setTimeout(() => {\n if (props.onClose) {\n props.onClose()\n }\n }, 300) // Match FModal transition duration\n}\n\nfunction open() {\n isVisible.value = true\n}\n\ndefineExpose({ update, close, open })\n</script>\n\n<template>\n <FModal\n :vis=\"isVisible\"\n :disable-teleport=\"true\"\n modal-class=\"max-w-4xl h-[80vh] md:h-[600px]\"\n :has-close=\"false\"\n @update:vis=\"isVisible = $event\"\n @close=\"close\"\n >\n <BotProvider\n :sdk=\"sdk\"\n :handle=\"handle\"\n :bot=\"currentBot\"\n :context=\"currentContext\"\n :first-message=\"currentFirstMessage\"\n :button-text=\"currentButtonText\"\n :button-icon=\"currentButtonIcon\"\n :chat-only=\"chatOnly\"\n :has-close=\"true\"\n @close=\"close\"\n />\n </FModal>\n</template>\n","<script setup lang=\"ts\">\nimport type { PageLinesSDK } from '../../sdkClient'\nimport type { Bot } from '../../bot/schema'\nimport type { ButtonIconPreset } from '../PLWidget'\nimport { nextTick, onMounted, ref } from 'vue'\nimport FModal from '../../ui/FModal.vue'\nimport BotProvider from '../../bot/ui/BotProvider.vue'\nimport { useWidgetState } from '../composables/useWidgetState'\n\nconst props = defineProps<{\n sdk?: PageLinesSDK\n handle?: string\n bot?: Bot\n context?: string\n firstMessage?: string\n buttonText?: string\n buttonIcon?: ButtonIconPreset\n chatOnly?: boolean\n onClose?: () => void\n}>()\n\nconst { currentBot, currentContext, currentFirstMessage, currentButtonText, currentButtonIcon, update } = useWidgetState(props)\nconst isVisible = ref(false)\n\n// Trigger transition after mount\nonMounted(async () => {\n await nextTick()\n // Small delay to ensure DOM is ready and transition fires\n setTimeout(() => {\n isVisible.value = true\n }, 10)\n})\n\nfunction close() {\n isVisible.value = false\n // Wait for transition to complete before calling onClose\n setTimeout(() => {\n if (props.onClose) {\n props.onClose()\n }\n }, 300) // Match FModal transition duration\n}\n\nfunction open() {\n isVisible.value = true\n}\n\ndefineExpose({ update, close, open })\n</script>\n\n<template>\n <FModal\n :vis=\"isVisible\"\n :disable-teleport=\"true\"\n modal-class=\"max-w-4xl h-[80vh] md:h-[600px]\"\n :has-close=\"false\"\n @update:vis=\"isVisible = $event\"\n @close=\"close\"\n >\n <BotProvider\n :sdk=\"sdk\"\n :handle=\"handle\"\n :bot=\"currentBot\"\n :context=\"currentContext\"\n :first-message=\"currentFirstMessage\"\n :button-text=\"currentButtonText\"\n :button-icon=\"currentButtonIcon\"\n :chat-only=\"chatOnly\"\n :has-close=\"true\"\n @close=\"close\"\n />\n </FModal>\n</template>\n"],"mappings":"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"}