initial_commit

This commit is contained in:
2026-06-01 20:16:53 +09:00
commit 903d34761c
31 changed files with 1123 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue'
import { useChatStore } from '../stores/chat'
const store = useChatStore()
const scrollEl = ref<HTMLElement | null>(null)
watch(
() => store.messages.length,
async () => {
await nextTick()
if (scrollEl.value) scrollEl.value.scrollTop = scrollEl.value.scrollHeight
},
)
</script>
<template>
<div class="chat-window" ref="scrollEl">
<div v-if="store.messages.length === 0" class="empty">
メッセージを送信してチャットを開始してください
</div>
<div
v-for="(msg, i) in store.messages"
:key="i"
:class="['message', msg.role, { pending: msg.pending }]"
>
<div class="bubble">
<span class="content">{{ msg.content }}</span>
<span v-if="msg.pending" class="cursor">▌</span>
</div>
</div>
</div>
</template>
<style scoped>
.chat-window {
flex: 1;
overflow-y: auto;
padding: 16px 20px;
display: flex;
flex-direction: column;
gap: 12px;
}
.empty {
margin: auto;
color: #555;
font-size: 14px;
}
.message {
display: flex;
}
.message.user { justify-content: flex-end; }
.message.assistant { justify-content: flex-start; }
.bubble {
max-width: 72%;
padding: 10px 14px;
border-radius: 12px;
font-size: 14px;
line-height: 1.6;
white-space: pre-wrap;
word-break: break-word;
}
.user .bubble {
background: #2563eb;
color: #fff;
border-bottom-right-radius: 4px;
}
.assistant .bubble {
background: #2a2a2a;
color: #eee;
border-bottom-left-radius: 4px;
}
.cursor {
animation: blink 0.8s step-end infinite;
}
@keyframes blink { 50% { opacity: 0; } }
</style>