import { DeesElement, property, html, customElement, type TemplateResult, cssManager, css, unsafeCSS, state, } from '@design.estate/dees-element'; // Import design tokens import { colors, bdTheme } from './00colors.js'; import { spacing, radius, shadows, transitions } from './00tokens.js'; import { fontFamilies, typography } from './00fonts.js'; // Types export interface IMessage { id: string; text: string; sender: 'user' | 'support'; time: string; status?: 'sending' | 'sent' | 'delivered' | 'read'; } export interface IConversationData { id: string; title: string; messages: IMessage[]; } declare global { interface HTMLElementTagNameMap { 'sio-conversation-view': SioConversationView; } } @customElement('sio-conversation-view') export class SioConversationView extends DeesElement { public static demo = () => html` `; @property({ type: Object }) public conversation: IConversationData | null = null; @state() private messageText: string = ''; @state() private isTyping: boolean = false; public static styles = [ cssManager.defaultStyles, css` :host { display: flex; flex-direction: column; height: 100%; background: ${bdTheme('background')}; font-family: ${unsafeCSS(fontFamilies.sans)}; } .header { padding: ${unsafeCSS(spacing["4"])}; border-bottom: 1px solid ${bdTheme('border')}; background: ${bdTheme('background')}; display: flex; align-items: center; gap: ${unsafeCSS(spacing["3"])}; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); position: sticky; top: 0; z-index: 10; } .back-button { display: none; } @media (max-width: 600px) { .back-button { display: block; } } .header-title { font-size: 1.125rem; line-height: 1.5; font-weight: 600; margin: 0; color: ${bdTheme('foreground')}; flex: 1; } .header-actions { display: flex; gap: ${unsafeCSS(spacing["2"])}; } .messages-container { flex: 1; overflow-y: auto; padding: ${unsafeCSS(spacing["4"])}; display: flex; flex-direction: column; gap: ${unsafeCSS(spacing["3"])}; } .message { display: flex; align-items: flex-start; gap: ${unsafeCSS(spacing["3"])}; max-width: 70%; } .message.user { align-self: flex-end; flex-direction: row-reverse; } .message-bubble { padding: ${unsafeCSS(spacing["2.5"])} ${unsafeCSS(spacing["3.5"])}; border-radius: ${unsafeCSS(radius["2xl"])}; font-size: 0.9375rem; line-height: 1.6; position: relative; box-shadow: ${unsafeCSS(shadows.sm)}; max-width: 100%; word-wrap: break-word; } .message.support .message-bubble { background: ${bdTheme('secondary')}; color: ${bdTheme('secondaryForeground')}; border-bottom-left-radius: ${unsafeCSS(spacing["1"])}; border: 1px solid ${bdTheme('border')}; } .message.user .message-bubble { background: ${bdTheme('primary')}; color: ${bdTheme('primaryForeground')}; border-bottom-right-radius: ${unsafeCSS(spacing["1"])}; } .message-time { font-size: 0.75rem; line-height: 1.5; color: ${bdTheme('mutedForeground')}; margin-top: ${unsafeCSS(spacing["1"])}; } .message.user .message-time { text-align: right; } .typing-indicator { display: flex; align-items: center; gap: ${unsafeCSS(spacing["1"])}; padding: ${unsafeCSS(spacing["2"])} ${unsafeCSS(spacing["3"])}; background: ${bdTheme('muted')}; border-radius: ${unsafeCSS(radius.lg)}; width: fit-content; } .typing-dot { width: 8px; height: 8px; background: ${bdTheme('mutedForeground')}; border-radius: 50%; animation: typing 1.4s infinite; } .typing-dot:nth-child(2) { animation-delay: 0.2s; } .typing-dot:nth-child(3) { animation-delay: 0.4s; } @keyframes typing { 0%, 60%, 100% { opacity: 0.3; transform: scale(0.8); } 30% { opacity: 1; transform: scale(1); } } .input-container { padding: ${unsafeCSS(spacing["4"])}; border-top: 1px solid ${bdTheme('border')}; background: ${bdTheme('background')}; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); } .input-wrapper { display: flex; gap: ${unsafeCSS(spacing["2"])}; align-items: flex-end; } .message-input { flex: 1; min-height: 42px; max-height: 120px; padding: ${unsafeCSS(spacing["2.5"])} ${unsafeCSS(spacing[3])}; background: ${bdTheme('secondary')}; border: 1px solid ${bdTheme('border')}; border-radius: ${unsafeCSS(radius.xl)}; font-size: 0.9375rem; color: ${bdTheme('foreground')}; outline: none; resize: none; font-family: ${unsafeCSS(fontFamilies.sans)}; line-height: 1.5; transition: ${unsafeCSS(transitions.all)}; } .message-input::placeholder { color: ${bdTheme('mutedForeground')}; font-size: 0.875rem; } .message-input:focus { border-color: ${bdTheme('ring')}; background: ${bdTheme('background')}; box-shadow: 0 0 0 3px ${bdTheme('ring')}15; } .input-actions { display: flex; gap: ${unsafeCSS(spacing["1"])}; } .empty-state { flex: 1; display: flex; align-items: center; justify-content: center; flex-direction: column; gap: ${unsafeCSS(spacing["4"])}; padding: ${unsafeCSS(spacing["8"])}; text-align: center; color: ${bdTheme('mutedForeground')}; animation: fadeIn 500ms ease-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .empty-icon { font-size: 64px; opacity: 0.5; } /* Scrollbar styling */ .messages-container::-webkit-scrollbar { width: 6px; } .messages-container::-webkit-scrollbar-track { background: transparent; } .messages-container::-webkit-scrollbar-thumb { background: ${bdTheme('border')}; border-radius: 3px; } .messages-container::-webkit-scrollbar-thumb:hover { background: ${bdTheme('mutedForeground')}; } `, ]; public render(): TemplateResult { if (!this.conversation) { return html`

Select a conversation

Choose a conversation from the sidebar to start messaging

`; } return html`

${this.conversation.title}

${this.conversation.messages.map(msg => html`
${msg.text}
${msg.time}
`)} ${this.isTyping ? html`
` : ''}
`; } private handleBack() { this.dispatchEvent(new CustomEvent('back', { bubbles: true, composed: true })); } private handleInput(e: Event) { const textarea = e.target as HTMLTextAreaElement; this.messageText = textarea.value; // Auto-resize textarea textarea.style.height = 'auto'; textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px'; } private handleKeyDown(e: KeyboardEvent) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); this.sendMessage(); } } private sendMessage() { if (!this.messageText.trim()) return; const message: IMessage = { id: Date.now().toString(), text: this.messageText.trim(), sender: 'user', time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), status: 'sending' }; // Dispatch event for parent to handle this.dispatchEvent(new CustomEvent('send-message', { detail: { message }, bubbles: true, composed: true })); // Clear input this.messageText = ''; const textarea = this.shadowRoot?.querySelector('.message-input') as HTMLTextAreaElement; if (textarea) { textarea.style.height = 'auto'; } // Simulate typing indicator (remove in production) setTimeout(() => { this.isTyping = true; setTimeout(() => { this.isTyping = false; }, 2000); }, 1000); } public updated() { // Scroll to bottom when new messages arrive const container = this.shadowRoot?.querySelector('#messages'); if (container) { container.scrollTop = container.scrollHeight; } } }