@conversionpros/aiva 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -0
- package/auto-deploy.js +190 -0
- package/bin/aiva.js +81 -0
- package/cli-sync.js +126 -0
- package/d2a-prompt-template.txt +106 -0
- package/diagnostics-api.js +304 -0
- package/docs/ara-dedup-fix-scope.md +112 -0
- package/docs/ara-fix-round2-scope.md +61 -0
- package/docs/ara-greeting-fix-scope.md +70 -0
- package/docs/calendar-date-fix-scope.md +28 -0
- package/docs/getting-started.md +115 -0
- package/docs/network-architecture-rollout-scope.md +43 -0
- package/docs/scope-google-oauth-integration.md +351 -0
- package/docs/settings-page-scope.md +50 -0
- package/docs/xai-imagine-scope.md +116 -0
- package/docs/xai-voice-integration-scope.md +115 -0
- package/docs/xai-voice-tools-scope.md +165 -0
- package/email-router.js +512 -0
- package/follow-up-handler.js +606 -0
- package/gateway-monitor.js +158 -0
- package/google-email.js +379 -0
- package/google-oauth.js +310 -0
- package/grok-imagine.js +97 -0
- package/health-reporter.js +287 -0
- package/invisible-prefix-base.txt +206 -0
- package/invisible-prefix-owner.txt +26 -0
- package/invisible-prefix-slim.txt +10 -0
- package/invisible-prefix.txt +43 -0
- package/knowledge-base.js +472 -0
- package/lib/cli.js +19 -0
- package/lib/config.js +124 -0
- package/lib/health.js +57 -0
- package/lib/process.js +207 -0
- package/lib/server.js +42 -0
- package/lib/setup.js +472 -0
- package/meta-capi.js +206 -0
- package/meta-leads.js +411 -0
- package/notion-oauth.js +323 -0
- package/package.json +61 -0
- package/public/agent-config.html +241 -0
- package/public/aiva-avatar-anime.png +0 -0
- package/public/css/docs.css.bak +688 -0
- package/public/css/onboarding.css +543 -0
- package/public/diagrams/claude-subscription-pool.html +329 -0
- package/public/diagrams/claude-subscription-pool.png +0 -0
- package/public/docs-icon.png +0 -0
- package/public/escalation.html +237 -0
- package/public/group-config.html +300 -0
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/icons/agents.svg +1 -0
- package/public/icons/attach.svg +1 -0
- package/public/icons/characters.svg +1 -0
- package/public/icons/chat.svg +1 -0
- package/public/icons/docs.svg +1 -0
- package/public/icons/heartbeat.svg +1 -0
- package/public/icons/messages.svg +1 -0
- package/public/icons/mic.svg +1 -0
- package/public/icons/notes.svg +1 -0
- package/public/icons/settings.svg +1 -0
- package/public/icons/tasks.svg +1 -0
- package/public/images/onboarding/p0-communication-layer.png +0 -0
- package/public/images/onboarding/p0-infinite-surface.png +0 -0
- package/public/images/onboarding/p0-learning-model.png +0 -0
- package/public/images/onboarding/p0-meet-aiva.png +0 -0
- package/public/images/onboarding/p4-contact-intelligence.png +0 -0
- package/public/images/onboarding/p4-context-compounds.png +0 -0
- package/public/images/onboarding/p4-message-router.png +0 -0
- package/public/images/onboarding/p4-per-contact-rules.png +0 -0
- package/public/images/onboarding/p4-send-messages.png +0 -0
- package/public/images/onboarding/p6-be-precise.png +0 -0
- package/public/images/onboarding/p6-review-escalations.png +0 -0
- package/public/images/onboarding/p6-voice-input.png +0 -0
- package/public/images/onboarding/p7-completion.png +0 -0
- package/public/index.html +11594 -0
- package/public/js/onboarding.js +699 -0
- package/public/manifest.json +24 -0
- package/public/messages-v2.html +2824 -0
- package/public/permission-approve.html.bak +107 -0
- package/public/permissions.html +150 -0
- package/public/styles/design-system.css +68 -0
- package/router-db.js +604 -0
- package/router-utils.js +28 -0
- package/router-v2/adapters/imessage.js +191 -0
- package/router-v2/adapters/quo.js +82 -0
- package/router-v2/adapters/whatsapp.js +192 -0
- package/router-v2/contact-manager.js +234 -0
- package/router-v2/conversation-engine.js +498 -0
- package/router-v2/data/knowledge-base.json +176 -0
- package/router-v2/data/router-v2.db +0 -0
- package/router-v2/data/router-v2.db-shm +0 -0
- package/router-v2/data/router-v2.db-wal +0 -0
- package/router-v2/data/router.db +0 -0
- package/router-v2/db.js +457 -0
- package/router-v2/escalation-bridge.js +540 -0
- package/router-v2/follow-up-engine.js +347 -0
- package/router-v2/index.js +441 -0
- package/router-v2/ingestion.js +213 -0
- package/router-v2/knowledge-base.js +231 -0
- package/router-v2/lead-qualifier.js +152 -0
- package/router-v2/learning-loop.js +202 -0
- package/router-v2/outbound-sender.js +160 -0
- package/router-v2/package.json +13 -0
- package/router-v2/permission-gate.js +86 -0
- package/router-v2/playbook.js +177 -0
- package/router-v2/prompts/base.js +52 -0
- package/router-v2/prompts/first-contact.js +38 -0
- package/router-v2/prompts/lead-qualification.js +37 -0
- package/router-v2/prompts/scheduling.js +72 -0
- package/router-v2/prompts/style-overrides.js +22 -0
- package/router-v2/scheduler.js +301 -0
- package/router-v2/scripts/migrate-v1-to-v2.js +215 -0
- package/router-v2/scripts/seed-faq.js +67 -0
- package/router-v2/seed-knowledge-base.js +39 -0
- package/router-v2/utils/ai.js +129 -0
- package/router-v2/utils/phone.js +52 -0
- package/router-v2/utils/response-validator.js +98 -0
- package/router-v2/utils/sanitize.js +222 -0
- package/router.js +5005 -0
- package/routes/google-calendar.js +186 -0
- package/scripts/deploy.sh +62 -0
- package/scripts/macos-calendar.sh +232 -0
- package/scripts/onboard-device.sh +466 -0
- package/server.js +5131 -0
- package/start.sh +24 -0
- package/templates/AGENTS.md +548 -0
- package/templates/IDENTITY.md +15 -0
- package/templates/docs-agents.html +132 -0
- package/templates/docs-app.html +130 -0
- package/templates/docs-home.html +83 -0
- package/templates/docs-imessage.html +121 -0
- package/templates/docs-tasks.html +123 -0
- package/templates/docs-tips.html +175 -0
- package/templates/getting-started.html +809 -0
- package/templates/invisible-prefix-base.txt +171 -0
- package/templates/invisible-prefix-owner.txt +282 -0
- package/templates/invisible-prefix.txt +338 -0
- package/templates/manifest.json +61 -0
- package/templates/memory-org/clients.md +7 -0
- package/templates/memory-org/credentials.md +9 -0
- package/templates/memory-org/devices.md +7 -0
- package/templates/updates.html +464 -0
- package/templates/workspace/AGENTS.md.tmpl +161 -0
- package/templates/workspace/HEARTBEAT.md.tmpl +17 -0
- package/templates/workspace/IDENTITY.md.tmpl +15 -0
- package/templates/workspace/MEMORY.md.tmpl +16 -0
- package/templates/workspace/SOUL.md.tmpl +51 -0
- package/templates/workspace/USER.md.tmpl +25 -0
- package/tts-proxy.js +96 -0
- package/voice-call-local.js +731 -0
- package/voice-call.js +732 -0
- package/wa-listener.js +354 -0
|
@@ -0,0 +1,699 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIVA Onboarding Tutorial — v2 Revamp
|
|
3
|
+
* Premium copy, inline SVGs, deep messaging guide.
|
|
4
|
+
*/
|
|
5
|
+
(function() {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
// ── SVG Icon Library ──────────────────────────────────────────────────
|
|
9
|
+
const SVG = {
|
|
10
|
+
brain: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a5 5 0 0 1 4.9 4 4.5 4.5 0 0 1 2.1 4 4 4 0 0 1-1.5 7.5A4 4 0 0 1 12 22a4 4 0 0 1-5.5-4.5A4 4 0 0 1 5 10a4.5 4.5 0 0 1 2.1-4A5 5 0 0 1 12 2z"/><path d="M12 2v20"/><path d="M8 6c2 1 4 1 6 0"/><path d="M7 10.5c2.5 1 5.5 1 8 0"/><path d="M7.5 15c2.5 1 5 1 7.5 0"/></svg>`,
|
|
11
|
+
nodes: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="5" cy="6" r="2"/><circle cx="19" cy="6" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="5" cy="18" r="2"/><circle cx="19" cy="18" r="2"/><line x1="7" y1="6" x2="10" y2="12"/><line x1="14" y1="12" x2="17" y2="6"/><line x1="7" y1="18" x2="10" y2="12"/><line x1="14" y1="12" x2="17" y2="18"/></svg>`,
|
|
12
|
+
speechWaves: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M16 8v0"/><path d="M18 6v4"/><path d="M20 7v2"/></svg>`,
|
|
13
|
+
calendarClock: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/><circle cx="14" cy="16" r="3"/><path d="M14 14.5V16l1 1"/></svg>`,
|
|
14
|
+
gearLightning: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/><path d="M13 9l-2 3h3l-2 3"/></svg>`,
|
|
15
|
+
checkBubble: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><polyline points="9 11 11 13 15 9"/></svg>`,
|
|
16
|
+
envelopeNeural: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><polyline points="22 4 12 13 2 4"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><line x1="10" y1="12" x2="14" y2="12"/></svg>`,
|
|
17
|
+
brainArrows: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="10" r="5"/><path d="M12 5V3"/><path d="M8 7L5 4"/><path d="M16 7l3-3"/><path d="M6 19l3-4"/><path d="M18 19l-3-4"/><path d="M12 15v6"/></svg>`,
|
|
18
|
+
shieldRoute: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12h6m-3-3v6"/></svg>`,
|
|
19
|
+
dialSlider: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="8" x2="20" y2="8"/><line x1="4" y1="16" x2="20" y2="16"/><circle cx="10" cy="8" r="2"/><circle cx="16" cy="16" r="2"/></svg>`,
|
|
20
|
+
graphNeural: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 17 8 12 12 15 17 8 21 5"/><circle cx="21" cy="5" r="2"/><path d="M17 8c1 3 2 5 1 8"/></svg>`,
|
|
21
|
+
crosshair: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8"/><line x1="12" y1="2" x2="12" y2="6"/><line x1="12" y1="18" x2="12" y2="22"/><line x1="2" y1="12" x2="6" y2="12"/><line x1="18" y1="12" x2="22" y2="12"/><polyline points="10 12 11 13 14 10"/></svg>`,
|
|
22
|
+
waveform: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="8" x2="4" y2="16"/><line x1="8" y1="5" x2="8" y2="19"/><line x1="12" y1="3" x2="12" y2="21"/><line x1="16" y1="6" x2="16" y2="18"/><line x1="20" y1="9" x2="20" y2="15"/></svg>`,
|
|
23
|
+
bell: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/><circle cx="18" cy="4" r="2" fill="none" stroke="currentColor" stroke-width="1"/><circle cx="18" cy="4" r="4" fill="none" stroke="currentColor" stroke-width="0.5" opacity="0.4"/></svg>`,
|
|
24
|
+
xCircle: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>`,
|
|
25
|
+
checkCircle: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="9 12 11 14 16 9"/></svg>`,
|
|
26
|
+
terminal: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>`,
|
|
27
|
+
kanban: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="5" height="18" rx="1"/><rect x="10" y="3" width="5" height="12" rx="1"/><rect x="17" y="3" width="5" height="8" rx="1"/></svg>`,
|
|
28
|
+
envelope: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><polyline points="22 4 12 13 2 4"/><path d="M15 13l4 4M9 13l-4 4"/></svg>`,
|
|
29
|
+
gear: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>`,
|
|
30
|
+
checkAnimated: `<svg width="60" height="60" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10" stroke-dasharray="63" stroke-dashoffset="63" style="animation:svgDraw 0.6s ease forwards"/><polyline points="8 12 11 15 16 9" stroke-dasharray="20" stroke-dashoffset="20" style="animation:svgDraw 0.4s ease 0.6s forwards"/></svg>`,
|
|
31
|
+
mic: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="1" width="6" height="12" rx="3"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>`,
|
|
32
|
+
paperclip: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>`,
|
|
33
|
+
filter: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>`,
|
|
34
|
+
inbox: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>`,
|
|
35
|
+
settings: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.32 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>`,
|
|
36
|
+
key: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.78 7.78 5.5 5.5 0 0 1 7.78-7.78zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>`,
|
|
37
|
+
record: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>`,
|
|
38
|
+
// Messaging guide specific
|
|
39
|
+
router: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="8" width="20" height="8" rx="2"/><line x1="6" y1="12" x2="6" y2="12.01"/><line x1="10" y1="12" x2="10" y2="12.01"/><path d="M6 8V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v3"/><path d="M6 16v3M18 16v3"/></svg>`,
|
|
40
|
+
userRules: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/><path d="M18 8l2 2 4-4"/></svg>`,
|
|
41
|
+
contextBuild: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><line x1="8" y1="7" x2="16" y2="7"/><line x1="8" y1="11" x2="14" y2="11"/><line x1="8" y1="15" x2="12" y2="15"/></svg>`,
|
|
42
|
+
sendMsg: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>`,
|
|
43
|
+
userIntel: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M20 21v-2a4 4 0 0 0-3-3.87"/><path d="M4 21v-2a4 4 0 0 1 3-3.87"/><path d="M12 14c-3 0-5.5 1.5-6.5 4"/><circle cx="17" cy="17" r="3"/><path d="M17 15.5v1.5l1 1"/></svg>`,
|
|
44
|
+
notepad: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="13" y2="17"/></svg>`,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Helper: wrap SVG in icon container
|
|
48
|
+
function svgIcon(key, size) {
|
|
49
|
+
return `<span class="ob-svg-icon" style="display:inline-flex;align-items:center;justify-content:center;width:${size||20}px;height:${size||20}px;">${SVG[key] || SVG.brain}</span>`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Large icon for screens
|
|
53
|
+
function svgIconLarge(key) {
|
|
54
|
+
const raw = SVG[key] || SVG.brain;
|
|
55
|
+
return raw.replace(/width="20"/g, 'width="48"').replace(/height="20"/g, 'height="48"');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── Step Image Map ──────────────────────────────────────────────────
|
|
59
|
+
const STEP_IMAGES = {
|
|
60
|
+
'0-0': '/images/onboarding/p0-meet-aiva.png',
|
|
61
|
+
'0-1': '/images/onboarding/p0-infinite-surface.png',
|
|
62
|
+
'0-2': '/images/onboarding/p0-communication-layer.png',
|
|
63
|
+
'0-3': '/images/onboarding/p0-learning-model.png',
|
|
64
|
+
'4-0': '/images/onboarding/p4-message-router.png',
|
|
65
|
+
'4-1': '/images/onboarding/p4-per-contact-rules.png',
|
|
66
|
+
'4-2': '/images/onboarding/p4-context-compounds.png',
|
|
67
|
+
'4-3': '/images/onboarding/p4-send-messages.png',
|
|
68
|
+
'4-4': '/images/onboarding/p4-contact-intelligence.png',
|
|
69
|
+
'6-0': '/images/onboarding/p6-be-precise.png',
|
|
70
|
+
'6-1': '/images/onboarding/p6-voice-input.png',
|
|
71
|
+
'6-2': '/images/onboarding/p6-review-escalations.png',
|
|
72
|
+
'7-0': '/images/onboarding/p7-completion.png',
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
function animContainer(phaseIdx, stepIdx) {
|
|
76
|
+
const key = `${phaseIdx}-${stepIdx}`;
|
|
77
|
+
const src = STEP_IMAGES[key];
|
|
78
|
+
if (!src) return '';
|
|
79
|
+
return `<div class="onboarding-anim-container ob-anim-float"><img src="${src}" alt="" class="onboarding-step-image" style="width:200px;height:200px;object-fit:cover;border-radius:20px;box-shadow:0 8px 40px rgba(129,140,248,0.3);"/></div>`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Allow reset via URL parameter
|
|
83
|
+
if (new URLSearchParams(window.location.search).get('reset_tour') === '1' ||
|
|
84
|
+
new URLSearchParams(window.location.search).has('tour')) {
|
|
85
|
+
localStorage.removeItem('aiva_onboarding_completed');
|
|
86
|
+
const url = new URL(window.location);
|
|
87
|
+
url.searchParams.delete('reset_tour');
|
|
88
|
+
url.searchParams.delete('tour');
|
|
89
|
+
window.history.replaceState({}, '', url);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const STORAGE_KEY = 'aiva_onboarding_completed';
|
|
93
|
+
|
|
94
|
+
const PHASES = [
|
|
95
|
+
// ═══ Phase 0: Welcome (screens) ═══
|
|
96
|
+
{
|
|
97
|
+
name: 'Welcome',
|
|
98
|
+
type: 'screens',
|
|
99
|
+
steps: [
|
|
100
|
+
{
|
|
101
|
+
svgKey: 'brain', iconClass: 'purple',
|
|
102
|
+
title: 'Meet AIVA',
|
|
103
|
+
subtitle: 'You just got access to something most people don\'t have yet.',
|
|
104
|
+
detail: 'AIVA isn\'t a chatbot. She\'s an autonomous intelligence that takes real action — messaging contacts, managing your calendar, running your pipeline, designing assets, drafting contracts, and working while you sleep.'
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
svgKey: 'nodes', iconClass: 'pink',
|
|
108
|
+
title: 'One Brain. Infinite Surface Area.',
|
|
109
|
+
subtitle: 'AIVA connects to your tools, your contacts, your workflows — and acts on all of them.',
|
|
110
|
+
features: [
|
|
111
|
+
{ svgKey: 'speechWaves', text: '<strong>Communicate</strong> — Send messages across iMessage, WhatsApp, and Quo with full context of who you\'re talking to and why' },
|
|
112
|
+
{ svgKey: 'calendarClock', text: '<strong>Orchestrate</strong> — Schedule meetings, block focus time, and manage your calendar without lifting a finger' },
|
|
113
|
+
{ svgKey: 'gearLightning', text: '<strong>Execute</strong> — Run integrations, trigger workflows, and operate your business tools autonomously' },
|
|
114
|
+
{ svgKey: 'checkBubble', text: '<strong>Capture</strong> — Extract tasks, commitments, and follow-ups from every conversation automatically' }
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
svgKey: 'envelopeNeural', iconClass: 'blue',
|
|
119
|
+
title: 'Your Communication Layer',
|
|
120
|
+
subtitle: 'Every conversation AIVA handles gets smarter. Per-contact intelligence means she remembers context, adapts tone, and takes autonomous action — so the right message reaches the right person at the right time.',
|
|
121
|
+
features: [
|
|
122
|
+
{ svgKey: 'brainArrows', text: '<strong>Contextual Memory</strong> — AIVA recalls every prior exchange, relationship detail, and preference for each contact. No conversation starts from zero.' },
|
|
123
|
+
{ svgKey: 'shieldRoute', text: '<strong>Autonomous Action</strong> — She replies on your behalf with your voice, escalates what matters, and stays silent when that\'s the smarter move' },
|
|
124
|
+
{ svgKey: 'dialSlider', text: '<strong>Per-Contact Control</strong> — Set the behavior individually. Full autonomy for some contacts, human-in-the-loop for others. You decide the boundaries.' }
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
svgKey: 'graphNeural', iconClass: 'green',
|
|
129
|
+
title: 'The More You Use Her, The More She Knows',
|
|
130
|
+
subtitle: 'AIVA builds a living model of your world — your contacts, your preferences, your patterns, your voice.',
|
|
131
|
+
detail: 'This isn\'t keyword matching. It\'s accumulated intelligence. Every interaction refines her understanding of how you work, who matters to you, and what you\'d want done next.'
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
// ═══ Phase 1: Chat Tour (tooltips) ═══
|
|
136
|
+
{
|
|
137
|
+
name: 'Chat Tour',
|
|
138
|
+
type: 'tooltips',
|
|
139
|
+
steps: [
|
|
140
|
+
{
|
|
141
|
+
selector: '#chatInput',
|
|
142
|
+
title: 'Command Center',
|
|
143
|
+
text: 'This is where everything starts. Tell AIVA what you need — send a message, research a competitor, draft a contract, plan your week. She doesn\'t just answer questions. She executes.'
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
selector: '#micBtn',
|
|
147
|
+
title: 'Think Out Loud',
|
|
148
|
+
text: 'Hold to record. Speak naturally — complex instructions, stream-of-consciousness ideas, detailed briefs. AIVA processes your voice with full comprehension, not just transcription.'
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
selector: '.chat-btn.attach',
|
|
152
|
+
title: 'Drop Anything In',
|
|
153
|
+
text: 'Screenshots, documents, images, PDFs. AIVA reads, analyzes, and acts on whatever you share. Hand her a competitor\'s sales sheet and ask for a better one.'
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
// ═══ Phase 2: Tasks Tour (tooltips) ═══
|
|
158
|
+
{
|
|
159
|
+
name: 'Tasks Tour',
|
|
160
|
+
type: 'tooltips',
|
|
161
|
+
steps: [
|
|
162
|
+
{
|
|
163
|
+
selector: '.nav-item[onclick*="kanban"]',
|
|
164
|
+
title: 'Your Task Board',
|
|
165
|
+
text: 'AIVA doesn\'t just track what you tell her — she extracts commitments, deadlines, and action items from every conversation. They surface here automatically.',
|
|
166
|
+
position: 'top',
|
|
167
|
+
navigate: 'kanban'
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
selector: '.kanban-board',
|
|
171
|
+
title: 'Pipeline at a Glance',
|
|
172
|
+
text: 'Tasks are organized by status. Add tasks and AIVA executes them — moving cards through the pipeline as work progresses. From backlog to done, she handles the workflow.',
|
|
173
|
+
navigate: 'kanban'
|
|
174
|
+
},
|
|
175
|
+
// Multi-user dropdown step removed — single tenancy
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
// ═══ Phase 3: Notes Tour (tooltips) ═══
|
|
179
|
+
{
|
|
180
|
+
name: 'Notes Tour',
|
|
181
|
+
type: 'tooltips',
|
|
182
|
+
steps: [
|
|
183
|
+
{
|
|
184
|
+
selector: '.nav-item[onclick*="notes"]',
|
|
185
|
+
title: 'Voice-First Notes',
|
|
186
|
+
text: 'Capture ideas, meeting takeaways, and raw thinking by voice. AIVA transcribes, summarizes, and organizes — so your thoughts become searchable assets.',
|
|
187
|
+
position: 'top',
|
|
188
|
+
navigate: 'notes'
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
selector: '#notesRecordBtn',
|
|
192
|
+
title: 'Start Recording',
|
|
193
|
+
text: 'One tap. Speak freely. AIVA handles transcription, tagging, and summarization. Your words become structured, retrievable intelligence.',
|
|
194
|
+
navigate: 'notes'
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
selector: '#notesFilter',
|
|
198
|
+
title: 'Find Anything Fast',
|
|
199
|
+
text: 'Filter by type — voice memos, meeting notes, or everything. As your library grows, this keeps signal above noise.',
|
|
200
|
+
navigate: 'notes'
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
// ═══ Phase 4: Messages Tour (interactive guide) ═══
|
|
205
|
+
{
|
|
206
|
+
name: 'Messages Tour',
|
|
207
|
+
type: 'interactive-guide',
|
|
208
|
+
steps: [
|
|
209
|
+
{
|
|
210
|
+
svgKey: 'router', iconClass: 'blue',
|
|
211
|
+
title: 'The Message Router',
|
|
212
|
+
subtitle: 'This is where AIVA becomes your communication layer. Every inbound message flows through an intelligent router that decides: respond, escalate, or hold.',
|
|
213
|
+
detail: 'Think of it as a chief of staff for your inbox. AIVA reads every message, understands the context, and takes the right action — instantly.',
|
|
214
|
+
guideStep: 1, guideTotal: 5
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
svgKey: 'userRules', iconClass: 'purple',
|
|
218
|
+
title: 'Per-Contact Rules',
|
|
219
|
+
subtitle: 'Every contact gets their own behavior profile. You decide how AIVA handles each person.',
|
|
220
|
+
features: [
|
|
221
|
+
{ svgKey: 'shieldRoute', text: '<strong>Auto-Respond</strong> — AIVA replies using your voice and tone. The contact never knows.' },
|
|
222
|
+
{ svgKey: 'bell', text: '<strong>Escalate</strong> — AIVA flags the message for your personal attention with full context.' },
|
|
223
|
+
{ svgKey: 'dialSlider', text: '<strong>Monitor</strong> — AIVA watches silently. Tracks the conversation. Only intervenes if something triggers a rule.' }
|
|
224
|
+
],
|
|
225
|
+
detail: 'Set it once, adjust anytime. You\'re always in control of the boundaries.',
|
|
226
|
+
guideStep: 2, guideTotal: 5
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
svgKey: 'contextBuild', iconClass: 'green',
|
|
230
|
+
title: 'Context That Compounds',
|
|
231
|
+
subtitle: 'Every conversation makes AIVA sharper. She builds a living profile for each contact.',
|
|
232
|
+
features: [
|
|
233
|
+
{ svgKey: 'brainArrows', text: '<strong>Relationship history</strong> — who they are, what they care about, how they communicate' },
|
|
234
|
+
{ svgKey: 'calendarClock', text: '<strong>Timing patterns</strong> — when they reach out, response expectations, follow-up cadence' },
|
|
235
|
+
{ svgKey: 'checkBubble', text: '<strong>Commitments tracking</strong> — promises made, tasks referenced, deadlines mentioned' }
|
|
236
|
+
],
|
|
237
|
+
detail: 'After 10 conversations, AIVA knows that contact better than most CRMs ever will.',
|
|
238
|
+
guideStep: 3, guideTotal: 5
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
svgKey: 'sendMsg', iconClass: 'pink',
|
|
242
|
+
title: 'Send Messages Through AIVA',
|
|
243
|
+
subtitle: 'You don\'t have to leave the app. Tell AIVA who to message, what to say, and which channel — she handles delivery.',
|
|
244
|
+
features: [
|
|
245
|
+
{ svgKey: 'speechWaves', text: '<strong>Multi-channel</strong> — iMessage, WhatsApp, Quo. One command, any platform.' },
|
|
246
|
+
{ svgKey: 'crosshair', text: '<strong>Tone matching</strong> — AIVA adapts the message to match how you\'d actually say it' }
|
|
247
|
+
],
|
|
248
|
+
detail: 'Try: "Send Marcus a follow-up about the proposal. Keep it warm but direct. Use WhatsApp."',
|
|
249
|
+
guideStep: 4, guideTotal: 5
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
svgKey: 'userIntel', iconClass: 'blue',
|
|
253
|
+
title: 'Per-Contact Intelligence',
|
|
254
|
+
subtitle: 'Tap any contact to see what AIVA knows — conversation summaries, sentiment trends, pending action items, and recommended next steps.',
|
|
255
|
+
detail: 'This is your relationship intelligence layer. Every contact becomes a strategic profile, updated in real-time as conversations happen.',
|
|
256
|
+
guideStep: 5, guideTotal: 5
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
},
|
|
260
|
+
// ═══ Phase 5: Settings Tour (tooltips) ═══
|
|
261
|
+
{
|
|
262
|
+
name: 'Settings Tour',
|
|
263
|
+
type: 'tooltips',
|
|
264
|
+
steps: [
|
|
265
|
+
{
|
|
266
|
+
selector: '.nav-item[onclick*="settings"]',
|
|
267
|
+
title: 'Configuration',
|
|
268
|
+
text: 'Connect services, manage API tokens, and fine-tune how AIVA operates. This is the control plane behind the intelligence.',
|
|
269
|
+
position: 'top',
|
|
270
|
+
navigate: 'settings'
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
selector: '.settings-tab[onclick*="aiva-tokens"]',
|
|
274
|
+
title: 'Optional Superpowers',
|
|
275
|
+
text: 'AIVA is powerful out of the box. API keys unlock extra capabilities — image generation, voice synthesis, advanced AI models. Not required. Not scary. Just more power when you want it.',
|
|
276
|
+
navigate: 'settings'
|
|
277
|
+
}
|
|
278
|
+
]
|
|
279
|
+
},
|
|
280
|
+
// ═══ Phase 6: Best Practices (screens) ═══
|
|
281
|
+
{
|
|
282
|
+
name: 'Best Practices',
|
|
283
|
+
type: 'screens',
|
|
284
|
+
steps: [
|
|
285
|
+
{
|
|
286
|
+
svgKey: 'crosshair', iconClass: 'purple',
|
|
287
|
+
title: 'Be Precise. Get Precision.',
|
|
288
|
+
subtitle: 'AIVA operates on intent. The sharper your input, the sharper her output.',
|
|
289
|
+
features: [
|
|
290
|
+
{ svgKey: 'xCircle', text: '<strong>Vague:</strong> "send a message"' },
|
|
291
|
+
{ svgKey: 'checkCircle', text: '<strong>Precise:</strong> "Send John a reminder about our meeting tomorrow at 3pm via iMessage. Keep it casual."' }
|
|
292
|
+
],
|
|
293
|
+
detail: 'Names, dates, channels, tone — include everything. AIVA doesn\'t guess when she can know.'
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
svgKey: 'waveform', iconClass: 'pink',
|
|
297
|
+
title: 'Your Voice Is an Input Device',
|
|
298
|
+
subtitle: 'Complex requests, multi-step instructions, creative briefs — just talk. AIVA processes natural speech with full contextual understanding.',
|
|
299
|
+
detail: 'Voice is faster than typing for anything beyond a sentence. Use it for brainstorms, detailed task delegation, and anything where nuance matters.'
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
svgKey: 'bell', iconClass: 'blue',
|
|
303
|
+
title: 'Review What She Flags',
|
|
304
|
+
subtitle: 'When AIVA encounters something that requires your judgment, she escalates. Your response teaches her where the boundaries are.',
|
|
305
|
+
detail: 'The feedback loop is the learning loop. Every escalation you resolve makes her more autonomous next time.'
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
},
|
|
309
|
+
// ═══ Phase 7: Completion ═══
|
|
310
|
+
{
|
|
311
|
+
name: "You're Live",
|
|
312
|
+
type: 'completion',
|
|
313
|
+
steps: [{ title: 'completion' }]
|
|
314
|
+
}
|
|
315
|
+
];
|
|
316
|
+
|
|
317
|
+
let currentPhase = 0;
|
|
318
|
+
let currentStep = 0;
|
|
319
|
+
let isReplay = false;
|
|
320
|
+
let overlay = null;
|
|
321
|
+
|
|
322
|
+
function totalSteps() {
|
|
323
|
+
return PHASES.reduce((sum, p) => sum + p.steps.length, 0);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function globalStepIndex() {
|
|
327
|
+
let idx = 0;
|
|
328
|
+
for (let i = 0; i < currentPhase; i++) idx += PHASES[i].steps.length;
|
|
329
|
+
return idx + currentStep;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function progressPercent() {
|
|
333
|
+
return ((globalStepIndex() + 1) / totalSteps()) * 100;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function init() {
|
|
337
|
+
if (window.location.pathname !== '/' && !window.location.pathname.endsWith('index.html')) return;
|
|
338
|
+
const origShowApp = window.showApp;
|
|
339
|
+
if (typeof origShowApp === 'function') {
|
|
340
|
+
window.showApp = async function() {
|
|
341
|
+
await origShowApp.apply(this, arguments);
|
|
342
|
+
checkAndStart();
|
|
343
|
+
};
|
|
344
|
+
} else {
|
|
345
|
+
const poll = setInterval(() => {
|
|
346
|
+
if (document.getElementById('appContainer')?.style.display === 'flex') {
|
|
347
|
+
clearInterval(poll);
|
|
348
|
+
checkAndStart();
|
|
349
|
+
}
|
|
350
|
+
}, 500);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function checkAndStart() {
|
|
355
|
+
if (localStorage.getItem(STORAGE_KEY)) return;
|
|
356
|
+
setTimeout(() => start(false), 600);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function start(replay) {
|
|
360
|
+
isReplay = replay;
|
|
361
|
+
currentPhase = 0;
|
|
362
|
+
currentStep = 0;
|
|
363
|
+
if (typeof showView === 'function') showView('chat');
|
|
364
|
+
createOverlay();
|
|
365
|
+
render();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function createOverlay() {
|
|
369
|
+
if (overlay) overlay.remove();
|
|
370
|
+
overlay = document.createElement('div');
|
|
371
|
+
overlay.className = 'onboarding-overlay';
|
|
372
|
+
overlay.id = 'aivaOnboarding';
|
|
373
|
+
document.body.appendChild(overlay);
|
|
374
|
+
requestAnimationFrame(() => overlay.classList.add('visible'));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function cleanupHighlighted() {
|
|
378
|
+
document.querySelectorAll('.onboarding-highlighted').forEach(el => {
|
|
379
|
+
el.classList.remove('onboarding-highlighted');
|
|
380
|
+
});
|
|
381
|
+
const svgOverlay = document.getElementById('onboarding-svg-overlay');
|
|
382
|
+
if (svgOverlay) svgOverlay.remove();
|
|
383
|
+
const oldHighlight = document.getElementById('onboarding-highlight-el');
|
|
384
|
+
if (oldHighlight) oldHighlight.remove();
|
|
385
|
+
const oldTooltip = document.getElementById('onboarding-tooltip-el');
|
|
386
|
+
if (oldTooltip) oldTooltip.remove();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function createSvgMaskOverlay(rect, padding) {
|
|
390
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
391
|
+
svg.id = 'onboarding-svg-overlay';
|
|
392
|
+
svg.setAttribute('style', 'position:fixed;inset:0;z-index:999991;width:100%;height:100%;pointer-events:auto;');
|
|
393
|
+
svg.innerHTML = `
|
|
394
|
+
<defs>
|
|
395
|
+
<mask id="onboarding-mask">
|
|
396
|
+
<rect width="100%" height="100%" fill="white"/>
|
|
397
|
+
<rect x="${rect.left - padding}" y="${rect.top - padding}"
|
|
398
|
+
width="${rect.width + padding * 2}" height="${rect.height + padding * 2}"
|
|
399
|
+
rx="12" fill="black"/>
|
|
400
|
+
</mask>
|
|
401
|
+
</defs>
|
|
402
|
+
<rect width="100%" height="100%" fill="rgba(5,5,20,0.92)" mask="url(#onboarding-mask)"/>`;
|
|
403
|
+
document.body.appendChild(svg);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function navigateToPhase(phase) {
|
|
407
|
+
if (typeof showView !== 'function') return;
|
|
408
|
+
const viewMap = {
|
|
409
|
+
'Chat Tour': 'chat',
|
|
410
|
+
'Tasks Tour': 'kanban',
|
|
411
|
+
'Notes Tour': 'notes',
|
|
412
|
+
'Messages Tour': 'messages',
|
|
413
|
+
'Settings Tour': 'settings'
|
|
414
|
+
};
|
|
415
|
+
if (viewMap[phase.name]) showView(viewMap[phase.name]);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function render() {
|
|
419
|
+
cleanupHighlighted();
|
|
420
|
+
const phase = PHASES[currentPhase];
|
|
421
|
+
if (!phase) return finish();
|
|
422
|
+
|
|
423
|
+
navigateToPhase(phase);
|
|
424
|
+
|
|
425
|
+
if (phase.type === 'screens') renderScreen();
|
|
426
|
+
else if (phase.type === 'tooltips') renderTooltip();
|
|
427
|
+
else if (phase.type === 'interactive-guide') renderInteractiveGuide();
|
|
428
|
+
else if (phase.type === 'completion') renderCompletion();
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function renderScreen() {
|
|
432
|
+
const phase = PHASES[currentPhase];
|
|
433
|
+
const step = phase.steps[currentStep];
|
|
434
|
+
|
|
435
|
+
overlay.style.background = 'rgba(5, 5, 20, 0.93)';
|
|
436
|
+
overlay.innerHTML = `
|
|
437
|
+
${progressHTML()}
|
|
438
|
+
${isReplay ? skipHTML() : ''}
|
|
439
|
+
<div class="onboarding-screen active">
|
|
440
|
+
${animContainer(currentPhase, currentStep)}
|
|
441
|
+
${STEP_IMAGES[`${currentPhase}-${currentStep}`] ? '' : `<div class="onboarding-icon ${step.iconClass || 'purple'}">${svgIconLarge(step.svgKey)}</div>`}
|
|
442
|
+
<div class="onboarding-title">${step.title}</div>
|
|
443
|
+
<div class="onboarding-subtitle">${step.subtitle}</div>
|
|
444
|
+
${step.features ? `<div class="onboarding-features">${step.features.map(f =>
|
|
445
|
+
`<div class="onboarding-feature">
|
|
446
|
+
<div class="onboarding-feature-icon">${svgIcon(f.svgKey)}</div>
|
|
447
|
+
<div class="onboarding-feature-text">${f.text}</div>
|
|
448
|
+
</div>`
|
|
449
|
+
).join('')}</div>` : ''}
|
|
450
|
+
${step.detail ? `<div class="onboarding-detail">${step.detail}</div>` : ''}
|
|
451
|
+
</div>
|
|
452
|
+
${navHTML()}
|
|
453
|
+
`;
|
|
454
|
+
bindNav();
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function renderInteractiveGuide() {
|
|
458
|
+
const phase = PHASES[currentPhase];
|
|
459
|
+
const step = phase.steps[currentStep];
|
|
460
|
+
|
|
461
|
+
// Navigate to messages view on first step
|
|
462
|
+
if (typeof showView === 'function') showView('messages');
|
|
463
|
+
|
|
464
|
+
overlay.style.background = 'rgba(5, 5, 20, 0.93)';
|
|
465
|
+
overlay.innerHTML = `
|
|
466
|
+
${progressHTML()}
|
|
467
|
+
${isReplay ? skipHTML() : ''}
|
|
468
|
+
<div class="onboarding-screen active">
|
|
469
|
+
${animContainer(currentPhase, currentStep)}
|
|
470
|
+
<div class="onboarding-guide-step-indicator">
|
|
471
|
+
${Array.from({length: step.guideTotal}, (_, i) =>
|
|
472
|
+
`<div class="guide-dot ${i + 1 === step.guideStep ? 'active' : i + 1 < step.guideStep ? 'completed' : ''}"></div>`
|
|
473
|
+
).join('<div class="guide-dot-line"></div>')}
|
|
474
|
+
</div>
|
|
475
|
+
${STEP_IMAGES[`${currentPhase}-${currentStep}`] ? '' : `<div class="onboarding-icon ${step.iconClass || 'blue'}">${svgIconLarge(step.svgKey)}</div>`}
|
|
476
|
+
<div class="onboarding-title">${step.title}</div>
|
|
477
|
+
<div class="onboarding-subtitle">${step.subtitle}</div>
|
|
478
|
+
${step.features ? `<div class="onboarding-features">${step.features.map(f =>
|
|
479
|
+
`<div class="onboarding-feature">
|
|
480
|
+
<div class="onboarding-feature-icon">${svgIcon(f.svgKey)}</div>
|
|
481
|
+
<div class="onboarding-feature-text">${f.text}</div>
|
|
482
|
+
</div>`
|
|
483
|
+
).join('')}</div>` : ''}
|
|
484
|
+
${step.detail ? `<div class="onboarding-detail">${step.detail}</div>` : ''}
|
|
485
|
+
</div>
|
|
486
|
+
${navHTML()}
|
|
487
|
+
`;
|
|
488
|
+
bindNav();
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function renderTooltip() {
|
|
492
|
+
const phase = PHASES[currentPhase];
|
|
493
|
+
const step = phase.steps[currentStep];
|
|
494
|
+
|
|
495
|
+
if (step.navigate && typeof showView === 'function') {
|
|
496
|
+
showView(step.navigate);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (step.preAction) step.preAction();
|
|
500
|
+
|
|
501
|
+
overlay.innerHTML = `${progressHTML()}${isReplay ? skipHTML() : ''}`;
|
|
502
|
+
overlay.style.background = 'transparent';
|
|
503
|
+
|
|
504
|
+
setTimeout(() => {
|
|
505
|
+
const el = document.querySelector(step.selector);
|
|
506
|
+
if (!el) { next(); return; }
|
|
507
|
+
|
|
508
|
+
el.classList.add('onboarding-highlighted');
|
|
509
|
+
const rect = el.getBoundingClientRect();
|
|
510
|
+
const pad = 6;
|
|
511
|
+
|
|
512
|
+
createSvgMaskOverlay(rect, pad);
|
|
513
|
+
|
|
514
|
+
const highlight = document.createElement('div');
|
|
515
|
+
highlight.className = 'onboarding-highlight';
|
|
516
|
+
highlight.id = 'onboarding-highlight-el';
|
|
517
|
+
highlight.style.left = (rect.left - pad) + 'px';
|
|
518
|
+
highlight.style.top = (rect.top - pad) + 'px';
|
|
519
|
+
highlight.style.width = (rect.width + pad * 2) + 'px';
|
|
520
|
+
highlight.style.height = (rect.height + pad * 2) + 'px';
|
|
521
|
+
document.body.appendChild(highlight);
|
|
522
|
+
|
|
523
|
+
const tooltip = document.createElement('div');
|
|
524
|
+
tooltip.className = 'onboarding-tooltip';
|
|
525
|
+
tooltip.id = 'onboarding-tooltip-el';
|
|
526
|
+
tooltip.style.visibility = 'hidden';
|
|
527
|
+
tooltip.style.top = '0';
|
|
528
|
+
tooltip.style.left = '0';
|
|
529
|
+
|
|
530
|
+
tooltip.innerHTML = `
|
|
531
|
+
<div class="onboarding-tooltip-title">${step.title}</div>
|
|
532
|
+
<div class="onboarding-tooltip-text">${step.text}</div>
|
|
533
|
+
<div class="onboarding-tooltip-nav">
|
|
534
|
+
${canGoBack() ? '<button class="onboarding-btn onboarding-btn-back" id="obBack">Back</button>' : ''}
|
|
535
|
+
<button class="onboarding-btn onboarding-btn-next" id="obNext">${isLastStep() ? 'Next Phase' : 'Next'} ${svgIcon('terminal', 14)}</button>
|
|
536
|
+
</div>
|
|
537
|
+
`;
|
|
538
|
+
document.body.appendChild(tooltip);
|
|
539
|
+
|
|
540
|
+
const GAP = 12, MARGIN = 8;
|
|
541
|
+
const vw = window.innerWidth, vh = window.innerHeight;
|
|
542
|
+
const tRect = tooltip.getBoundingClientRect();
|
|
543
|
+
const tw = tRect.width, th = tRect.height;
|
|
544
|
+
const hRect = {
|
|
545
|
+
top: rect.top - pad, bottom: rect.bottom + pad,
|
|
546
|
+
left: rect.left - pad, right: rect.right + pad,
|
|
547
|
+
width: rect.width + pad * 2, height: rect.height + pad * 2
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const spaceBelow = vh - hRect.bottom - GAP;
|
|
551
|
+
const spaceAbove = hRect.top - GAP;
|
|
552
|
+
let top, left;
|
|
553
|
+
const preferAbove = step.position === 'top';
|
|
554
|
+
|
|
555
|
+
if (!preferAbove && spaceBelow >= th) {
|
|
556
|
+
top = hRect.bottom + GAP;
|
|
557
|
+
left = hRect.left + hRect.width / 2 - tw / 2;
|
|
558
|
+
} else if (spaceAbove >= th) {
|
|
559
|
+
top = hRect.top - GAP - th;
|
|
560
|
+
left = hRect.left + hRect.width / 2 - tw / 2;
|
|
561
|
+
} else if (!preferAbove && spaceBelow >= spaceAbove) {
|
|
562
|
+
top = hRect.bottom + GAP;
|
|
563
|
+
left = hRect.left + hRect.width / 2 - tw / 2;
|
|
564
|
+
} else {
|
|
565
|
+
top = hRect.top - GAP - th;
|
|
566
|
+
left = hRect.left + hRect.width / 2 - tw / 2;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
left = Math.max(MARGIN, Math.min(left, vw - tw - MARGIN));
|
|
570
|
+
top = Math.max(MARGIN, Math.min(top, vh - th - MARGIN));
|
|
571
|
+
|
|
572
|
+
const tTop = top, tBottom = top + th, tLeft = left, tRight = left + tw;
|
|
573
|
+
const overlaps = !(tRight <= hRect.left || tLeft >= hRect.right || tBottom <= hRect.top || tTop >= hRect.bottom);
|
|
574
|
+
if (overlaps) {
|
|
575
|
+
top = top > hRect.top ? hRect.top - GAP - th : hRect.bottom + GAP;
|
|
576
|
+
top = Math.max(MARGIN, Math.min(top, vh - th - MARGIN));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
tooltip.style.top = top + 'px';
|
|
580
|
+
tooltip.style.left = left + 'px';
|
|
581
|
+
tooltip.style.visibility = 'visible';
|
|
582
|
+
|
|
583
|
+
bindNav();
|
|
584
|
+
}, 200);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function renderCompletion() {
|
|
588
|
+
overlay.style.background = 'rgba(5, 5, 20, 0.93)';
|
|
589
|
+
overlay.innerHTML = `
|
|
590
|
+
${progressHTML()}
|
|
591
|
+
<div class="onboarding-screen active">
|
|
592
|
+
${animContainer(currentPhase, currentStep)}
|
|
593
|
+
<div class="onboarding-complete-check">${SVG.checkAnimated}</div>
|
|
594
|
+
<div class="onboarding-title">You're Live.</div>
|
|
595
|
+
<div class="onboarding-subtitle">Have AIVA join Facebook groups and start conversations. Manage your CRM pipeline. Build a weekly meal plan with a grocery list every Saturday. Design your next sales sheet. Draft contracts. Research competitors. Plan your workouts. Reply to leads at 2 AM while you sleep.</div>
|
|
596
|
+
<div class="onboarding-summary">
|
|
597
|
+
<div class="onboarding-summary-item">${svgIcon('terminal')} Command Center</div>
|
|
598
|
+
<div class="onboarding-summary-item">${svgIcon('kanban')} Task Pipeline</div>
|
|
599
|
+
<div class="onboarding-summary-item">${svgIcon('waveform')} Voice Notes</div>
|
|
600
|
+
<div class="onboarding-summary-item">${svgIcon('envelope')} Communication Layer</div>
|
|
601
|
+
<div class="onboarding-summary-item">${svgIcon('gear')} Configuration</div>
|
|
602
|
+
</div>
|
|
603
|
+
<div class="onboarding-pullquote">The real question isn't what AIVA can do. It's what you'll try first.</div>
|
|
604
|
+
</div>
|
|
605
|
+
<div class="onboarding-nav">
|
|
606
|
+
<button class="onboarding-btn onboarding-btn-next" id="obFinish" style="max-width:none;">Start Working with AIVA</button>
|
|
607
|
+
</div>
|
|
608
|
+
`;
|
|
609
|
+
|
|
610
|
+
document.getElementById('obFinish')?.addEventListener('click', finish);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function progressHTML() {
|
|
614
|
+
const phase = PHASES[currentPhase];
|
|
615
|
+
return `<div class="onboarding-progress">
|
|
616
|
+
<div class="onboarding-progress-label">
|
|
617
|
+
<span class="onboarding-progress-phase">Phase ${currentPhase + 1} of ${PHASES.length}: ${phase?.name || ''}</span>
|
|
618
|
+
<span class="onboarding-progress-step">Step ${currentStep + 1} of ${phase?.steps.length || 1}</span>
|
|
619
|
+
</div>
|
|
620
|
+
<div class="onboarding-progress-bar">
|
|
621
|
+
<div class="onboarding-progress-fill" style="width:${progressPercent()}%"></div>
|
|
622
|
+
</div>
|
|
623
|
+
</div>`;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function skipHTML() {
|
|
627
|
+
return '<button class="onboarding-skip" id="obSkip">Skip Tutorial</button>';
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function navHTML() {
|
|
631
|
+
return `<div class="onboarding-nav">
|
|
632
|
+
${canGoBack() ? '<button class="onboarding-btn onboarding-btn-back" id="obBack">Back</button>' : ''}
|
|
633
|
+
<button class="onboarding-btn onboarding-btn-next" id="obNext">Next</button>
|
|
634
|
+
</div>`;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function canGoBack() {
|
|
638
|
+
return currentPhase > 0 || currentStep > 0;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function isLastStep() {
|
|
642
|
+
const phase = PHASES[currentPhase];
|
|
643
|
+
return currentStep >= phase.steps.length - 1;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function bindNav() {
|
|
647
|
+
document.getElementById('obNext')?.addEventListener('click', next);
|
|
648
|
+
document.getElementById('obBack')?.addEventListener('click', back);
|
|
649
|
+
document.getElementById('obSkip')?.addEventListener('click', finish);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function next() {
|
|
653
|
+
const phase = PHASES[currentPhase];
|
|
654
|
+
if (currentStep < phase.steps.length - 1) {
|
|
655
|
+
currentStep++;
|
|
656
|
+
} else if (currentPhase < PHASES.length - 1) {
|
|
657
|
+
currentPhase++;
|
|
658
|
+
currentStep = 0;
|
|
659
|
+
if (PHASES[currentPhase]?.type !== 'tooltips' && typeof showView === 'function') {
|
|
660
|
+
showView('chat');
|
|
661
|
+
}
|
|
662
|
+
} else {
|
|
663
|
+
finish();
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
render();
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function back() {
|
|
670
|
+
if (currentStep > 0) {
|
|
671
|
+
currentStep--;
|
|
672
|
+
} else if (currentPhase > 0) {
|
|
673
|
+
currentPhase--;
|
|
674
|
+
currentStep = PHASES[currentPhase].steps.length - 1;
|
|
675
|
+
}
|
|
676
|
+
render();
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function finish() {
|
|
680
|
+
cleanupHighlighted();
|
|
681
|
+
localStorage.setItem(STORAGE_KEY, Date.now().toString());
|
|
682
|
+
if (overlay) {
|
|
683
|
+
overlay.classList.remove('visible');
|
|
684
|
+
setTimeout(() => { overlay.remove(); overlay = null; }, 400);
|
|
685
|
+
}
|
|
686
|
+
if (typeof showView === 'function') showView('chat');
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
window.aivaOnboarding = {
|
|
690
|
+
start: function() { start(true); },
|
|
691
|
+
isCompleted: function() { return !!localStorage.getItem(STORAGE_KEY); }
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
if (document.readyState === 'loading') {
|
|
695
|
+
document.addEventListener('DOMContentLoaded', init);
|
|
696
|
+
} else {
|
|
697
|
+
init();
|
|
698
|
+
}
|
|
699
|
+
})();
|