326 lines
11 KiB
PHP
326 lines
11 KiB
PHP
{{-- Import helper function to use in chatbox --}}
|
|
@use('Namu\WireChat\Helpers\Helper')
|
|
@use('Namu\WireChat\Facades\WireChat')
|
|
|
|
@php
|
|
$primaryColor = WireChat::getColor();
|
|
@endphp
|
|
|
|
|
|
|
|
@assets
|
|
<style>
|
|
|
|
emoji-picker {
|
|
width: 100% !important;
|
|
height: 100%;
|
|
}
|
|
|
|
/* Emoji picker configuration */
|
|
emoji-picker {
|
|
--background: none !important;
|
|
--border-radius: 12px;
|
|
--input-border-color: rgb(229 229 229);
|
|
--input-padding: 0.45rem;
|
|
--outline-color: none;
|
|
--outline-size: 1px;
|
|
--num-columns: 8;
|
|
/* Mobile-first default */
|
|
--emoji-padding: 0.7rem;
|
|
--emoji-size: 1.5rem;
|
|
/* Smaller size for mobile */
|
|
--border-color: none;
|
|
--indicator-color: #9ca3af;
|
|
}
|
|
|
|
|
|
@media screen and (min-width: 600px) {
|
|
emoji-picker {
|
|
--num-columns: 10;
|
|
/* Increase columns for larger screens */
|
|
--emoji-size: 1.8rem;
|
|
/* Larger size for desktop */
|
|
}
|
|
}
|
|
|
|
@media screen and (min-width: 900px) {
|
|
emoji-picker {
|
|
--num-columns: 16;
|
|
/* Increase columns for larger screens */
|
|
--emoji-size: 1.9rem;
|
|
/* Larger size for desktop */
|
|
}
|
|
}
|
|
/* Dark mode using prefers-color-scheme */
|
|
@media (prefers-color-scheme: dark) {
|
|
emoji-picker {
|
|
--background: none !important;
|
|
--input-border-color: var(--wc-dark-border);
|
|
--outline-color: none;
|
|
--outline-size: 1px;
|
|
--border-color: none;
|
|
--input-font-color: white;
|
|
--indicator-color: var(--wc-dark-accent);
|
|
--button-hover-background: var(--wc-dark-accent);
|
|
}
|
|
}
|
|
|
|
|
|
/* Ensure dark mode takes precedence */
|
|
.dark emoji-picker {
|
|
--background: none !important;
|
|
--input-border-color: var(--wc-dark-border);
|
|
--outline-color: none;
|
|
--outline-size: 1px;
|
|
--border-color: none;
|
|
--input-font-color: white;
|
|
--indicator-color: var(--wc-dark-accent);
|
|
--button-hover-background: var(--wc-dark-accent);
|
|
}
|
|
</style>
|
|
|
|
@endassets
|
|
|
|
<div x-data="{
|
|
initializing: true,
|
|
conversationId:@js($conversation->id),
|
|
conversationElement: document.getElementById('conversation'),
|
|
loadEmojiPicker() {
|
|
if (!document.head.querySelector('script[src*=\'/js/vendor/emoji-picker-element/index.js\']')) {
|
|
// Clear old IndexedDB database that may have cached CDN data
|
|
if (window.indexedDB) {
|
|
indexedDB.deleteDatabase('emoji-picker-element');
|
|
}
|
|
|
|
let script = document.createElement('script');
|
|
script.type = 'module';
|
|
script.async = true; // Load asynchronously
|
|
// Add cache-busting parameter to force reload of updated files
|
|
script.src = '/js/vendor/emoji-picker-element/index.js?v=' + Date.now();
|
|
|
|
// After the script loads, configure all emoji pickers
|
|
script.onload = () => {
|
|
setTimeout(() => {
|
|
document.querySelectorAll('emoji-picker').forEach(picker => {
|
|
picker.dataSource = '/js/vendor/emoji-picker-element-data/en/emojibase/data.json';
|
|
});
|
|
}, 100);
|
|
};
|
|
|
|
document.head.appendChild(script);
|
|
}
|
|
},
|
|
get isWidget() {
|
|
|
|
return $wire.widget == true;
|
|
}
|
|
}"
|
|
|
|
x-init="setTimeout(() => {
|
|
|
|
requestAnimationFrame(() => {
|
|
initializing = false;
|
|
$wire.dispatch('focus-input-field');
|
|
loadEmojiPicker();
|
|
{{-- if (isWidget) { --}}
|
|
//NotifyListeners about chat opened
|
|
$wire.dispatch('chat-opened',{conversation:conversationId});
|
|
{{-- } --}}
|
|
});
|
|
}, 120);"
|
|
class="w-full transition bg-[var(--wc-light-primary)] dark:bg-[var(--wc-dark-primary)] overflow-hidden h-full relative" style="contain:content">
|
|
|
|
<div class=" flex flex-col grow h-full min-h-0 relative ">
|
|
{{-- ---------- --}}
|
|
{{-- --Header-- --}}
|
|
{{-- ---------- --}}
|
|
@include('wirechat::livewire.chat.partials.header', [ 'conversation' => $conversation, 'receiver' => $receiver])
|
|
{{-- ---------- --}}
|
|
{{-- -Body----- --}}
|
|
{{-- ---------- --}}
|
|
<div class="flex-1 min-h-0">
|
|
@include('wirechat::livewire.chat.partials.body', [ 'conversation' => $conversation, 'authParticipant' => $authParticipant, 'loadedMessages' => $loadedMessages, 'isPrivate' => $conversation->isPrivate(), 'isGroup' => $conversation->isGroup(), 'receiver' => $receiver])
|
|
</div>
|
|
{{-- ---------- --}}
|
|
{{-- -Footer--- --}}
|
|
{{-- ---------- --}}
|
|
<livewire:wire-chat.typing-indicator :conversation-id="$conversation->id" />
|
|
|
|
@include('wirechat::livewire.chat.partials.footer', [ 'conversation' => $conversation, 'authParticipant' => $authParticipant, 'media' => $media, 'files' => $files, 'replyMessage' => $replyMessage])
|
|
|
|
|
|
</div>
|
|
|
|
<livewire:wirechat.chat.drawer />
|
|
|
|
|
|
{{-- Add this script directly to your WireChat chat template --}}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
function setupWireChatTyping() {
|
|
const typingIndicators = document.querySelectorAll('.wirechat-typing-indicator');
|
|
|
|
if (typingIndicators.length === 0) {
|
|
return;
|
|
}
|
|
|
|
typingIndicators.forEach((indicator, index) => {
|
|
const wireId = indicator.getAttribute('wire:id');
|
|
|
|
if (!wireId) {
|
|
return;
|
|
}
|
|
|
|
// Find WireChat specific inputs
|
|
const messageInputs = document.querySelectorAll(
|
|
'input[wire\\:model*="message"], ' +
|
|
'textarea[wire\\:model*="message"], ' +
|
|
'input[placeholder*="message"], ' +
|
|
'textarea[placeholder*="message"], ' +
|
|
'input[placeholder*="Type"], ' +
|
|
'textarea[placeholder*="Type"]'
|
|
);
|
|
|
|
|
|
if (messageInputs.length === 0) {
|
|
messageInputs = document.querySelectorAll('input[type="text"], textarea');
|
|
}
|
|
|
|
let typingTimer;
|
|
let isTyping = false;
|
|
|
|
function startTyping() {
|
|
|
|
if (!isTyping) {
|
|
isTyping = true;
|
|
|
|
try {
|
|
const component = window.Livewire.find(wireId);
|
|
if (component && typeof component.call === 'function') {
|
|
|
|
component.call('startTyping');
|
|
} else {
|
|
}
|
|
} catch (e) {
|
|
}
|
|
} else {
|
|
}
|
|
|
|
// Reset timer
|
|
clearTimeout(typingTimer);
|
|
typingTimer = setTimeout(() => {
|
|
stopTyping();
|
|
}, 3000);
|
|
}
|
|
|
|
function stopTyping() {
|
|
if (isTyping) {
|
|
isTyping = false;
|
|
clearTimeout(typingTimer);
|
|
|
|
try {
|
|
const component = window.Livewire.find(wireId);
|
|
if (component && typeof component.call === 'function') {
|
|
component.call('stopTyping');
|
|
}
|
|
} catch (e) {
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add event listeners with improved logic
|
|
messageInputs.forEach((input, inputIndex) => {
|
|
const inputDesc = input.placeholder || input.getAttribute('wire:model') || `input-${inputIndex}`;
|
|
|
|
// Input event - most reliable for typing detection
|
|
input.addEventListener('input', function(e) {
|
|
startTyping();
|
|
});
|
|
|
|
// Keydown event - for immediate response
|
|
input.addEventListener('keydown', function(e) {
|
|
// Only log actual typing keys to reduce noise
|
|
if (e.key.length === 1 || e.key === 'Backspace' || e.key === 'Delete') {
|
|
startTyping();
|
|
} else if (e.key === 'Enter' && !e.shiftKey) {
|
|
stopTyping();
|
|
}
|
|
});
|
|
|
|
// Focus event - just for logging
|
|
input.addEventListener('focus', function() {
|
|
});
|
|
|
|
// Blur event - only stop if not typing recently
|
|
input.addEventListener('blur', function() {
|
|
// Add a small delay before stopping to prevent immediate stop
|
|
setTimeout(() => {
|
|
if (isTyping) {
|
|
stopTyping();
|
|
}
|
|
}, 100);
|
|
});
|
|
});
|
|
|
|
});
|
|
}
|
|
|
|
// Setup with delay to ensure Livewire is ready
|
|
setTimeout(setupWireChatTyping, 500);
|
|
|
|
// Re-setup on navigation
|
|
document.addEventListener('livewire:navigated', function() {
|
|
setTimeout(setupWireChatTyping, 500);
|
|
});
|
|
});
|
|
|
|
// Global test functions
|
|
window.testWireChatTyping = {
|
|
start: function() {
|
|
const indicators = document.querySelectorAll('.wirechat-typing-indicator');
|
|
indicators.forEach(indicator => {
|
|
const wireId = indicator.getAttribute('wire:id');
|
|
if (wireId) {
|
|
try {
|
|
const component = window.Livewire.find(wireId);
|
|
component.call('startTyping');
|
|
} catch (e) {
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
stop: function() {
|
|
const indicators = document.querySelectorAll('.wirechat-typing-indicator');
|
|
indicators.forEach(indicator => {
|
|
const wireId = indicator.getAttribute('wire:id');
|
|
if (wireId) {
|
|
try {
|
|
const component = window.Livewire.find(wireId);
|
|
component.call('stopTyping');
|
|
} catch (e) {
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
checkRedis: function() {
|
|
// This would need to be done server-side, but we can check component state
|
|
const indicators = document.querySelectorAll('.wirechat-typing-indicator');
|
|
indicators.forEach(indicator => {
|
|
const wireId = indicator.getAttribute('wire:id');
|
|
if (wireId) {
|
|
try {
|
|
const component = window.Livewire.find(wireId);
|
|
component.call('debug');
|
|
} catch (e) {
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
</script>
|
|
</div>
|