316 lines
22 KiB
PHP
316 lines
22 KiB
PHP
<div class="bg-gray-100/50 backdrop-blur-sm border border-gray-700/50 rounded-xl shadow-xl">
|
|
<div class="p-8">
|
|
<h3 class="text-2xl font-bold bg-gradient-to-r from-white to-gray-300 bg-clip-text mb-8 flex items-center">
|
|
<i class="ri-chat-3-line mr-3"></i>
|
|
Comments <span class="ml-2 px-3 py-1 bg-gradient-to-r from-blue-600/20 to-purple-600/20 border border-blue-500/30 rounded-full text-sm">{{ $comments->count() }}</span>
|
|
</h3>
|
|
|
|
<!-- New Comment Form -->
|
|
@if($canComment)
|
|
<div class="mb-8 border-b border-gray-700/50 pb-8">
|
|
<div class="flex space-x-4">
|
|
@php
|
|
$currentAvatar = $currentUserProfile ? $currentUserProfile->avatar_url : auth()->user()->avatar;
|
|
$currentName = $currentUserProfile ? $currentUserProfile->display_name : auth()->user()->name;
|
|
@endphp
|
|
<div class="w-12 h-12 rounded-full ring-4 ring-blue-500/20 overflow-hidden flex-shrink-0">
|
|
<img src="{{ $currentAvatar }}"
|
|
alt="{{ $currentName }}"
|
|
class="w-full h-full object-cover">
|
|
</div>
|
|
<div class="flex-1">
|
|
<textarea
|
|
wire:model="newComment"
|
|
placeholder="Write a comment..."
|
|
class="w-full p-4 border border-gray-600/50 bg-gray-700/50 text-white placeholder-gray-400 rounded-xl resize-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200"
|
|
rows="3"
|
|
></textarea>
|
|
@error('newComment')
|
|
<span class="text-red-400 text-sm font-medium mt-2 block"><i class="ri-error-warning-line mr-1"></i>{{ $message }}</span>
|
|
@enderror
|
|
<div class="flex justify-end mt-3">
|
|
<button
|
|
wire:click="submitComment"
|
|
class="bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white px-6 py-3 rounded-xl font-semibold transition-all duration-300 hover:scale-105 shadow-lg shadow-blue-500/25 disabled:opacity-50 inline-flex items-center"
|
|
wire:loading.attr="disabled"
|
|
>
|
|
<span wire:loading.remove><i class="ri-send-plane-line mr-2"></i>Post Comment</span>
|
|
<span wire:loading><i class="ri-loader-4-line mr-2 animate-spin"></i>Posting...</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Comments List -->
|
|
<div class="space-y-6">
|
|
@forelse($comments as $comment)
|
|
@php
|
|
$commentProfile = $profiles->get($comment->user_id);
|
|
$commentAvatar = $commentProfile ? $commentProfile->avatar_url : $comment->user->avatar;
|
|
$commentName = $commentProfile ? $commentProfile->display_name : $comment->user->name;
|
|
@endphp
|
|
<div class="flex space-x-4">
|
|
<div class="w-12 h-12 rounded-full ring-4 ring-gray-600/30 overflow-hidden flex-shrink-0">
|
|
<img src="{{ $commentAvatar }}"
|
|
alt="{{ $commentName }}"
|
|
class="w-full h-full object-cover">
|
|
</div>
|
|
<div class="flex-1">
|
|
<div class="bg-gray-700/40 border border-gray-600/50 rounded-xl p-5">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<div class="flex items-center space-x-2">
|
|
<span class="font-semibold text-white">{{ $commentName }}</span>
|
|
<span class="text-sm text-gray-400">•</span>
|
|
<span class="text-sm text-gray-400">{{ $comment->formatted_date }}</span>
|
|
@if($comment->is_edited)
|
|
<span class="text-xs text-gray-500 italic">(edited)</span>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2">
|
|
@if($comment->canEdit(auth()->user()))
|
|
<button
|
|
wire:click="startEdit({{ $comment->id }})"
|
|
class="text-blue-400 hover:text-blue-300 transition-colors"
|
|
title="Edit comment"
|
|
>
|
|
<i class="ri-edit-line text-lg"></i>
|
|
</button>
|
|
@endif
|
|
|
|
@if($comment->canBeDeletedBy(auth()->user()))
|
|
<button
|
|
wire:click="deleteComment({{ $comment->id }})"
|
|
wire:confirm="Are you sure you want to delete this comment?"
|
|
class="text-red-400 hover:text-red-300 transition-colors"
|
|
title="Delete comment"
|
|
>
|
|
<i class="ri-delete-bin-line text-lg"></i>
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
@if($editingComment === $comment->id)
|
|
<!-- Edit Form -->
|
|
<div class="mt-3">
|
|
<textarea
|
|
wire:model="editContent"
|
|
class="w-full p-3 border border-gray-600/50 bg-gray-700/50 text-white rounded-xl resize-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
rows="3"
|
|
></textarea>
|
|
@error('editContent')
|
|
<span class="text-red-400 text-sm font-medium mt-2 block"><i class="ri-error-warning-line mr-1"></i>{{ $message }}</span>
|
|
@enderror
|
|
<div class="flex justify-end gap-3 mt-3">
|
|
<button
|
|
wire:click="cancelEdit"
|
|
class="text-gray-400 hover:text-gray-200 px-4 py-2 text-sm font-medium transition-colors"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
wire:click="saveEdit"
|
|
class="bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white px-4 py-2 rounded-xl text-sm font-semibold transition-all duration-300 hover:scale-105 disabled:opacity-50"
|
|
wire:loading.attr="disabled"
|
|
>
|
|
<span wire:loading.remove><i class="ri-save-line mr-1"></i>Save</span>
|
|
<span wire:loading><i class="ri-loader-4-line mr-1 animate-spin"></i>Saving...</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
@else
|
|
<p class="text-gray-300 leading-relaxed">{{ $comment->content }}</p>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Reactions -->
|
|
@if(auth()->check())
|
|
<div class="flex items-center space-x-3 mt-3">
|
|
<div class="flex items-center gap-1 bg-gray-100/30 px-3 py-2 rounded-xl border border-gray-600/30">
|
|
@foreach(['like' => '👍', 'love' => '❤️', 'celebrate' => '🎉', 'fire' => '🔥', 'thinking' => '🤔'] as $type => $emoji)
|
|
<button
|
|
wire:click="toggleReaction({{ $comment->id }}, '{{ $type }}')"
|
|
class="text-xl hover:scale-125 transition-transform duration-200 {{ $comment->hasReactionFromUser(auth()->user(), $type) ? 'brightness-125 scale-110' : 'opacity-60 hover:opacity-100' }}"
|
|
title="{{ ucfirst($type) }}"
|
|
>
|
|
{{ $emoji }}
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
|
|
@if($comment->reaction_counts && array_sum($comment->reaction_counts) > 0)
|
|
<div class="flex items-center gap-2">
|
|
@php
|
|
$reactionEmojis = ['like' => '👍', 'love' => '❤️', 'celebrate' => '🎉', 'fire' => '🔥', 'thinking' => '🤔'];
|
|
@endphp
|
|
@foreach($comment->reaction_counts as $type => $count)
|
|
@if($count > 0)
|
|
<span class="bg-gradient-to-r from-blue-600/20 to-purple-600/20 border border-blue-500/30 px-3 py-1 rounded-full text-xs font-semibold text-blue-300">
|
|
{{ $reactionEmojis[$type] ?? '👍' }} {{ $count }}
|
|
</span>
|
|
@endif
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Comment Actions -->
|
|
<div class="flex items-center space-x-4 mt-3">
|
|
@if($canComment)
|
|
<button
|
|
wire:click="startReply({{ $comment->id }})"
|
|
class="text-blue-400 hover:text-blue-300 text-sm font-medium transition-colors"
|
|
>
|
|
<i class="ri-reply-line mr-1"></i>Reply
|
|
</button>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Reply Form -->
|
|
@if($replyingTo === $comment->id)
|
|
<div class="mt-4 ml-6">
|
|
<div class="flex space-x-3">
|
|
<div class="w-10 h-10 rounded-full ring-4 ring-blue-500/20 overflow-hidden flex-shrink-0">
|
|
<img src="{{ auth()->user()->avatar ?? 'https://www.gravatar.com/avatar/' . md5(strtolower(trim(auth()->user()->email))) . '?d=identicon&s=32' }}"
|
|
alt="{{ auth()->user()->name }}"
|
|
class="w-full h-full object-cover">
|
|
</div>
|
|
<div class="flex-1">
|
|
<textarea
|
|
wire:model="replyContent"
|
|
placeholder="Write a reply..."
|
|
class="w-full p-3 border border-gray-600/50 bg-gray-700/50 text-white placeholder-gray-400 rounded-xl resize-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
rows="2"
|
|
></textarea>
|
|
@error('replyContent')
|
|
<span class="text-red-400 text-sm font-medium mt-2 block"><i class="ri-error-warning-line mr-1"></i>{{ $message }}</span>
|
|
@enderror
|
|
<div class="flex justify-end gap-3 mt-3">
|
|
<button
|
|
wire:click="cancelReply"
|
|
class="text-gray-400 hover:text-gray-200 px-3 py-2 text-sm font-medium"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
wire:click="submitReply"
|
|
class="bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white px-4 py-2 rounded-xl text-sm font-semibold transition-all duration-300 hover:scale-105 disabled:opacity-50"
|
|
wire:loading.attr="disabled"
|
|
>
|
|
<span wire:loading.remove><i class="ri-send-plane-line mr-1"></i>Reply</span>
|
|
<span wire:loading><i class="ri-loader-4-line mr-1 animate-spin"></i>Replying...</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Replies -->
|
|
@if($comment->replies->count() > 0)
|
|
<div class="ml-6 mt-4 space-y-4">
|
|
@foreach($comment->replies as $reply)
|
|
@php
|
|
$replyProfile = $profiles->get($reply->user_id);
|
|
$replyAvatar = $replyProfile ? $replyProfile->avatar_url : $reply->user->avatar;
|
|
$replyName = $replyProfile ? $replyProfile->display_name : $reply->user->name;
|
|
@endphp
|
|
<div class="flex space-x-3">
|
|
<div class="w-10 h-10 rounded-full ring-4 ring-gray-600/20 overflow-hidden flex-shrink-0">
|
|
<img src="{{ $replyAvatar }}"
|
|
alt="{{ $replyName }}"
|
|
class="w-full h-full object-cover">
|
|
</div>
|
|
<div class="flex-1">
|
|
<div class="bg-gray-700/30 border border-gray-600/40 rounded-xl p-4">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<div class="flex items-center space-x-2">
|
|
<span class="font-semibold text-white text-sm">{{ $replyName }}</span>
|
|
<span class="text-xs text-gray-400">•</span>
|
|
<span class="text-xs text-gray-400">{{ $reply->formatted_date }}</span>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2">
|
|
@if($reply->canEdit(auth()->user()))
|
|
<button
|
|
wire:click="startEdit({{ $reply->id }})"
|
|
class="text-blue-400 hover:text-blue-300 transition-colors"
|
|
title="Edit reply"
|
|
>
|
|
<i class="ri-edit-line"></i>
|
|
</button>
|
|
@endif
|
|
|
|
@if($reply->canBeDeletedBy(auth()->user()))
|
|
<button
|
|
wire:click="deleteComment({{ $reply->id }})"
|
|
wire:confirm="Are you sure you want to delete this reply?"
|
|
class="text-red-400 hover:text-red-300 transition-colors"
|
|
title="Delete reply"
|
|
>
|
|
<i class="ri-delete-bin-line"></i>
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
@if($editingComment === $reply->id)
|
|
<!-- Edit Form for Reply -->
|
|
<div class="mt-2">
|
|
<textarea
|
|
wire:model="editContent"
|
|
class="w-full p-2 border border-gray-600/50 bg-gray-700/50 text-white rounded-xl resize-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm"
|
|
rows="2"
|
|
></textarea>
|
|
@error('editContent')
|
|
<span class="text-red-400 text-xs mt-1 block"><i class="ri-error-warning-line mr-1"></i>{{ $message }}</span>
|
|
@enderror
|
|
<div class="flex justify-end gap-2 mt-2">
|
|
<button
|
|
wire:click="cancelEdit"
|
|
class="text-gray-400 hover:text-gray-200 px-3 py-1 text-xs font-medium"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
wire:click="saveEdit"
|
|
class="bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white px-3 py-1 rounded-lg text-xs font-semibold transition-all duration-300 disabled:opacity-50"
|
|
wire:loading.attr="disabled"
|
|
>
|
|
<span wire:loading.remove><i class="ri-save-line mr-1"></i>Save</span>
|
|
<span wire:loading><i class="ri-loader-4-line mr-1 animate-spin"></i>Saving...</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
@else
|
|
<p class="text-gray-300 text-sm leading-relaxed">{{ $reply->content }}</p>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div class="text-center py-16">
|
|
<div class="w-24 h-24 bg-gradient-to-r from-blue-500/20 to-purple-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
|
<i class="ri-chat-3-line text-5xl text-gray-400"></i>
|
|
</div>
|
|
<h3 class="text-2xl font-bold mb-2">No Comments Yet</h3>
|
|
@if($canComment)
|
|
<p class="text-gray-400">Be the first to leave a comment!</p>
|
|
@else
|
|
<p class="text-gray-400">No comments have been posted yet.</p>
|
|
@endif
|
|
</div>
|
|
@endforelse
|
|
</div>
|
|
</div>
|
|
</div>
|