feat: add welcome card

This commit is contained in:
Shivam Mishra
2026-06-29 18:11:43 +05:30
parent bb387dbd4a
commit ef63752075
5 changed files with 107 additions and 33 deletions
@@ -182,7 +182,8 @@ const handleCreateAssistant = () => {
</div>
</div>
<div class="flex gap-2">
<div class="flex items-center gap-2">
<slot name="headerActions" />
<slot name="search" />
<div
v-if="!showPaywall && buttonLabel"
@@ -0,0 +1,61 @@
<script setup>
import { computed } from 'vue';
import { useMapGetter } from 'dashboard/composables/store';
const currentUser = useMapGetter('getCurrentUser');
const firstName = computed(() => {
const name = currentUser.value?.name?.trim();
return name ? name.split(' ')[0] : 'there';
});
// The summary is generated by the model from the assistant's stats using the
// captain_overview_summary.liquid prompt (lib/integrations/openai/openai_prompts).
// DUMMY: stands in for an LLM-generated summary. In production this markdown
// string would come back from the model after we feed it the assistant's
// stats; numbers are emphasised with **bold** so we can highlight them.
const welcomeMarkdown = computed(
() =>
`Hey ${firstName.value}, your assistant handled **1,248 conversations** this month and saved your team **612 hours** of work. Auto-resolution climbed **4.1%** while keeping handoffs low. Knowledge coverage is running strong as well.\n\nI'd keep an eye out for credits, you seem to have exhaused nearly **80%** of it.`
);
// Split the markdown on **bold** runs so we can render emphasised numbers as
// brand-highlighted spans with Tailwind (instead of styling raw HTML).
const segments = computed(() => {
const parts = [];
const regex = /\*\*(.+?)\*\*/g;
let lastIndex = 0;
let match = regex.exec(welcomeMarkdown.value);
while (match) {
if (match.index > lastIndex) {
parts.push({ text: welcomeMarkdown.value.slice(lastIndex, match.index) });
}
parts.push({ text: match[1], bold: true });
lastIndex = regex.lastIndex;
match = regex.exec(welcomeMarkdown.value);
}
if (lastIndex < welcomeMarkdown.value.length) {
parts.push({ text: welcomeMarkdown.value.slice(lastIndex) });
}
return parts.map((part, index) => ({ ...part, key: index }));
});
</script>
<template>
<div class="flex flex-col gap-3">
<div class="flex items-center gap-1.5 text-n-slate-10">
<span class="i-lucide-sparkles size-3.5" />
<span class="text-xs">
{{ $t('CAPTAIN.OVERVIEW.WELCOME.LABEL') }}
</span>
</div>
<p class="text-lg leading-relaxed text-n-slate-12">
<template v-for="segment in segments" :key="segment.key">
<span v-if="segment.bold" class="font-bold tabular-nums text-n-brand">{{
segment.text
}}</span>
<template v-else>{{ segment.text }}</template>
</template>
</p>
</div>
</template>