Snapshot of main at 9f39a6e1e (2026-11-02)
This commit is contained in:
commit
6ccf1792d7
2580 files changed
+1040202
No files matched your search
@@ -0,0 +1,57 @@
|
||||
@use('Namu\WireChat\Facades\WireChat')
|
||||
<div x-data="{ selectedConversationId: '{{ request()->conversation ?? $selectedConversationId }}' }"
|
||||
x-on:open-chat.window="selectedConversationId= $event.detail.conversation; $wire.selectedConversationId= $event.detail.conversation;"
|
||||
x-init=" setTimeout(() => {
|
||||
conversationElement = document.getElementById('conversation-' + selectedConversationId);
|
||||
|
||||
// Scroll to the conversation element
|
||||
if (conversationElement) {
|
||||
conversationElement.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}, 200);"
|
||||
class="flex flex-col bg-[var(--wc-light-primary)] dark:bg-[var(--wc-dark-primary)] transition-all h-full overflow-hidden w-full sm:p-3">
|
||||
|
||||
@php
|
||||
/* Show header if any of these conditions are true */
|
||||
$showHeader = $showNewChatModalButton || $allowChatsSearch || $showHomeRouteButton || !empty($title);
|
||||
@endphp
|
||||
|
||||
{{-- include header --}}
|
||||
@includeWhen($showHeader, 'wirechat::livewire.chats.partials.header')
|
||||
|
||||
<main x-data
|
||||
@scroll.self.debounce="
|
||||
{{-- Detect when scrolled to the bottom --}}
|
||||
// Calculate scroll values
|
||||
scrollTop = $el.scrollTop;
|
||||
scrollHeight = $el.scrollHeight;
|
||||
clientHeight = $el.clientHeight;
|
||||
|
||||
// Check if the user is at the bottom of the scrollable element
|
||||
if ((scrollTop + clientHeight) >= (scrollHeight - 1) && $wire.canLoadMore) {
|
||||
// Trigger load more if we're at the bottom
|
||||
await $nextTick();
|
||||
$wire.loadMore();
|
||||
}
|
||||
"
|
||||
class=" overflow-y-auto py-2 grow h-full relative " style="contain:content">
|
||||
|
||||
{{-- loading indicator --}}
|
||||
|
||||
@if (count($conversations) > 0)
|
||||
{{-- include list item --}}
|
||||
@include('wirechat::livewire.chats.partials.list')
|
||||
|
||||
|
||||
{{-- include load more if true --}}
|
||||
@includeWhen($canLoadMore, 'wirechat::livewire.chats.partials.load-more-button')
|
||||
@else
|
||||
<div class="w-full flex items-center h-full justify-center">
|
||||
<h6 class=" font-bold text-gray-700 dark:text-white">{{ __('wirechat::chats.labels.no_conversations_yet') }}</h6>
|
||||
</div>
|
||||
@endif
|
||||
</main>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
@use('Namu\WireChat\Facades\WireChat')
|
||||
|
||||
<header class="px-3 z-10 sticky top-0 w-full py-2 " dusk="header">
|
||||
|
||||
|
||||
{{-- Title/name and Icon --}}
|
||||
<section class="flex flex-col pb-2">
|
||||
|
||||
@if (isset($title))
|
||||
<div class="flex items-center gap-2 truncate" wire:ignore>
|
||||
<h2 class="text-2xl font-bold dark:text-white" dusk="title">{{$title}}</h2>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($showNewChatModalButton)
|
||||
<div class="mt-2">
|
||||
<x-wirechat::actions.new-chat widget="{{$this->isWidget()}}">
|
||||
@if ($title === '')
|
||||
<x-jetstream.button id="open-new-chat-modal-button" type="button">
|
||||
{{ __('wirechat::new.chat.labels.heading') }}
|
||||
</x-jetstream.button>
|
||||
@else
|
||||
<x-jetstream.secondary-button id="open-new-chat-modal-button" type="button">
|
||||
{{ __('wirechat::new.chat.labels.heading') }}
|
||||
</x-jetstream.secondary-button>
|
||||
@endif
|
||||
</x-wirechat::actions.new-chat>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</section>
|
||||
|
||||
{{-- Search input --}}
|
||||
@if ($allowChatsSearch)
|
||||
<section class="mt-4">
|
||||
<div class="px-2 rounded-lg dark:bg-[var(--wc-dark-secondary)] bg-[var(--wc-light-secondary)] grid grid-cols-12 items-center">
|
||||
|
||||
<label for="chats-search-field" class="col-span-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" class="size-5 w-5 h-5 dark:text-gray-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||
</svg>
|
||||
</label>
|
||||
|
||||
<input id="chats-search-field"
|
||||
name="chats_search"
|
||||
maxlength="100"
|
||||
type="search"
|
||||
wire:model.live.debounce='search'
|
||||
placeholder="{{ __('wirechat::chats.inputs.search.placeholder') }}"
|
||||
autocomplete="off"
|
||||
@click.stop
|
||||
class="col-span-11 border-0 bg-inherit dark:text-white outline-hidden w-full focus:outline-hidden focus:ring-0 hover:ring-0">
|
||||
</div>
|
||||
|
||||
</section>
|
||||
@endif
|
||||
|
||||
</header>
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
@use('Namu\WireChat\Facades\WireChat')
|
||||
|
||||
<ul wire:loading.delay.long.remove wire:target="search" class="p-2 grid w-full spacey-y-2">
|
||||
@foreach ($conversations as $key=> $conversation)
|
||||
@php
|
||||
//$receiver =$conversation->getReceiver();
|
||||
$group = $conversation->isGroup() ? $conversation->group : null;
|
||||
$receiver = $conversation->isGroup() ? null : ($conversation->isPrivate() ? $conversation->peer_participant?->participantable : $this->auth);
|
||||
//$receiver = $conversation->isGroup() ? null : ($conversation->isPrivate() ? $conversation->peerParticipant()?->participantable : $this->auth);
|
||||
$lastMessage = $conversation->lastMessage;
|
||||
//mark isReadByAuth true if user has chat opened
|
||||
$isReadByAuth = $conversation?->readBy($conversation->auth_participant??$this->auth) || $selectedConversationId == $conversation->id;
|
||||
$belongsToAuth = $lastMessage?->belongsToAuth();
|
||||
|
||||
@endphp
|
||||
|
||||
<li x-data="{
|
||||
conversationID: @js($conversation->id),
|
||||
showUnreadStatus: @js(!$isReadByAuth),
|
||||
handleChatOpened(event) {
|
||||
// Hide unread dot
|
||||
if (event.detail.conversation== this.conversationID) {
|
||||
this.showUnreadStatus= false;
|
||||
}
|
||||
//update this so that the the selected conversation highlighter can be updated
|
||||
$wire.selectedConversationId= event.detail.conversation;
|
||||
},
|
||||
handleChatClosed(event) {
|
||||
// Clear the globally selected conversation.
|
||||
$wire.selectedConversationId = null;
|
||||
selectedConversationId = null;
|
||||
},
|
||||
handleOpenChat(event) {
|
||||
// Clear the globally selected conversation.
|
||||
if (this.showUnreadStatus== event.detail.conversation== this.conversationID) {
|
||||
this.showUnreadStatus= false;
|
||||
}
|
||||
}
|
||||
}"
|
||||
|
||||
id="conversation-{{ $conversation->id }}"
|
||||
wire:key="conversation-em-{{ $conversation->id }}-{{ $conversation->updated_at->timestamp }}"
|
||||
x-on:chat-opened.window="handleChatOpened($event)"
|
||||
x-on:chat-closed.window="handleChatClosed($event)">
|
||||
<a @if ($widget) tabindex="0"
|
||||
role="button"
|
||||
dusk="openChatWidgetButton"
|
||||
@click="$dispatch('open-chat',{conversation:@js($conversation->id)})"
|
||||
@keydown.enter="$dispatch('open-chat',{conversation:@js($conversation->id)})"
|
||||
@else
|
||||
wire:navigate href="{{ route(WireChat::viewRouteName(), $conversation->id) }}" @endif
|
||||
@style(['border-color:var(--wc-brand-primary)' => $selectedConversationId == $conversation?->id])
|
||||
class="py-3 flex gap-4 dark:hover:bg-[var(--wc-dark-secondary)] hover:bg-[var(--wc-light-secondary)] rounded-xs transition-colors duration-150 relative w-full cursor-pointer px-2"
|
||||
:class="$wire.selectedConversationId == conversationID &&
|
||||
'rounded-md dark:bg-[var(--wc-dark-secondary)] bg-[var(--wc-light-secondary)] border-[var(--wc-brand-primary)]'">
|
||||
|
||||
<div class="shrink-0">
|
||||
<x-wirechat::avatar group="{{ $conversation->isGroup() }}"
|
||||
:src="$group ? $group?->cover_url : $receiver?->cover_url ?? null" class="w-12 h-12" />
|
||||
</div>
|
||||
|
||||
<aside class="grid grid-cols-12 w-full">
|
||||
<div
|
||||
class="col-span-10 pb-2 relative overflow-hidden truncate leading-5 w-full flex-nowrap p-1">
|
||||
|
||||
{{-- name --}}
|
||||
<div class="flex gap-1 mb-1 w-full items-center">
|
||||
<h6 class="truncate font-medium text-gray-900 dark:text-white">
|
||||
{{ $group ? $group?->name : $receiver?->display_name }}
|
||||
</h6>
|
||||
|
||||
@if ($conversation->isSelfConversation())
|
||||
<span class="font-medium dark:text-white">({{__('wirechat::chats.labels.you') }})</span>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Message body --}}
|
||||
@if ($lastMessage != null)
|
||||
@include('wirechat::livewire.chats.partials.message-body')
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Read status --}}
|
||||
{{-- Only show if AUTH is NOT onwer of message --}}
|
||||
@if ($lastMessage != null && !$lastMessage?->ownedBy($this->auth) && !$isReadByAuth)
|
||||
<div x-show="showUnreadStatus" dusk="unreadMessagesDot" class=" col-span-2 flex flex-col text-center my-auto">
|
||||
{{-- Dots icon --}}
|
||||
<span dusk="unreadDotItem" class="sr-only">unread dot</span>
|
||||
{{-- 1. Remove the @style directive and change the class --}}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
|
||||
fill="#b91c1c" class="bi bi-dot w-10 h-10 text-gray-700" viewBox="0 0 16 16">
|
||||
<path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z" />
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</aside>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@endforeach
|
||||
|
||||
</ul>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<section wire:loading.remove wire:target="search" class="w-full justify-center flex my-3 ">
|
||||
<button wire:loading.remove wire:target="loadMore" wire:loading.attr="disabled"
|
||||
dusk="loadMoreButton" @click="$wire.loadMore()"
|
||||
class=" text-sm dark:text-white disabled:hover:cursor-not-allowed hover:text-gray-700 transition-colors dark:hover:text-gray-500 dark:gray-200">
|
||||
@lang('wirechat::chats.labels.load_more')
|
||||
</button>
|
||||
|
||||
<div wire:loading wire:target="loadMore">
|
||||
<x-wirechat::loading-spin />
|
||||
</div>
|
||||
</section>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
|
||||
<div x-cloak wire:loading.delay.class.remove="hidden"
|
||||
wire:target="search"class="hidden transition-all duration-300 ">
|
||||
<x-wirechat::loading-spin />
|
||||
</div>
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<div class="flex gap-x-2 items-center">
|
||||
|
||||
{{-- Only show if AUTH is onwer of message --}}
|
||||
@if ($lastMessage?->ownedBy($this->auth))
|
||||
<span class="font-bold text-xs dark:text-white/90 dark:font-normal">
|
||||
@lang('wirechat::chats.labels.you'):
|
||||
</span>
|
||||
@elseif(!$lastMessage?->ownedBy($this->auth) && $group !== null)
|
||||
<span class="font-bold text-xs dark:text-white/80 dark:font-normal">
|
||||
{{ $lastMessage->sendable?->display_name }}:
|
||||
</span>
|
||||
@endif
|
||||
|
||||
<p @class([
|
||||
'truncate text-sm dark:text-white gap-2 items-center',
|
||||
'font-semibold text-black' =>
|
||||
!$isReadByAuth && !$lastMessage?->ownedBy($this->auth),
|
||||
'font-normal text-gray-600' =>
|
||||
$isReadByAuth && !$lastMessage?->ownedBy($this->auth),
|
||||
'font-normal text-gray-600' =>
|
||||
$isReadByAuth && $lastMessage?->ownedBy($this->auth),
|
||||
])>
|
||||
{{ $lastMessage->body != '' ? $lastMessage->body : ($lastMessage->isAttachment() ? '📎 '.__('wirechat::chats.labels.attachment') : '') }}
|
||||
</p>
|
||||
|
||||
<span class="font-medium px-1 text-xs shrink-0 text-gray-800 dark:text-gray-50">
|
||||
@if ((int) ($lastMessage->created_at->diffInMinutes(now(), true)) < 1)
|
||||
@lang('wirechat::chats.labels.now')
|
||||
@else
|
||||
{{ $lastMessage->created_at->shortAbsoluteDiffForHumans() }}
|
||||
@endif
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
Reference in new issue
Block a user