Initial commit

This commit is contained in:
Ronald Huynen
2026-03-23 21:37:59 +01:00
commit 2547717edb
2193 changed files with 972171 additions and 0 deletions

View File

@@ -0,0 +1,325 @@
{{-- 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>