File size: 2,399 Bytes
bc7e9cd
db9635c
bc7e9cd
 
 
 
 
 
 
db9635c
bc7e9cd
 
db9635c
bc7e9cd
 
db9635c
 
 
bc7e9cd
 
db9635c
 
bc7e9cd
 
 
 
 
 
 
db9635c
 
bc7e9cd
 
 
 
db9635c
 
 
 
 
 
 
 
 
 
 
 
bc7e9cd
 
db9635c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bc7e9cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<script lang="ts">
  import { onMount, afterUpdate } from "svelte";
  import gsap from "gsap";
  import type { ChatMessage } from "../../models/chat-data";
  import MessageContent from "./MessageContent.svelte";

  export let message: ChatMessage;

  let messageRef: HTMLDivElement;
  let hasAnimated = false;

  onMount(() => {
    if (messageRef && !hasAnimated) {
      const isUser = message.role === 'user';

      const tl = gsap.timeline();

      tl.fromTo(messageRef,
        {
          opacity: 0,
          y: isUser ? 5 : 10,
          x: isUser ? 8 : -8,
          scale: 0.98
        },
        {
          opacity: 1,
          y: 0,
          x: 0,
          scale: 1,
          duration: 0.35,
          ease: "power2.out"
        }
      );

      if (!isUser) {
        tl.fromTo(messageRef.querySelector('.message-content'),
          {
            opacity: 0,
            borderLeftWidth: "0px"
          },
          {
            opacity: 1,
            borderLeftWidth: "2px",
            duration: 0.3,
            ease: "power2.out"
          },
          "-=0.2"
        );
      }

      hasAnimated = true;
    }
  });

  afterUpdate(() => {
    if (messageRef && !message.streaming && message.role === 'assistant' && hasAnimated) {
      const borderEl = messageRef.querySelector('.message-content') as HTMLElement;
      if (borderEl && !borderEl.dataset.completed) {
        borderEl.dataset.completed = "true";
        gsap.to(borderEl, {
          borderLeftColor: "rgba(76, 175, 80, 0.4)",
          duration: 0.3,
          yoyo: true,
          repeat: 1,
          ease: "power2.inOut",
          onComplete: () => {
            gsap.set(borderEl, { borderLeftColor: "rgba(139, 115, 85, 0.08)" });
          }
        });
      }
    }
  });
</script>

<div class="message {message.role}" bind:this={messageRef}>
  <div class="message-content">
    <MessageContent {message} />
  </div>
</div>

<style>
  .message {
    padding: 0.375rem 0.5rem;
    position: relative;
  }

  .message-content {
    position: relative;
  }

  .message.user {
    opacity: 0.9;
  }

  .message.user .message-content {
    padding-left: 0.5rem;
    border-left: 2px solid rgba(124, 152, 133, 0.3);
  }

  .message.assistant {
    opacity: 1;
  }

  .message.assistant .message-content {
    padding-left: 0.5rem;
    border-left: 2px solid rgba(139, 115, 85, 0.08);
  }
</style>