Files
CRM_Montzar/apps/web/src/components/CustomerMoodFace.vue
T
MahdiandCursor 7757c0837d Add Ask Mento, customer mood, and Pipecat speech-to-text.
Ship assistant answers, contact moods, voice dictation, and the related CRM UI so these can be deployed to production.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 14:20:55 +03:30

222 lines
3.8 KiB
Vue

<script setup lang="ts">
import type { PersonMood } from '@mento/shared';
withDefaults(
defineProps<{
mood?: PersonMood | null;
size?: number;
}>(),
{ mood: 'newcomer', size: 48 },
);
</script>
<template>
<span
class="face"
:class="mood || 'newcomer'"
:style="{ width: `${size}px`, height: `${size}px` }"
aria-hidden="true"
>
<svg viewBox="0 0 64 64" fill="none">
<circle class="skin" cx="32" cy="34" r="22" />
<g class="shine">
<ellipse cx="24" cy="26" rx="6" ry="3.2" />
</g>
<g class="eyes">
<g class="eye left">
<ellipse class="open" cx="24" cy="33" rx="3.1" ry="3.6" />
<path class="happy" d="M21 33c1.4-2.2 4.6-2.2 6 0" />
<path class="sad" d="M21.4 34.6c1.2-2 4-2 5.2 0" />
</g>
<g class="eye right">
<ellipse class="open" cx="40" cy="33" rx="3.1" ry="3.6" />
<path class="happy" d="M37 33c1.4-2.2 4.6-2.2 6 0" />
<path class="sad" d="M37.4 34.6c1.2-2 4-2 5.2 0" />
</g>
</g>
<path class="mouth smile" d="M24 42c2.6 4.4 13.4 4.4 16 0" />
<path class="mouth grin" d="M22 40.5c3.4 7 16.6 7 20 0" />
<path class="mouth frown" d="M25 46c2.8-3.6 11.2-3.6 14 0" />
<g class="tears">
<ellipse class="tear t1" cx="18" cy="40" rx="2.1" ry="3.2" />
<ellipse class="tear t2" cx="46" cy="42" rx="2.1" ry="3.2" />
</g>
<g class="crown">
<path d="M16 18.5 22 26l10-9 10 9 6-7.5-2 12H18l-2-12Z" />
<rect x="18" y="26" width="28" height="3.4" rx="1" />
<circle class="gem" cx="32" cy="20" r="2.1" />
<circle class="gem side" cx="22.5" cy="23" r="1.5" />
<circle class="gem side" cx="41.5" cy="23" r="1.5" />
</g>
</svg>
</span>
</template>
<style scoped>
.face {
display: inline-grid;
place-items: center;
flex-shrink: 0;
border-radius: 50%;
background: #fff7d6;
box-shadow: inset 0 -3px 0 rgba(180, 120, 20, 0.08);
overflow: visible;
}
svg {
width: 100%;
height: 100%;
overflow: visible;
}
.skin {
fill: #f5c542;
}
.shine ellipse {
fill: rgba(255, 255, 255, 0.35);
}
.eye .open {
fill: #3b2415;
}
.eye .happy,
.eye .sad,
.mouth,
.tears,
.crown {
display: none;
}
.eye .happy,
.eye .sad,
.mouth {
stroke: #3b2415;
stroke-width: 2.4;
stroke-linecap: round;
fill: none;
}
.face.newcomer .mouth.smile {
display: block;
}
.face.happy {
animation: bounce 1.6s ease-in-out infinite;
}
.face.happy .eye .open {
display: none;
}
.face.happy .eye .happy,
.face.happy .mouth.grin {
display: block;
}
.face.unhappy .eye .open {
display: none;
}
.face.unhappy .eye .sad,
.face.unhappy .mouth.frown,
.face.unhappy .tears {
display: block;
}
.tear {
fill: #5bb7ff;
}
.t1 {
animation: drop 1.4s ease-in infinite;
}
.t2 {
animation: drop 1.4s ease-in 0.35s infinite;
}
.face.special .mouth.smile,
.face.special .crown {
display: block;
}
.face.special .crown {
transform-origin: 32px 22px;
animation: bob 1.8s ease-in-out infinite;
}
.crown path,
.crown rect {
fill: #f0b429;
stroke: #c48414;
stroke-width: 1;
}
.gem {
fill: #ef4444;
}
.gem.side {
fill: #22c55e;
}
.face.newcomer .eye .open,
.face.special .eye .open {
transform-box: fill-box;
transform-origin: center;
animation: blink 3.4s ease-in-out infinite;
}
@keyframes blink {
0%,
42%,
48%,
100% {
transform: scaleY(1);
}
45% {
transform: scaleY(0.12);
}
}
@keyframes bounce {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-2px);
}
}
@keyframes drop {
0% {
opacity: 0;
transform: translateY(-4px);
}
25% {
opacity: 1;
}
100% {
opacity: 0;
transform: translateY(10px);
}
}
@keyframes bob {
0%,
100% {
transform: translateY(0) rotate(-4deg);
}
50% {
transform: translateY(-2px) rotate(4deg);
}
}
</style>