fix(ui): adjust composer status layering
This commit is contained in:
parent
0815625cfd
commit
2f0e269788
@ -1,72 +1,6 @@
|
||||
<template>
|
||||
<div class="input-area compact-input-area" ref="inputAreaRoot">
|
||||
<div class="stadium-input-wrapper" ref="stadiumShellOuter">
|
||||
<transition name="floating-status-motion">
|
||||
<div
|
||||
v-if="floatingStatusVisible"
|
||||
class="floating-project-status"
|
||||
@click.stop
|
||||
>
|
||||
<span v-if="projectGitSummaryForRender" class="floating-project-status__left">
|
||||
<span class="floating-project-status__menu-wrap">
|
||||
<button
|
||||
type="button"
|
||||
class="floating-project-status__button floating-project-status__button--project"
|
||||
:class="{ 'floating-project-status__button--active': projectGitMenuOpen === 'project' }"
|
||||
@click.stop="toggleProjectGitMenu('project')"
|
||||
>
|
||||
{{ projectGitSummaryForRender.projectName }}
|
||||
</button>
|
||||
<div
|
||||
v-if="projectGitMenuOpen === 'project'"
|
||||
class="floating-project-status__submenu floating-project-status__submenu--project"
|
||||
@click.stop
|
||||
>
|
||||
<button type="button" @click.stop="openProjectInFileManager">在文件管理器中打开</button>
|
||||
<button type="button" @click.stop="copyProjectPath">复制地址</button>
|
||||
</div>
|
||||
</span>
|
||||
<span class="floating-project-status__menu-wrap">
|
||||
<button
|
||||
type="button"
|
||||
class="floating-project-status__button floating-project-status__button--branch"
|
||||
:class="{ 'floating-project-status__button--active': projectGitMenuOpen === 'branch' }"
|
||||
@click.stop="toggleProjectGitMenu('branch')"
|
||||
>
|
||||
{{ projectGitSummaryForRender.branch }}
|
||||
</button>
|
||||
<div
|
||||
v-if="projectGitMenuOpen === 'branch'"
|
||||
class="floating-project-status__submenu floating-project-status__submenu--branch"
|
||||
@click.stop
|
||||
>
|
||||
<button type="button" @click.stop="copyProjectBranch">复制分支名称</button>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
<span class="floating-project-status__right">
|
||||
<span v-if="goalRunning" class="floating-project-status__notice">目标模式运行中</span>
|
||||
<span v-else-if="goalModeArmed" class="floating-project-status__notice">目标模式就绪</span>
|
||||
<button
|
||||
v-if="userQuestionMinimized && pendingUserQuestionCount > 0"
|
||||
type="button"
|
||||
class="floating-project-status__notice floating-project-status__notice--button"
|
||||
@click.stop="$emit('restore-user-question')"
|
||||
>
|
||||
等待回答问题
|
||||
</button>
|
||||
<button
|
||||
v-if="projectGitSummaryForRender"
|
||||
type="button"
|
||||
class="floating-project-status__stats"
|
||||
@click.stop="$emit('open-git-changes-panel')"
|
||||
>
|
||||
<span class="floating-project-status__add">+{{ projectGitSummaryForRender.additions }}</span>
|
||||
<span class="floating-project-status__del">-{{ projectGitSummaryForRender.deletions }}</span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</transition>
|
||||
<div
|
||||
class="runtime-queue-list"
|
||||
:class="{ 'runtime-queue-list--empty': !runtimeQueuedMessagesForRender.length }"
|
||||
@ -136,6 +70,72 @@
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="floating-status-motion">
|
||||
<div
|
||||
v-if="floatingStatusVisible"
|
||||
class="floating-project-status"
|
||||
@click.stop
|
||||
>
|
||||
<span v-if="projectGitSummaryForRender" class="floating-project-status__left">
|
||||
<span class="floating-project-status__menu-wrap">
|
||||
<button
|
||||
type="button"
|
||||
class="floating-project-status__button floating-project-status__button--project"
|
||||
:class="{ 'floating-project-status__button--active': projectGitMenuOpen === 'project' }"
|
||||
@click.stop="toggleProjectGitMenu('project')"
|
||||
>
|
||||
{{ projectGitSummaryForRender.projectName }}
|
||||
</button>
|
||||
<div
|
||||
v-if="projectGitMenuOpen === 'project'"
|
||||
class="floating-project-status__submenu floating-project-status__submenu--project"
|
||||
@click.stop
|
||||
>
|
||||
<button type="button" @click.stop="openProjectInFileManager">在文件管理器中打开</button>
|
||||
<button type="button" @click.stop="copyProjectPath">复制地址</button>
|
||||
</div>
|
||||
</span>
|
||||
<span class="floating-project-status__menu-wrap">
|
||||
<button
|
||||
type="button"
|
||||
class="floating-project-status__button floating-project-status__button--branch"
|
||||
:class="{ 'floating-project-status__button--active': projectGitMenuOpen === 'branch' }"
|
||||
@click.stop="toggleProjectGitMenu('branch')"
|
||||
>
|
||||
{{ projectGitSummaryForRender.branch }}
|
||||
</button>
|
||||
<div
|
||||
v-if="projectGitMenuOpen === 'branch'"
|
||||
class="floating-project-status__submenu floating-project-status__submenu--branch"
|
||||
@click.stop
|
||||
>
|
||||
<button type="button" @click.stop="copyProjectBranch">复制分支名称</button>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
<span class="floating-project-status__right">
|
||||
<span v-if="goalRunning" class="floating-project-status__notice">目标模式运行中</span>
|
||||
<span v-else-if="goalModeArmed" class="floating-project-status__notice">目标模式就绪</span>
|
||||
<button
|
||||
v-if="userQuestionMinimized && pendingUserQuestionCount > 0"
|
||||
type="button"
|
||||
class="floating-project-status__notice floating-project-status__notice--button"
|
||||
@click.stop="$emit('restore-user-question')"
|
||||
>
|
||||
等待回答问题
|
||||
</button>
|
||||
<button
|
||||
v-if="projectGitSummaryForRender"
|
||||
type="button"
|
||||
class="floating-project-status__stats"
|
||||
@click.stop="$emit('open-git-changes-panel')"
|
||||
>
|
||||
<span class="floating-project-status__add">+{{ projectGitSummaryForRender.additions }}</span>
|
||||
<span class="floating-project-status__del">-{{ projectGitSummaryForRender.deletions }}</span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</transition>
|
||||
<div
|
||||
class="stadium-shell"
|
||||
ref="compactInputShell"
|
||||
@ -1459,22 +1459,30 @@ const collectComposerVisualHeight = () => {
|
||||
if (!root || !shell) {
|
||||
return 0;
|
||||
}
|
||||
const shellRect = shell.getBoundingClientRect();
|
||||
let top = shellRect.top;
|
||||
let bottom = shellRect.bottom;
|
||||
// 用 offset 布局坐标(offsetTop/offsetHeight)计算可视高度,而非 getBoundingClientRect。
|
||||
// 后者会把进入/离开动画的 transform 一起算进去:状态栏进场时还停在 translateY(44px) 的低位,
|
||||
// 测得的增长量≈0,要等 260ms 动画结束才量到真实高度、再迟一拍下降——表现为「先挡住、完全出现后才下降」。
|
||||
// offset 系列只反映静止布局、不受 transform 影响,状态栏一挂载就按最终高度上报,
|
||||
// 输入栏下降与状态栏出现动画得以同时发生。这些浮层与 shell 同为 .stadium-input-wrapper 的直接子节点,
|
||||
// 其 offsetParent 一致,offsetTop 可直接比较。
|
||||
let top = shell.offsetTop;
|
||||
let bottom = shell.offsetTop + shell.offsetHeight;
|
||||
const slashMenu = root.querySelector('.skill-slash-menu');
|
||||
if (slashMenu instanceof HTMLElement) {
|
||||
const rect = slashMenu.getBoundingClientRect();
|
||||
return Math.max(0, Math.max(shellRect.bottom, rect.bottom) - Math.min(shellRect.top, rect.top));
|
||||
const sTop = slashMenu.offsetTop;
|
||||
const sBottom = slashMenu.offsetTop + slashMenu.offsetHeight;
|
||||
return Math.max(0, Math.max(bottom, sBottom) - Math.min(top, sTop));
|
||||
}
|
||||
// 收起态横幅是脱离流、浮在角上的小圆点,不应计入为聊天区预留的高度,
|
||||
// 否则会把消息区可滚动范围顶高。故排除 .goal-mode-banner--collapsed。
|
||||
const nodes = root.querySelectorAll('.runtime-queue-list:not(.runtime-queue-list--empty), .floating-project-status');
|
||||
nodes.forEach((node) => {
|
||||
if (!(node instanceof HTMLElement)) return;
|
||||
const rect = node.getBoundingClientRect();
|
||||
top = Math.min(top, rect.top);
|
||||
bottom = Math.max(bottom, rect.bottom);
|
||||
// 离开态:floatingStatusVisible 已翻 false 但元素仍在 DOM 中做退场动画。
|
||||
// 此时不再计入它的高度,让输入栏立即回升、与状态栏的退场动画同步。
|
||||
if (node.classList.contains('floating-project-status') && !floatingStatusVisible.value) return;
|
||||
top = Math.min(top, node.offsetTop);
|
||||
bottom = Math.max(bottom, node.offsetTop + node.offsetHeight);
|
||||
});
|
||||
return Math.max(0, bottom - top);
|
||||
};
|
||||
@ -1807,9 +1815,9 @@ onBeforeUnmount(() => {
|
||||
<style scoped>
|
||||
.floating-project-status {
|
||||
position: absolute;
|
||||
left: calc(50% - 7px);
|
||||
left: calc(5% - 7px);
|
||||
bottom: calc(100% + 6px);
|
||||
z-index: 45;
|
||||
z-index: auto;
|
||||
width: 90%;
|
||||
max-width: 90%;
|
||||
height: 34px;
|
||||
@ -1822,7 +1830,6 @@ onBeforeUnmount(() => {
|
||||
border-radius: 14px;
|
||||
background: var(--theme-surface-muted);
|
||||
box-shadow: none;
|
||||
transform: translateX(-50%);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
@ -1992,18 +1999,22 @@ onBeforeUnmount(() => {
|
||||
opacity 180ms ease,
|
||||
transform 260ms cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
transform-origin: bottom center;
|
||||
will-change: transform, opacity;
|
||||
/* 状态栏本体永远在最底层:输入栏 shell(z-index:2) > / 菜单(z-index:1) > 状态栏(auto)。
|
||||
不在这里设置 z-index,避免创建低层 stacking context 后把二级菜单也压在输入栏下。 */
|
||||
z-index: auto;
|
||||
}
|
||||
|
||||
.floating-status-motion-enter-from,
|
||||
.floating-status-motion-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(44px);
|
||||
transform: translateY(44px);
|
||||
}
|
||||
|
||||
.floating-status-motion-enter-to,
|
||||
.floating-status-motion-leave-from {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 目标模式横幅:与 + 按钮左对齐,置于输入框上方 */
|
||||
|
||||
@ -172,8 +172,21 @@
|
||||
will-change: transform, clip-path;
|
||||
}
|
||||
|
||||
/* / 菜单始终高于状态栏本体、低于输入栏 shell(z-index:2):
|
||||
输入栏 > / 菜单 > 状态栏。本体状态栏不设置正 z-index,
|
||||
只让状态栏二级菜单单独使用高 z-index。 */
|
||||
.skill-slash-menu-motion-enter-active,
|
||||
.skill-slash-menu-motion-leave-active {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.skill-slash-menu-motion-enter-from,
|
||||
.skill-slash-menu-motion-leave-to {
|
||||
/* 底边锚定在输入框上沿(bottom:100%-2px),配合 clip-path 从底部揭开:
|
||||
translateY(100%) 把元素整体下移一个自身高度后,再让 clip 的底部 inset 从 100%→0,
|
||||
净效果是「可见底边始终钉在输入框上沿、可见顶边向上生长」,即从输入框上沿升起。
|
||||
注意:不能改成 translateY(0)——那样 clip 会从元素静止态的顶部(在输入框上方一整个菜单高度处)
|
||||
向下揭开,看起来像菜单从高空往下展开,正是要避免的「在状态栏上方出现」。 */
|
||||
transform: translateX(-50%) translateY(100%);
|
||||
clip-path: inset(0 0 100% 0 round 12px 12px 0 0);
|
||||
}
|
||||
@ -913,7 +926,10 @@ body[data-theme='dark'] {
|
||||
}
|
||||
|
||||
.composer-container.blank-hero-mode {
|
||||
transform: translateY(-38vh);
|
||||
// 新对话居中态:当输入栏上方出现 git 状态栏或输入变多行时,整体可视高度会向上增长,
|
||||
// 顶到欢迎文字。用已计算好的 --composer-growth-height 把输入栏整体下移同样的距离,
|
||||
// 让栈顶回到「裸单行输入」时的位置,从而保证不遮挡欢迎文字。
|
||||
transform: translateY(calc(-38vh + var(--composer-growth-height, 0px)));
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@ -925,7 +941,7 @@ body[data-theme='dark'] {
|
||||
height: 44px;
|
||||
}
|
||||
.composer-container.blank-hero-mode {
|
||||
transform: translateY(-32vh);
|
||||
transform: translateY(calc(-32vh + var(--composer-growth-height, 0px)));
|
||||
}
|
||||
.blank-hero-overlay {
|
||||
padding-bottom: 120px;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user