功能:留言板新建留言改为弹窗形式,并新增用户选择下拉列表

- GuestbookController::index() 追加传入 $users 用户名列表
- 顶部内联展开表单改为居中 Modal 弹窗,带遮罩层和过渡动画
- 收件人从普通文本输入改为下拉选择器(含全部注册用户)
- 悄悄话改为 toggle 开关样式
- 增加顶级渐变色标题栏
This commit is contained in:
2026-02-27 02:02:38 +08:00
parent 6cb788b81f
commit fefa275771
2 changed files with 95 additions and 28 deletions

View File

@@ -58,7 +58,13 @@ class GuestbookController extends Controller
// 获取收件人默认值 (比如点击他人名片的"写私信"转跳过来)
$defaultTo = $request->input('to', '');
return view('guestbook.index', compact('messages', 'tab', 'defaultTo'));
// 获取所有用户名列表(供写信弹窗的收件人选择器使用)
$users = User::where('username', '!=', $user->username)
->orderBy('username')
->pluck('username');
return view('guestbook.index', compact('messages', 'tab', 'defaultTo', 'users'));
}
/**

View File

@@ -30,43 +30,102 @@
</div>
@endif
{{-- 写信/留言表单区 (Alpine 控制显隐) --}}
<div x-show="showWriteForm" x-collapse class="bg-indigo-50/50 border-b border-indigo-100 shadow-sm relative z-10">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<form action="{{ route('guestbook.store') }}" method="POST" class="space-y-4">
{{-- 弹窗遮罩层 --}}
<div x-show="showWriteForm" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4"
@click.self="showWriteForm = false" style="display: none;">
{{-- 对话框 --}}
<div x-show="showWriteForm" x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95" x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-150" x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="bg-white rounded-2xl shadow-2xl w-full max-w-xl overflow-hidden">
{{-- 弹窗头部 --}}
<div class="bg-gradient-to-r from-indigo-600 to-indigo-500 px-6 py-4 flex justify-between items-center">
<div class="flex items-center space-x-2">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z">
</path>
</svg>
<h3 class="text-white font-bold text-lg">撰写留言</h3>
</div>
<button @click="showWriteForm = false" class="text-white/70 hover:text-white transition">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12">
</path>
</svg>
</button>
</div>
{{-- 表单内容 --}}
<form action="{{ route('guestbook.store') }}" method="POST" class="p-6 space-y-5">
@csrf
<div class="flex items-center space-x-4">
<div class="flex-1">
<label class="block text-sm font-medium text-gray-700 mb-1">接收人 (留空或填"大家"表示公共留言)</label>
<input type="text" name="towho" x-model="towho" placeholder="系统自动处理"
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div class="flex items-center h-full pt-6">
<label
class="flex items-center space-x-2 text-sm text-gray-700 cursor-pointer bg-pink-50 px-3 py-2 rounded-md hover:bg-pink-100 transition border border-pink-100">
<input type="checkbox" name="secret" value="1"
class="rounded text-pink-500 focus:ring-pink-500 w-4 h-4">
<span class="font-bold text-pink-700">🔒 悄悄话 (仅双方可见)</span>
</label>
{{-- 收件人选择 --}}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">
📬 收件人
<span class="font-normal text-gray-400 ml-1">(留空则为公共留言)</span>
</label>
<div class="relative">
<select name="towho" x-model="towho"
class="w-full border-gray-200 rounded-xl py-2.5 px-4 focus:ring-indigo-500 focus:border-indigo-500 text-sm appearance-none bg-gray-50 pr-10">
<option value="">🌍 公共留言(所有人可见)</option>
@foreach ($users as $uname)
<option value="{{ $uname }}" :selected="towho === '{{ $uname }}'">👤
{{ $uname }}</option>
@endforeach
</select>
<div class="pointer-events-none absolute inset-y-0 right-3 flex items-center">
<svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div>
</div>
</div>
{{-- 您您话开关 --}}
<label class="flex items-center space-x-3 cursor-pointer group">
<div class="relative">
<input type="checkbox" name="secret" value="1" class="sr-only peer">
<div class="w-10 h-6 bg-gray-200 rounded-full peer-checked:bg-pink-500 transition-colors"></div>
<div
class="absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow transition-transform peer-checked:translate-x-4">
</div>
</div>
<span class="text-sm font-medium text-gray-700 group-hover:text-pink-600 transition-colors">🔒
您您话(仅双方可见)</span>
</label>
{{-- 正文 --}}
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">正文内容 <span
class="text-red-500">*</span></label>
<textarea name="text_body" x-ref="textBody" rows="3" required
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
<label class="block text-sm font-semibold text-gray-700 mb-2">
📝 留言内容 <span class="text-red-500">*</span>
</label>
<textarea name="text_body" x-ref="textBody" rows="5" required
class="w-full border-gray-200 rounded-xl p-4 focus:ring-indigo-500 focus:border-indigo-500 text-sm bg-gray-50 resize-none"
placeholder="相逢何必曾相识,留下您的足迹吧..."></textarea>
</div>
<div class="flex justify-end">
{{-- 操作按钮 --}}
<div class="flex justify-end space-x-3 pt-2">
<button type="button" @click="showWriteForm = false"
class="px-5 py-2.5 text-sm font-medium text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-xl transition">
取消
</button>
<button type="submit"
class="bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-6 rounded-md shadow flex items-center font-bold">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
class="px-6 py-2.5 text-sm font-bold text-white bg-indigo-600 hover:bg-indigo-700 rounded-xl shadow-md hover:shadow-lg transition-all transform hover:-translate-y-0.5 flex items-center">
<svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
</svg>
发送
发送飞鸽
</button>
</div>
</form>
@@ -166,7 +225,8 @@
<button
@click="showWriteForm = true; towho = '{{ $msg->who }}'; setTimeout(() => $refs.textBody.focus(), 100); window.scrollTo({top:0, behavior:'smooth'})"
class="text-xs text-indigo-500 hover:text-indigo-700 font-medium flex items-center transition">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6"></path>
</svg>
@@ -181,7 +241,8 @@
<span class="text-6xl drop-shadow-sm mb-6">📭</span>
<h3 class="text-xl font-bold text-gray-800 tracking-wide">暂无信件</h3>
<p class="mt-3 text-gray-400">这里是空空如也的荒原。</p>
<button @click="showWriteForm = true; towho = ''; setTimeout(() => $refs.textBody.focus(), 100)"
<button
@click="showWriteForm = true; towho = ''; setTimeout(() => $refs.textBody.focus(), 100)"
class="mt-8 bg-indigo-50 hover:bg-indigo-100 text-indigo-600 font-bold py-2.5 px-6 rounded-xl transition-colors border border-indigo-100/50">
来抢沙发留言吧!
</button>