ui improvements
This commit is contained in:
parent
b230e22ed1
commit
fcf052bf8a
3 changed files with 41 additions and 40 deletions
|
|
@ -133,7 +133,7 @@ const getMessageGroupClasses = (sent: boolean) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Card
|
<Card
|
||||||
class="flex flex-col h-[calc(100vh-2rem)] bg-gradient-to-b from-[#1e1e2e] to-[#181825] border-[#313244] shadow-2xl overflow-hidden relative z-0">
|
class="flex flex-col h-full bg-gradient-to-b from-[#1e1e2e] to-[#181825] border-[#313244] shadow-2xl overflow-hidden relative z-0">
|
||||||
<CardHeader
|
<CardHeader
|
||||||
class="flex-shrink-0 flex flex-row items-center justify-between px-6 py-4 border-b border-[#313244]/50 bg-[#181825]/95 backdrop-blur-md relative z-50">
|
class="flex-shrink-0 flex flex-row items-center justify-between px-6 py-4 border-b border-[#313244]/50 bg-[#181825]/95 backdrop-blur-md relative z-50">
|
||||||
<!-- Left side with avatar and name -->
|
<!-- Left side with avatar and name -->
|
||||||
|
|
@ -176,7 +176,7 @@ const getMessageGroupClasses = (sent: boolean) => {
|
||||||
|
|
||||||
<CardContent class="flex-1 min-h-0 p-0 bg-gradient-to-b from-[#1e1e2e] to-[#181825] overflow-hidden">
|
<CardContent class="flex-1 min-h-0 p-0 bg-gradient-to-b from-[#1e1e2e] to-[#181825] overflow-hidden">
|
||||||
<ScrollArea class="h-full" type="hover">
|
<ScrollArea class="h-full" type="hover">
|
||||||
<div class="flex flex-col gap-4 p-6">
|
<div class="flex flex-col gap-4 px-6 py-4">
|
||||||
<template v-for="(group, groupIndex) in groupedMessages" :key="groupIndex">
|
<template v-for="(group, groupIndex) in groupedMessages" :key="groupIndex">
|
||||||
<!-- Date separator -->
|
<!-- Date separator -->
|
||||||
<div v-if="groupIndex === 0 ||
|
<div v-if="groupIndex === 0 ||
|
||||||
|
|
@ -210,7 +210,7 @@ const getMessageGroupClasses = (sent: boolean) => {
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|
||||||
<CardFooter
|
<CardFooter
|
||||||
class="flex-shrink-0 mt-auto border-t border-[#313244]/50 bg-[#181825]/95 backdrop-blur-md p-6 shadow-xl">
|
class="flex-shrink-0 border-t border-[#313244]/50 bg-[#181825]/95 backdrop-blur-md p-4 shadow-xl">
|
||||||
<form @submit="sendMessage" class="flex w-full items-center gap-4">
|
<form @submit="sendMessage" class="flex w-full items-center gap-4">
|
||||||
<Input id="message" v-model="input" placeholder="Type your message..."
|
<Input id="message" v-model="input" placeholder="Type your message..."
|
||||||
class="flex-1 bg-[#1e1e2e]/90 border-[#313244] text-[#cdd6f4] placeholder:text-[#6c7086] focus:ring-2 focus:ring-[#cba6f7] focus:border-[#cba6f7] transition-all duration-300 shadow-lg hover:border-[#45475a] rounded-xl h-11"
|
class="flex-1 bg-[#1e1e2e]/90 border-[#313244] text-[#cdd6f4] placeholder:text-[#6c7086] focus:ring-2 focus:ring-[#cba6f7] focus:border-[#cba6f7] transition-all duration-300 shadow-lg hover:border-[#45475a] rounded-xl h-11"
|
||||||
|
|
@ -279,21 +279,15 @@ const getMessageGroupClasses = (sent: boolean) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.scrollarea-viewport) {
|
:deep(.scrollarea-viewport) {
|
||||||
height: 100%;
|
height: 100% !important;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.scrollarea-thumb-y) {
|
/* Ensure the scroll area takes up all available space */
|
||||||
z-index: 30;
|
:deep(.scrollarea-viewport > div) {
|
||||||
width: 5px !important;
|
height: 100%;
|
||||||
background: #45475a !important;
|
display: flex;
|
||||||
border-radius: 9999px !important;
|
flex-direction: column;
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.scrollarea-thumb-y:hover) {
|
|
||||||
background: #585b70 !important;
|
|
||||||
width: 6px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Improved focus styles */
|
/* Improved focus styles */
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,9 @@ const nostrStore = useNostrStore()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="container max-w-4xl mx-auto py-8 px-4 sm:px-6 lg:px-8">
|
<div class="container max-w-4xl mx-auto h-[calc(100vh-4rem)] py-4 px-4 sm:px-6 lg:px-8">
|
||||||
<div class="space-y-6">
|
<div class="h-full">
|
||||||
<div class="flex flex-col space-y-1.5">
|
<div class="h-full animate-in fade-in-50 slide-in-from-bottom-3">
|
||||||
<h2 class="text-2xl font-semibold tracking-tight">Customer Support</h2>
|
|
||||||
<p class="text-sm text-muted-foreground">
|
|
||||||
Chat with our support team. We're here to help!
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="animate-in fade-in-50 slide-in-from-bottom-3">
|
|
||||||
<Login v-if="!nostrStore.isLoggedIn" />
|
<Login v-if="!nostrStore.isLoggedIn" />
|
||||||
<SupportChat v-else />
|
<SupportChat v-else />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -40,12 +33,22 @@ const nostrStore = useNostrStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fade-in-50 {
|
@keyframes fade-in-50 {
|
||||||
from { opacity: 0; }
|
from {
|
||||||
to { opacity: 1; }
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slide-in-from-bottom-3 {
|
@keyframes slide-in-from-bottom-3 {
|
||||||
from { transform: translateY(3px); }
|
from {
|
||||||
to { transform: translateY(0); }
|
transform: translateY(3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -194,7 +194,7 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
activeChat.value = null
|
activeChat.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addMessage(pubkey: string, message: DirectMessage) {
|
const addMessage = async (pubkey: string, message: DirectMessage) => {
|
||||||
// Skip if we've already processed this message
|
// Skip if we've already processed this message
|
||||||
if (processedMessageIds.value.has(message.id)) {
|
if (processedMessageIds.value.has(message.id)) {
|
||||||
return
|
return
|
||||||
|
|
@ -206,6 +206,11 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
// Add message to the map
|
// Add message to the map
|
||||||
const userMessages = messages.value.get(pubkey) || []
|
const userMessages = messages.value.get(pubkey) || []
|
||||||
messages.value.set(pubkey, [...userMessages, message])
|
messages.value.set(pubkey, [...userMessages, message])
|
||||||
|
|
||||||
|
// Sort messages by timestamp
|
||||||
|
const sortedMessages = messages.value.get(pubkey) || []
|
||||||
|
sortedMessages.sort((a, b) => a.created_at - b.created_at)
|
||||||
|
messages.value.set(pubkey, sortedMessages)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendMessage(to: string, content: string) {
|
async function sendMessage(to: string, content: string) {
|
||||||
|
|
@ -240,7 +245,7 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
await publishEvent(event, account.value.relays)
|
await publishEvent(event, account.value.relays)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function subscribeToMessages() {
|
const subscribeToMessages = async () => {
|
||||||
if (!account.value) return
|
if (!account.value) return
|
||||||
|
|
||||||
// Filter for received messages with history
|
// Filter for received messages with history
|
||||||
|
|
@ -254,14 +259,11 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
const sentFilter = {
|
const sentFilter = {
|
||||||
kinds: [4],
|
kinds: [4],
|
||||||
authors: [account.value.pubkey],
|
authors: [account.value.pubkey],
|
||||||
'#p': [SUPPORT_NPUB],
|
|
||||||
since: 0 // Get all historical messages
|
since: 0 // Get all historical messages
|
||||||
}
|
}
|
||||||
|
|
||||||
const subscribeToRelay = (relay: any) => {
|
const subscribeToRelay = (relay: any) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let receivedCount = 0
|
|
||||||
let sentCount = 0
|
|
||||||
let eoseCount = 0
|
let eoseCount = 0
|
||||||
|
|
||||||
// Subscribe to received messages
|
// Subscribe to received messages
|
||||||
|
|
@ -274,7 +276,6 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
receivedCount++
|
|
||||||
const decrypted = await window.NostrTools.nip04.decrypt(
|
const decrypted = await window.NostrTools.nip04.decrypt(
|
||||||
account.value!.privkey,
|
account.value!.privkey,
|
||||||
event.pubkey,
|
event.pubkey,
|
||||||
|
|
@ -310,22 +311,25 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sentCount++
|
// Find the target pubkey from the p tag
|
||||||
|
const targetPubkey = event.tags.find(tag => tag[0] === 'p')?.[1]
|
||||||
|
if (!targetPubkey) return
|
||||||
|
|
||||||
const decrypted = await window.NostrTools.nip04.decrypt(
|
const decrypted = await window.NostrTools.nip04.decrypt(
|
||||||
account.value!.privkey,
|
account.value!.privkey,
|
||||||
SUPPORT_NPUB,
|
targetPubkey,
|
||||||
event.content
|
event.content
|
||||||
)
|
)
|
||||||
|
|
||||||
const dm: DirectMessage = {
|
const dm: DirectMessage = {
|
||||||
id: event.id,
|
id: event.id,
|
||||||
pubkey: SUPPORT_NPUB,
|
pubkey: targetPubkey,
|
||||||
content: decrypted,
|
content: decrypted,
|
||||||
created_at: event.created_at,
|
created_at: event.created_at,
|
||||||
sent: true
|
sent: true
|
||||||
}
|
}
|
||||||
|
|
||||||
await addMessage(SUPPORT_NPUB, dm)
|
await addMessage(targetPubkey, dm)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to decrypt sent message:', err)
|
console.error('Failed to decrypt sent message:', err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue