fix(sidebar): 修复移动端对话「...」菜单点击无反应

- 触屏首次 tap 只应用 hover(按钮显现)并吞掉 click:@media (hover: none) 下「...」按钮与工作区操作按钮常显
- 菜单 fixed 定位受 .mobile-panel-sheet 常驻 transform 影响相对面板错位、被 overflow 裁剪:三处菜单 Teleport 到 body,样式选择器提为顶层,z-index 提升至 2300(高于移动端遮罩 2000)
This commit is contained in:
JOJO 2026-08-05 02:10:34 +08:00
parent 2db77fe663
commit ea232d6ac6
2 changed files with 116 additions and 98 deletions

View File

@ -289,37 +289,39 @@
>
<span aria-hidden="true"></span>
</button>
<div
v-if="shouldShowActionMenu(conv.id)"
class="conversation-actions-menu conversation-actions-menu--fixed"
:class="{ open: openActionMenuId === conv.id }"
:style="{
top: actionMenuPosition.top + 'px',
right: actionMenuPosition.right + 'px'
}"
>
<button
type="button"
@click="
openActionMenuId = null;
$emit('duplicate', conv.id);
"
<Teleport to="body">
<div
v-if="shouldShowActionMenu(conv.id)"
class="conversation-actions-menu conversation-actions-menu--fixed"
:class="{ open: openActionMenuId === conv.id }"
:style="{
top: actionMenuPosition.top + 'px',
right: actionMenuPosition.right + 'px'
}"
>
<span class="icon icon-sm" :style="iconStyle('copy')" aria-hidden="true"></span>
<span>复制</span>
</button>
<button
type="button"
class="danger"
@click="
openActionMenuId = null;
$emit('delete', { id: conv.id, workspaceId: String(ws.workspace_id || '') });
"
>
<span class="icon icon-sm" :style="iconStyle('trash')" aria-hidden="true"></span>
<span>删除</span>
</button>
</div>
<button
type="button"
@click="
openActionMenuId = null;
$emit('duplicate', conv.id);
"
>
<span class="icon icon-sm" :style="iconStyle('copy')" aria-hidden="true"></span>
<span>复制</span>
</button>
<button
type="button"
class="danger"
@click="
openActionMenuId = null;
$emit('delete', { id: conv.id, workspaceId: String(ws.workspace_id || '') });
"
>
<span class="icon icon-sm" :style="iconStyle('trash')" aria-hidden="true"></span>
<span>删除</span>
</button>
</div>
</Teleport>
</div>
</div>
</transition-group>
@ -407,37 +409,39 @@
>
<span aria-hidden="true"></span>
</button>
<div
v-if="shouldShowActionMenu(conv.id)"
class="conversation-actions-menu conversation-actions-menu--fixed"
:class="{ open: openActionMenuId === conv.id }"
:style="{
top: actionMenuPosition.top + 'px',
right: actionMenuPosition.right + 'px'
}"
>
<button
type="button"
@click="
openActionMenuId = null;
$emit('duplicate', conv.id);
"
<Teleport to="body">
<div
v-if="shouldShowActionMenu(conv.id)"
class="conversation-actions-menu conversation-actions-menu--fixed"
:class="{ open: openActionMenuId === conv.id }"
:style="{
top: actionMenuPosition.top + 'px',
right: actionMenuPosition.right + 'px'
}"
>
<span class="icon icon-sm" :style="iconStyle('copy')" aria-hidden="true"></span>
<span>复制</span>
</button>
<button
type="button"
class="danger"
@click="
openActionMenuId = null;
$emit('delete', { id: conv.id, workspaceId: String(group.workspace_id || '') });
"
>
<span class="icon icon-sm" :style="iconStyle('trash')" aria-hidden="true"></span>
<span>删除</span>
</button>
</div>
<button
type="button"
@click="
openActionMenuId = null;
$emit('duplicate', conv.id);
"
>
<span class="icon icon-sm" :style="iconStyle('copy')" aria-hidden="true"></span>
<span>复制</span>
</button>
<button
type="button"
class="danger"
@click="
openActionMenuId = null;
$emit('delete', { id: conv.id, workspaceId: String(group.workspace_id || '') });
"
>
<span class="icon icon-sm" :style="iconStyle('trash')" aria-hidden="true"></span>
<span>删除</span>
</button>
</div>
</Teleport>
</div>
</div>
</div>
@ -511,37 +515,39 @@
>
<span aria-hidden="true"></span>
</button>
<div
v-if="!isConversationActive(conv.id) && !isConversationCompleted(conv.id) && openActionMenuId === conv.id"
class="conversation-actions-menu conversation-actions-menu--fixed"
:class="{ open: openActionMenuId === conv.id }"
:style="{
top: actionMenuPosition.top + 'px',
right: actionMenuPosition.right + 'px'
}"
>
<button
type="button"
@click="
openActionMenuId = null;
$emit('duplicate', conv.id);
"
<Teleport to="body">
<div
v-if="!isConversationActive(conv.id) && !isConversationCompleted(conv.id) && openActionMenuId === conv.id"
class="conversation-actions-menu conversation-actions-menu--fixed"
:class="{ open: openActionMenuId === conv.id }"
:style="{
top: actionMenuPosition.top + 'px',
right: actionMenuPosition.right + 'px'
}"
>
<span class="icon icon-sm" :style="iconStyle('copy')" aria-hidden="true"></span>
<span>复制</span>
</button>
<button
type="button"
class="danger"
@click="
openActionMenuId = null;
$emit('delete', conv.id);
"
>
<span class="icon icon-sm" :style="iconStyle('trash')" aria-hidden="true"></span>
<span>删除</span>
</button>
</div>
<button
type="button"
@click="
openActionMenuId = null;
$emit('duplicate', conv.id);
"
>
<span class="icon icon-sm" :style="iconStyle('copy')" aria-hidden="true"></span>
<span>复制</span>
</button>
<button
type="button"
class="danger"
@click="
openActionMenuId = null;
$emit('delete', conv.id);
"
>
<span class="icon icon-sm" :style="iconStyle('trash')" aria-hidden="true"></span>
<span>删除</span>
</button>
</div>
</Teleport>
</div>
</div>
</transition-group>

View File

@ -542,7 +542,9 @@ body[data-theme='dark'] .conversation-sidebar .conversation-item.active:focus-wi
11px 0 0 currentColor;
}
.conversation-sidebar .conversation-actions-menu {
/* 菜单通过 Teleport 挂载到 body脱离移动端面板的 transform 包含块与 overflow 裁切
因此样式选择器不能挂在 .conversation-sidebar */
.conversation-actions-menu {
z-index: 140;
width: max-content;
min-width: 92px;
@ -559,24 +561,25 @@ body[data-theme='dark'] .conversation-sidebar .conversation-item.active:focus-wi
transform 150ms cubic-bezier(0.22, 1, 0.36, 1);
}
.conversation-sidebar .conversation-actions-menu--absolute {
.conversation-actions-menu--absolute {
position: absolute;
right: 0;
top: calc(100% + 6px);
}
.conversation-sidebar .conversation-actions-menu--fixed {
.conversation-actions-menu--fixed {
position: fixed;
z-index: 1000;
/* 需高于移动端面板遮罩 .mobile-panel-overlayz-index: 2000 */
z-index: 2300;
}
.conversation-sidebar .conversation-actions-menu.open {
.conversation-actions-menu.open {
opacity: 1;
transform: translateY(0) scale(1);
pointer-events: auto;
}
.conversation-sidebar .conversation-actions-menu button {
.conversation-actions-menu button {
width: 100%;
min-width: 80px;
height: 36px;
@ -595,11 +598,11 @@ body[data-theme='dark'] .conversation-sidebar .conversation-item.active:focus-wi
transition: background 140ms ease;
}
.conversation-sidebar .conversation-actions-menu button:hover {
.conversation-actions-menu button:hover {
background: var(--theme-tab-active);
}
.conversation-sidebar .conversation-actions-menu button.danger {
.conversation-actions-menu button.danger {
color: var(--state-danger);
}
@ -896,6 +899,15 @@ body[data-theme='dark'] .workspace-group-header.search-result-group-header:hover
background: var(--theme-tab-active);
}
/* 触摸设备手机/平板没有 hover常显操作入口
否则按钮透明时首次 tap 只会应用 hover 按钮显现并吞掉 click菜单打不开 */
@media (hover: none) {
.conversation-sidebar .conversation-more-btn,
.conversation-sidebar .workspace-group-actions {
opacity: 1;
}
}
.workspace-group-children {
display: grid;
grid-template-rows: 0fr;