Deploy Ladill Frontdesk / deploy (push) Successful in 34s
Add the AI assistant button, chat endpoint, and Frontdesk-specific prompts, and include Frontdesk in the shared launcher config used by the app switcher. Co-authored-by: Cursor <cursoragent@cursor.com>
107 lines
7.0 KiB
PHP
107 lines
7.0 KiB
PHP
@php
|
|
$afiaGreeting = "Hi, I'm Afia 👋 Ask me about visitor check-in, kiosks, hosts, badges, devices, or setting up your reception desk…";
|
|
$afiaSuggestions = [
|
|
'How do I set up a visitor kiosk?',
|
|
'How do I check a visitor in?',
|
|
'Where do I add reception desks?',
|
|
'How do hosts approve visits?',
|
|
];
|
|
@endphp
|
|
{{-- Afia — Ladill AI assistant slide-over. Opened via $dispatch('afia-open'). --}}
|
|
<div x-data="afia({
|
|
chatUrl: '{{ route('frontdesk.ai.chat') }}',
|
|
csrf: '{{ csrf_token() }}',
|
|
greeting: @js($afiaGreeting),
|
|
suggestions: @js($afiaSuggestions),
|
|
})" @afia-open.window="open = true; $nextTick(() => $refs.input && $refs.input.focus())">
|
|
<div x-show="open" x-cloak @click="close()" class="fixed inset-0 z-50 bg-slate-900/20"></div>
|
|
|
|
<section x-show="open" x-cloak
|
|
x-transition:enter="transition transform ease-out duration-200"
|
|
x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0"
|
|
x-transition:leave="transition transform ease-in duration-150"
|
|
x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full"
|
|
class="fixed inset-y-0 right-0 z-50 flex w-full max-w-md flex-col bg-white shadow-2xl">
|
|
<div class="flex items-center justify-between border-b border-slate-100 px-5 py-3.5">
|
|
<div class="flex items-center gap-2.5">
|
|
<span class="relative flex h-8 w-8 shrink-0 items-center justify-center">
|
|
<svg viewBox="0 0 36 36" class="h-8 w-8" aria-hidden="true">
|
|
<defs>
|
|
<radialGradient id="afia-orb" cx="40%" cy="35%" r="60%">
|
|
<stop offset="0%" stop-color="#a5b4fc"/>
|
|
<stop offset="50%" stop-color="#6366f1"/>
|
|
<stop offset="100%" stop-color="#3730a3"/>
|
|
</radialGradient>
|
|
</defs>
|
|
<circle cx="18" cy="18" r="14" fill="url(#afia-orb)">
|
|
<animate attributeName="r" values="14;14.8;14" dur="3s" repeatCount="indefinite"/>
|
|
</circle>
|
|
<circle cx="18" cy="18" r="11" fill="none" stroke="#c7d2fe" stroke-width=".6" opacity=".5">
|
|
<animate attributeName="r" values="11;12.5;11" dur="4s" repeatCount="indefinite"/>
|
|
<animate attributeName="opacity" values=".5;.15;.5" dur="4s" repeatCount="indefinite"/>
|
|
</circle>
|
|
<circle r="1.2" fill="#c7d2fe" opacity=".8">
|
|
<animateMotion dur="3s" repeatCount="indefinite" path="M18,8 A10,10 0 1,1 17.99,8" rotate="auto"/>
|
|
</circle>
|
|
</svg>
|
|
<span class="absolute -bottom-0.5 -right-0.5 h-2.5 w-2.5 rounded-full border-2 border-white bg-emerald-400"></span>
|
|
</span>
|
|
<div class="leading-tight">
|
|
<p class="text-sm font-semibold text-slate-900">Afia</p>
|
|
<p class="text-[11px] text-slate-400">Frontdesk assistant</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-1">
|
|
<a href="{{ ladill_account_url('ai') }}"
|
|
class="rounded-lg px-2 py-1 text-[11px] font-medium text-slate-500 hover:bg-slate-100 hover:text-slate-700"
|
|
title="AI usage history on your Ladill account">History</a>
|
|
<button @click="close()" class="rounded-lg p-1.5 text-slate-400 hover:bg-slate-100 hover:text-slate-600">
|
|
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex-1 overflow-y-auto px-4 py-4" x-ref="scroll">
|
|
<div class="space-y-3">
|
|
<template x-for="(m, i) in messages" :key="i">
|
|
<div class="flex" :class="m.role === 'user' ? 'justify-end' : 'justify-start'">
|
|
<div class="max-w-[85%] whitespace-pre-line rounded-2xl px-3.5 py-2.5 text-[13px] leading-relaxed"
|
|
:class="m.role === 'user' ? 'bg-indigo-600 text-white rounded-br-md' : 'bg-slate-100 text-slate-700 rounded-bl-md'"
|
|
x-html="m.text.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\*\*([^*]+?)\*\*/g,'<strong>$1</strong>')"></div>
|
|
</div>
|
|
</template>
|
|
<div x-show="loading" class="flex justify-start">
|
|
<div class="rounded-2xl rounded-bl-md bg-slate-100 px-4 py-3">
|
|
<div class="flex gap-1">
|
|
<span class="h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400" style="animation-delay:0ms"></span>
|
|
<span class="h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400" style="animation-delay:150ms"></span>
|
|
<span class="h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400" style="animation-delay:300ms"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div x-show="messages.length <= 1 && suggestions.length" class="mt-4 space-y-2">
|
|
<template x-for="s in suggestions" :key="s">
|
|
<button @click="useSuggestion(s)" :disabled="loading"
|
|
class="flex w-full items-center gap-2 rounded-xl border border-slate-200 bg-white px-3.5 py-2.5 text-left text-[13px] font-medium text-slate-700 transition hover:border-indigo-200 hover:bg-indigo-50 disabled:opacity-50">
|
|
<span class="text-indigo-400">→</span><span x-text="s"></span>
|
|
</button>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border-t border-slate-100 px-4 pb-4 pt-3">
|
|
<form @submit.prevent="send()" class="flex items-end gap-2">
|
|
<input type="text" x-ref="input" x-model="input" :disabled="loading" placeholder="Message Afia…"
|
|
class="flex-1 rounded-xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm text-slate-700 placeholder-slate-400 focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
|
|
<button type="submit" :disabled="loading || !input.trim()"
|
|
class="btn-fab shrink-0 disabled:opacity-40">
|
|
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18"/></svg>
|
|
</button>
|
|
</form>
|
|
<p class="mt-2 text-center text-[10px] text-slate-400">Afia can make mistakes — verify important details.</p>
|
|
</div>
|
|
</section>
|
|
</div>
|