Actions
Reactions code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/reactions.blade.php
@props([
'uuid' => null,
'uuidKey' => null,
])
@php
/*
| Emoji reaction pills with picker. Must live inside `<x-ui.comments>` so the
| parent Alpine scope exposes `reactionStates`, `toggleReaction`, and
| `togglePicker`.
|
| Pass `uuid` for server-rendered comments, or `uuidKey` for Alpine scope
| variables such as `comment.uuid` or `reply.uuid`.
|
| Usage:
| <x-ui.reactions :uuid="$comment->uuid" />
| <x-ui.reactions uuid-key="comment.uuid" />
*/
$emojis = \App\ReactionEmoji::values();
$resolvedKey = $uuidKey ?? "'{$uuid}'";
@endphp
<div {{ $attributes->merge(['class' => 'mt-2 flex flex-wrap items-center gap-1.5']) }}>
<template x-for="reaction in (reactionStates[{{ $resolvedKey }}] || [])" :key="reaction.emoji">
<button
type="button"
@click="toggleReaction({{ $resolvedKey }}, reaction.emoji)"
:class="reaction.reacted
? 'border-brand-200 bg-brand-50 text-brand-700 dark:border-brand-800 dark:bg-brand-950/40 dark:text-brand-300'
: 'border-gray-200 bg-gray-50 text-gray-600 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-300'"
class="inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium transition hover:border-brand-300 dark:hover:border-brand-700"
:aria-pressed="reaction.reacted.toString()"
>
<span x-text="reaction.emoji" aria-hidden="true"></span>
<span x-text="reaction.count"></span>
</button>
</template>
<div class="relative">
<button
type="button"
@click="togglePicker({{ $resolvedKey }})"
class="inline-flex h-7 w-7 items-center justify-center rounded-full border border-gray-200 bg-gray-50 text-gray-500 transition hover:border-brand-300 hover:text-brand-600 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-400 dark:hover:border-brand-700 dark:hover:text-brand-400"
aria-label="Add reaction"
>
<x-ui.icon name="smiley" weight="bold" size="sm" />
</button>
<div
x-show="pickerOpenFor === {{ $resolvedKey }}"
x-cloak
@click.outside="pickerOpenFor = null"
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="absolute z-10 mt-1 flex gap-0.5 rounded-xl border border-gray-200 bg-white p-1 shadow-lg ring-1 ring-black/5 dark:border-gray-800 dark:bg-gray-900"
>
@foreach ($emojis as $emoji)
<button
type="button"
@click="toggleReaction({{ $resolvedKey }}, @js($emoji)); pickerOpenFor = null"
class="flex h-8 w-8 items-center justify-center rounded-lg text-base transition hover:bg-gray-100 dark:hover:bg-gray-800"
aria-label="React with {{ $emoji }}"
>{{ $emoji }}</button>
@endforeach
</div>
</div>
</div>