diff --git a/resources/css/chat.css b/resources/css/chat.css new file mode 100644 index 0000000..c31f6d8 --- /dev/null +++ b/resources/css/chat.css @@ -0,0 +1,958 @@ +/** + * 文件功能:聊天室主界面样式表 + * 复刻原版海军蓝聊天室色系 (CHAT.CSS) + * 包含布局、消息窗格、输入工具栏、用户列表、弹窗等所有聊天界面样式 + * + * @author ChatRoom Laravel + * @version 1.0.0 + */ + +/* Alpine.js x-cloak:初始化完成前完全隐藏,防止弹窗闪烁 */ +[x-cloak] { + display: none !important; +} + +/* ═══════════════════════════════════════════════════ + 原版海军蓝聊天室色系 (CHAT.CSS 复刻) + ═══════════════════════════════════════════════════ */ +:root { + --bg-main: #EAF2FF; + --bg-bar: #b0d8ff; + --bg-header: #4488aa; + --bg-toolbar: #5599aa; + --text-link: #336699; + --text-navy: #112233; + --text-white: #ffffff; + --border-blue: #336699; + --scrollbar-base: #b0d8ff; + --scrollbar-arrow: #336699; + --scrollbar-track: #EAF2FF; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: "Microsoft YaHei", "SimSun", "宋体", sans-serif; + font-size: 10pt; + background: var(--bg-main); + color: var(--text-navy); + overflow: hidden; + height: 100vh; +} + +/* 全局链接样式 */ +a { + color: var(--text-link); + text-decoration: none; +} + +a:hover { + color: #009900; +} + +/* 自定义滚动条 - 模拟原版 */ +::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +::-webkit-scrollbar-thumb { + background-color: var(--scrollbar-base); + border-radius: 2px; + border: 1px solid var(--scrollbar-arrow); +} + +::-webkit-scrollbar-track { + background-color: var(--scrollbar-track); +} + +::-webkit-scrollbar-corner { + background-color: var(--scrollbar-base); +} + +/* ── 主布局 ─────────────────────────────────────── */ +.chat-layout { + display: flex; + height: 100vh; + width: 100vw; + overflow: hidden; + /* 防止整体滚动 */ +} + +/* 左侧主区域 */ +.chat-left { + flex: 1; + display: flex; + flex-direction: column; + min-width: 0; + min-height: 0; + /* 约束 Flex 子项高度,防止长历史记录撑破 100vh 导致输入栏被挤出屏幕 */ +} + +/* 竖向工具条 */ +.chat-toolbar { + width: 28px; + background: var(--bg-toolbar); + display: flex; + flex-direction: column; + align-items: center; + padding-top: 58px; + /* 与标题栏+公告栏底部对齐 */ + padding-bottom: 75px; + /* 与输入栏顶部对齐 */ + border-left: 1px solid var(--border-blue); + border-right: 1px solid var(--border-blue); + flex-shrink: 0; +} + +.chat-toolbar .tool-btn { + writing-mode: vertical-rl; + text-orientation: upright; + font-size: 11px; + color: #ddd; + cursor: pointer; + padding: 4px 0; + text-align: center; + transition: all 0.15s; + width: 100%; + flex: 1; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + letter-spacing: 2px; +} + +.chat-toolbar .tool-btn:hover { + color: #fff; + background: #5599cc; +} + +/* 右侧用户列表面板 */ +.chat-right { + width: 175px; + display: flex; + flex-direction: column; + border-left: 1px solid var(--border-blue); + background: var(--bg-main); + flex-shrink: 0; +} + +/* ── 标题栏 ─────────────────────────────────────── */ +.room-title-bar { + background: var(--bg-header); + color: var(--text-white); + text-align: center; + padding: 6px 10px; + font-size: 12px; + line-height: 1.6; + flex-shrink: 0; + border-bottom: 1px solid var(--border-blue); +} + +.room-title-bar .room-name { + font-weight: bold; + font-size: 14px; +} + +.room-title-bar .room-desc { + color: #cee8ff; + font-size: 11px; +} + +/* 公告/祝福语滚动条(复刻原版 marquee) */ +.room-announcement-bar { + background: linear-gradient(to right, #a8d8a8, #c8f0c8, #a8d8a8); + padding: 2px 6px; + border-bottom: 1px solid var(--border-blue); + flex-shrink: 0; + height: 20px; + line-height: 20px; + overflow: hidden; +} + +/* ── 消息窗格 ───────────────────────────────────── */ +.message-panes { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; +} + +.message-pane { + flex: 1; + overflow-y: auto; + padding: 5px 8px; + background: var(--bg-main); + font-size: 10pt; + line-height: 170%; + min-height: 0; +} + +.message-pane.say1 { + border-bottom: 2px solid var(--border-blue); +} + +.message-pane.say2 { + display: block; + flex: 0.4; + border-top: 2px solid var(--border-blue); +} + +.message-pane.say1 { + flex: 0.6; +} + + +/* 消息行样式 */ +.msg-line { + margin: 2px 0; + word-wrap: break-word; + word-break: break-all; +} + +.msg-line .msg-time { + font-size: 9px; + color: #999; +} + +.msg-line .msg-user { + cursor: pointer; + font-weight: bold; +} + +.msg-line .msg-user:hover { + text-decoration: underline; +} + +.msg-line .msg-action { + color: #009900; +} + +.msg-line .msg-secret { + color: #cc00cc; + font-style: italic; +} + +.msg-line .msg-content { + margin-left: 4px; +} + +.msg-line.sys-msg { + color: #cc0000; + text-align: center; + font-size: 9pt; +} + +/* ── 底部输入工具栏 ─────────────────────────────── */ +.input-bar { + height: auto; + min-height: 75px; + background: var(--bg-bar); + border-top: 2px solid var(--border-blue); + padding: 3px 6px; + flex-shrink: 0; + display: flex; + flex-direction: column; + gap: 3px; +} + +/* 欢迎语下拉浮层 */ +.welcome-menu { + position: absolute; + bottom: calc(100% + 4px); + left: 0; + z-index: 9000; + background: #fff; + border: 1px solid #b0c8e0; + border-radius: 6px; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18); + min-width: 280px; + max-width: 360px; + padding: 4px 0; +} + +.welcome-menu-item { + padding: 6px 12px; + font-size: 12px; + color: #224466; + cursor: pointer; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + border-bottom: 1px solid #eef4fb; + transition: background 0.1s; +} + +.welcome-menu-item:last-child { + border-bottom: none; +} + +.welcome-menu-item:hover { + background: #ddeeff; + color: #003366; +} + + +.input-bar select, +.input-bar input[type="text"], +.input-bar input[type="checkbox"] { + font-size: 12px; + border: 1px solid navy; + color: #224466; + padding: 1px 2px; + background: #fff; +} + +.input-bar select { + max-width: 100px; +} + +.input-bar .input-row { + display: flex; + align-items: center; + gap: 4px; + flex-wrap: wrap; +} + +.input-bar .say-input { + flex: 1; + min-width: 200px; + font-size: 12px; + border: 1px solid navy; + color: #224466; + padding: 3px 5px; + outline: none; +} + +.input-bar .say-input:focus { + border-color: #0066cc; + box-shadow: 0 0 3px rgba(0, 102, 204, 0.3); +} + +.input-bar .send-btn { + background: var(--bg-header); + color: white; + border: 1px solid var(--border-blue); + padding: 3px 12px; + font-size: 12px; + font-weight: bold; + cursor: pointer; + transition: background 0.15s; +} + +.input-bar .send-btn:hover { + background: #336699; +} + +.input-bar .send-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.input-bar label { + font-size: 12px; + cursor: pointer; + white-space: nowrap; + display: flex; + align-items: center; + gap: 2px; +} + +/* ── 右侧用户列表 Tab 栏 ──────────────────────── */ +.right-tabs { + display: flex; + background: var(--bg-bar); + border-bottom: 2px solid navy; + flex-shrink: 0; +} + +.right-tabs .tab-btn { + flex: 1; + text-align: center; + font-size: 12px; + padding: 3px 0; + cursor: pointer; + color: navy; + background: var(--bg-bar); + border: none; + font-family: inherit; + transition: all 0.15s; + user-select: none; +} + +.right-tabs .tab-btn.active { + background: navy; + color: white; +} + +.right-tabs .tab-btn:hover:not(.active) { + background: #99c8ee; +} + +/* 用户列表内容 */ +.user-list-content { + flex: 1; + overflow-y: auto; + padding: 4px; +} + +.user-item { + display: flex; + align-items: center; + gap: 4px; + padding: 3px 4px; + cursor: pointer; + font-size: 12px; + border-bottom: 1px dotted #cde; + transition: background 0.15s; +} + +.user-item:hover { + background: #d0e8ff; +} + +.user-item .user-head { + width: 36px; + height: 36px; + border-radius: 2px; + object-fit: cover; + background: transparent; + mix-blend-mode: multiply; + flex-shrink: 0; +} + +.user-item .user-name { + min-width: 0; + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--text-link); + font-weight: bold; +} + +.user-item .user-badge-slot { + flex-shrink: 0; + max-width: 78px; + min-width: 0; + overflow: hidden; +} + +.user-item .user-sex { + font-size: 10px; +} + +.user-item .user-level { + font-size: 9px; + color: #999; +} + +.user-badge-icon { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; +} + +.chat-hover-tooltip { + position: fixed; + z-index: 10030; + max-width: min(220px, calc(100vw - 20px)); + padding: 4px 8px; + border: 1px solid #244d77; + border-radius: 4px; + background: linear-gradient(to bottom, #fffef2, #fff6c9); + color: #243b53; + font-size: 11px; + line-height: 1.35; + white-space: nowrap; + box-shadow: 0 6px 18px rgba(17, 34, 51, 0.24); + pointer-events: none; +} + +.chat-hover-tooltip::after { + content: ''; + position: absolute; + top: 50%; + width: 6px; + height: 6px; + background: #fff9d8; + transform: translateY(-50%) rotate(45deg); +} + +.chat-hover-tooltip[data-side="right"]::after { + left: -4px; + border-left: 1px solid #244d77; + border-bottom: 1px solid #244d77; +} + +.chat-hover-tooltip[data-side="left"]::after { + right: -4px; + border-top: 1px solid #244d77; + border-right: 1px solid #244d77; +} + +/* 在线人数统计 */ +.online-stats { + background: var(--bg-bar); + text-align: center; + font-size: 11px; + padding: 3px; + border-top: 1px solid var(--border-blue); + color: navy; + flex-shrink: 0; +} + +/* ── 用户名片弹窗 ───────────────────────────────── */ +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; +} + +.modal-card { + background: white; + border: 2px solid var(--border-blue); + border-radius: 8px; + width: 420px; + max-width: 90vw; + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3); + overflow: hidden; +} + +.modal-header { + background: linear-gradient(135deg, var(--bg-header), var(--border-blue)); + color: white; + padding: 12px 16px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-header h3 { + font-size: 16px; + font-weight: bold; +} + +.modal-close { + background: none; + border: none; + color: white; + font-size: 20px; + cursor: pointer; + opacity: 0.8; +} + +.modal-close:hover { + opacity: 1; +} + +.modal-body { + padding: 16px; +} + +.modal-body .profile-row { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 12px; +} + +.modal-body .profile-avatar { + width: 56px; + height: 56px; + border-radius: 6px; + object-fit: cover; + border: 2px solid var(--bg-bar); + background: #eee; +} + +.modal-body .profile-info h4 { + font-size: 16px; + font-weight: bold; + color: var(--text-navy); +} + +.modal-body .profile-info .level-badge { + display: inline-block; + background: var(--bg-bar); + color: var(--border-blue); + font-size: 11px; + padding: 1px 6px; + border-radius: 10px; + font-weight: bold; + margin-left: 4px; +} + +.modal-body .profile-info .sex-badge { + font-size: 11px; + margin-left: 2px; +} + +.modal-body .profile-detail { + background: #f5f9ff; + border: 1px solid #e0ecff; + border-radius: 6px; + padding: 8px 12px; + font-size: 12px; + color: #666; + margin-bottom: 12px; +} + +.modal-actions { + padding: 0 16px 16px; + display: flex; + gap: 8px; +} + +.modal-actions button, +.modal-actions a { + flex: 1; + text-align: center; + padding: 6px 0; + border-radius: 6px; + font-size: 12px; + font-weight: bold; + cursor: pointer; + border: 1px solid; + transition: all 0.15s; + text-decoration: none; + display: block; +} + +.btn-kick { + background: #fee; + color: #c00; + border-color: #fcc; +} + +.btn-kick:hover { + background: #fcc; +} + +.btn-mute { + background: #fff8e6; + color: #b86e00; + border-color: #ffe0a0; +} + +.btn-mute:hover { + background: #ffe0a0; +} + +.btn-mail { + background: #f0e8ff; + color: #6633cc; + border-color: #d8c8ff; +} + +.btn-mail:hover { + background: #d8c8ff; +} + +.btn-whisper { + background: #e8f5ff; + color: var(--text-link); + border-color: var(--bg-bar); +} + +.btn-whisper:hover { + background: var(--bg-bar); +} + +/* 禁言输入行 */ +.mute-form { + display: flex; + align-items: center; + gap: 6px; + padding: 0 16px 12px; +} + +.mute-form input { + width: 60px; + border: 1px solid #ffe0a0; + border-radius: 4px; + padding: 3px 6px; + font-size: 12px; +} + +.mute-form button { + background: #b86e00; + color: white; + border: none; + border-radius: 4px; + padding: 4px 10px; + font-size: 12px; + cursor: pointer; +} + +/* ── 头像选择器 ─────────────────────────────────── */ +.avatar-option { + width: 36px; + height: 36px; + cursor: pointer; + border: 2px solid transparent; + border-radius: 3px; + transition: border-color 0.15s, transform 0.15s; +} + +.avatar-option:hover { + border-color: #88bbdd; + transform: scale(1.15); +} + +.avatar-option.selected { + border-color: #336699; + box-shadow: 0 0 6px rgba(51, 102, 153, 0.5); +} + +/* 送花礼物弹跳动画 */ +@keyframes giftBounce { + 0% { + transform: scale(0.3) rotate(-15deg); + opacity: 0; + } + + 50% { + transform: scale(1.3) rotate(5deg); + opacity: 1; + } + + 70% { + transform: scale(0.9) rotate(-3deg); + } + + 100% { + transform: scale(1) rotate(0deg); + } +} + +/* ═══════════════════════════════════════════════════ + 手机端响应式布局(≤ 640px) + ═══════════════════════════════════════════════════ */ +@media (max-width: 640px) { + + /* 隐藏中间工具条和右侧面板,让消息区占满全宽 */ + .chat-toolbar, + .chat-right { + display: none !important; + } + + /* 输入框最小宽度适配手机屏 */ + .input-bar .say-input { + min-width: 0; + } + + /* ── 右下角浮动按钮组 ── */ + #mobile-fabs { + position: fixed; + top: 35%; + right: 10px; + display: flex; + flex-direction: column; + gap: 8px; + z-index: 500; + } + + .mobile-fab { + width: 44px; + height: 44px; + border-radius: 50%; + border: 1px solid rgba(51, 102, 153, 0.4); + background: rgba(255, 255, 255, 0.82); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + color: #336699; + font-size: 18px; + cursor: pointer; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18); + display: flex; + align-items: center; + justify-content: center; + transition: transform 0.15s, background 0.15s, box-shadow 0.15s; + user-select: none; + -webkit-tap-highlight-color: transparent; + } + + .mobile-fab:active { + transform: scale(0.92); + background: rgba(51, 102, 153, 0.15); + box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2); + } + + /* ── 抽屉遮罩 ── */ + #mobile-drawer-mask { + display: none; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.45); + z-index: 600; + } + + #mobile-drawer-mask.open { + display: block; + } + + /* ── 抽屉通用容器(顶部向下滑入) ── */ + .mobile-drawer { + position: fixed; + left: 0; + right: 0; + top: 0; + z-index: 700; + background: #fff; + border-bottom: 2px solid var(--border-blue); + border-radius: 0 0 14px 14px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25); + transform: translateY(-100%); + transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1); + overflow: hidden; + display: flex; + flex-direction: column; + } + + .mobile-drawer.open { + transform: translateY(0); + } + + /* 抽屉顶部标题栏 */ + .mobile-drawer-header { + background: var(--bg-header); + color: #fff; + padding: 10px 14px; + font-size: 14px; + font-weight: bold; + display: flex; + justify-content: space-between; + align-items: center; + flex-shrink: 0; + } + + .mobile-drawer-close { + background: none; + border: none; + color: #fff; + font-size: 20px; + cursor: pointer; + line-height: 1; + opacity: 0.85; + padding: 0 4px; + } + + /* ── 工具条抽屉:横向网格排列按钮 ── */ + #mobile-drawer-toolbar .mobile-drawer-body { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 1px; + background: var(--border-blue); + max-height: 55vh; + overflow-y: auto; + } + + #mobile-drawer-toolbar .mobile-tool-btn { + background: var(--bg-toolbar); + color: #ddd; + font-size: 13px; + padding: 14px 4px; + text-align: center; + cursor: pointer; + user-select: none; + -webkit-tap-highlight-color: transparent; + transition: background 0.15s, color 0.15s; + writing-mode: horizontal-tb; + letter-spacing: 0; + } + + #mobile-drawer-toolbar .mobile-tool-btn:active { + background: #5599cc; + color: #fff; + } + + /* ── 名单/房间抽屉:限定高度,内部 flex 子项才能正确贡献高度 ── */ + #mobile-drawer-users { + height: 80vh; + } + + #mobile-drawer-users .mobile-right-clone { + display: flex; + flex-direction: column; + flex: 1; + overflow: hidden; + } + + /* 抽屉内的 tabs 复用样式 */ + #mobile-drawer-users .right-tabs { + flex-shrink: 0; + } + + #mobile-drawer-users .user-list-content { + flex: 1; + overflow-y: auto; + min-height: 0; + -webkit-overflow-scrolling: touch; + } + + #mobile-drawer-users .online-stats { + flex-shrink: 0; + } + + /* ── 名单抽屉内用户列表 item 放大触摸区域 ── */ + #mob-online-users-list .user-item { + padding: 7px 8px; + font-size: 13px; + } + + /* ── 现有弹窗(settings / avatar / shop)手机端自适应 ── */ + /* 防止固定像素宽度的 modal 内容区超出手机屏宽 */ + #settings-modal > div, + #avatar-picker-modal > div { + width: 92vw !important; + max-width: 420px !important; + max-height: 85vh !important; + } + + #shop-modal { + padding: 12px 6px !important; + } + + #shop-modal-inner { + width: 92vw !important; + max-width: 420px !important; + max-height: 85vh !important; + overflow-y: auto !important; + } + + /* ── 手机端隐藏房间介绍 ── */ + .room-desc { + display: none !important; + } + + /* ── 手机端隐藏输入栏中不常用的控件(动作/字色/字号/禁音/分屏) ── */ + /* 用 :has() 选择器精准定位含对应 input/select 的 label */ + .input-row label:has(#action), + .input-row label:has(#font_color), + .input-row label:has(#font_size_select), + .input-row label:has(#sound_muted) { + display: none !important; + } +} + +/* 桌面端(> 640px)不显示浮动按钮和抽屉组件 */ +@media (min-width: 641px) { + #mobile-fabs, + #mobile-drawer-mask, + #mobile-drawer-toolbar, + #mobile-drawer-users { + display: none !important; + } +} diff --git a/resources/views/chat/frame.blade.php b/resources/views/chat/frame.blade.php index f9e28de..edb91f5 100644 --- a/resources/views/chat/frame.blade.php +++ b/resources/views/chat/frame.blade.php @@ -138,9 +138,8 @@ // 兼容底部存量同步脚本,完整 URL 工厂由 Vite 的 chat-room/context.js 继续补齐。 window.chatContext = JSON.parse(document.getElementById('chat-context-data')?.textContent || '{}'); - @vite(['resources/css/app.css', 'resources/js/app.js', 'resources/js/chat.js']) + @vite(['resources/css/app.css', 'resources/css/chat.css', 'resources/js/app.js', 'resources/js/chat.js']) - diff --git a/vite.config.js b/vite.config.js index cacdcda..bd08006 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,6 +7,7 @@ export default defineConfig({ laravel({ input: [ "resources/css/app.css", + "resources/css/chat.css", "resources/js/admin-login.js", "resources/js/app.js", "resources/js/chat.js",