feat(header): 搜索框改居中命令面板,应用列表数据与 loading 与 AppList 共享
- header.scss: 删旧 .search-box 与 fade1/search-animation/icon-animation 动画段,
新增 app-cmdk-* 面板样式。样式段必须放顶层——面板 Teleport 到 body,嵌进
.default-header 会生成后代选择器而匹配不到
- Header.vue: 搜索 li 收敛为单图标 + openSearch;模板末尾追加 <Teleport to="body">
命令面板,支持实时过滤 / ↑↓ 键盘导航 / Enter 打开 / Esc 关闭 / 空结果态;
删 watch(isSearching) 与空函数 showSeachBox;挂/卸 window keydown
- store/index.ts: 新增 appListLoading 字段与 setAppListLoading
- utils/bschLinkPage.ts: 抽出 openAppPage(app, ifameAppIdArr),与点击应用图标同一路径
- AppList.vue: reloadAppData 写 store(数据 + loading,try/finally);
linkPage(item) 委托 openAppPage
硬约束保持不动:watch(searchAppText) -> mittBus.emit("searchChange")(背景应用网格靠它过滤)、
isSearchIconShow(route.name === "apps")。
This commit is contained in:
+135
-84
@@ -58,97 +58,148 @@
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
height: 36px;
|
||||
margin-right: 2px;
|
||||
background: #fff;
|
||||
border-radius: 34px;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
user-select: none;
|
||||
input {
|
||||
flex: 1;
|
||||
outline: none;
|
||||
border: none;
|
||||
margin-left: 15px;
|
||||
width: 210px;
|
||||
}
|
||||
.icon {
|
||||
margin: 0 8px;
|
||||
// animation: icon-turn 0.3s linear;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-animation {
|
||||
0% {
|
||||
display: none;
|
||||
}
|
||||
/* ===== Header 搜索命令面板(2026-10-08 定稿 B 方案)=====
|
||||
⚠️ 必须放在顶层(不可嵌进 .default-header 内):面板由 <Teleport to="body"> 渲染到 body 下,
|
||||
若嵌在 .default-header 内会生成 `.default-header .app-cmdk-layer`,匹配不到 body 下的元素。
|
||||
类名统一 app-cmdk- 前缀(本文件是全局样式,非 scoped)。 */
|
||||
.app-cmdk-layer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 2000;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.3s linear;
|
||||
|
||||
75% {
|
||||
display: none;
|
||||
}
|
||||
100% {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.fade1-enter-active,
|
||||
.fade1-enter-to {
|
||||
animation: fade-animation 0.5s;
|
||||
}
|
||||
&.is-open {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
.app-cmdk-mask {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(18, 26, 40, 0.34);
|
||||
backdrop-filter: blur(10px) saturate(125%);
|
||||
-webkit-backdrop-filter: blur(10px) saturate(125%);
|
||||
}
|
||||
.app-cmdk-panel {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 78px;
|
||||
width: min(620px, calc(100% - 48px));
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 26px 68px rgba(18, 30, 54, 0.3), 0 2px 8px rgba(18, 30, 54, 0.1);
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -14px) scale(0.965);
|
||||
transition: opacity 0.26s linear, transform 0.48s cubic-bezier(0.2, 0.9, 0.24, 1);
|
||||
|
||||
.fade1-leave-from,
|
||||
.fade1-leave-active {
|
||||
display: none !important;
|
||||
}
|
||||
.app-cmdk-layer.is-open & {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, 0) scale(1);
|
||||
}
|
||||
}
|
||||
.app-cmdk-hd {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 0 18px;
|
||||
height: 56px;
|
||||
border-bottom: 1px solid #f0f3f8;
|
||||
color: #98a2b0;
|
||||
|
||||
@keyframes search-animation {
|
||||
0% {
|
||||
display: none;
|
||||
width: 0;
|
||||
}
|
||||
20% {
|
||||
display: none;
|
||||
width: 0;
|
||||
}
|
||||
21% {
|
||||
width: 0;
|
||||
display: block;
|
||||
}
|
||||
100% {
|
||||
width: 210px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes icon-animation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.search-enter-active {
|
||||
& input {
|
||||
animation: search-animation 0.3s ease-in-out;
|
||||
}
|
||||
& .icon {
|
||||
animation: icon-animation 0.4s;
|
||||
}
|
||||
}
|
||||
|
||||
.search-leave-active {
|
||||
& input {
|
||||
animation: search-animation 0.35s ease-out reverse;
|
||||
}
|
||||
& .icon {
|
||||
animation: icon-animation 0.4s reverse;
|
||||
}
|
||||
input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
outline: none;
|
||||
border: 0;
|
||||
color: #252b35;
|
||||
font-size: 15px;
|
||||
background: none;
|
||||
&::placeholder {
|
||||
color: #aab3c0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.app-cmdk-kbd {
|
||||
font-size: 11px;
|
||||
color: #8b95a3;
|
||||
background: #f2f5fa;
|
||||
border: 1px solid #e4e9f2;
|
||||
border-radius: 5px;
|
||||
padding: 2px 6px;
|
||||
font-family: ui-monospace, Menlo, monospace;
|
||||
}
|
||||
.app-cmdk-list {
|
||||
padding: 8px;
|
||||
max-height: min(58vh, 440px);
|
||||
overflow: auto;
|
||||
}
|
||||
.app-cmdk-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 9px 12px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transform: translateY(9px);
|
||||
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
transform 0.42s cubic-bezier(0.4, 0, 0.2, 1), background 0.16s;
|
||||
|
||||
.app-cmdk-layer.is-open & {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
transition-delay: calc(0.14s + var(--i) * 0.035s), calc(0.14s + var(--i) * 0.035s), 0s;
|
||||
}
|
||||
&.is-hl,
|
||||
&:hover {
|
||||
background: #f3f6fc;
|
||||
}
|
||||
}
|
||||
.app-cmdk-list.is-instant .app-cmdk-item {
|
||||
transition-duration: 0.15s;
|
||||
transition-delay: 0s;
|
||||
}
|
||||
.app-cmdk-img {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 9px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.app-cmdk-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 13.5px;
|
||||
color: #252b35;
|
||||
font-weight: 600;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.app-cmdk-empty {
|
||||
display: none;
|
||||
padding: 28px 18px 32px;
|
||||
text-align: center;
|
||||
color: #a8b1be;
|
||||
font-size: 13px;
|
||||
&.is-show {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.app-cmdk-ft {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 10px 18px;
|
||||
border-top: 1px solid #f0f3f8;
|
||||
font-size: 11.5px;
|
||||
color: #98a2b0;
|
||||
background: #fbfcfe;
|
||||
}
|
||||
|
||||
.role-info {
|
||||
height: 22px;
|
||||
|
||||
Reference in New Issue
Block a user