|
@@ -1,32 +1,13 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <!-- 右栏产物面板:宽 340(可拖 280–560),收起后只留一条带角标的触发条 -->
|
|
|
|
|
- <aside
|
|
|
|
|
- class="awb-aside"
|
|
|
|
|
- :class="{ 'is-collapsed': collapsed }"
|
|
|
|
|
- :style="{ width: `${collapsed ? COLLAPSED_WIDTH : width}px` }"
|
|
|
|
|
- >
|
|
|
|
|
- <!-- 收起态:右缘触发条,点击/悬停角标展开 -->
|
|
|
|
|
- <button
|
|
|
|
|
- v-if="collapsed"
|
|
|
|
|
- class="awb-aside__strip"
|
|
|
|
|
- type="button"
|
|
|
|
|
- :title="artifacts.length ? `展开产物栏(${artifacts.length} 个文件)` : '展开产物栏'"
|
|
|
|
|
- @click="setCollapsed(false)"
|
|
|
|
|
- >
|
|
|
|
|
- <Icon icon="mdi:file-delimited-outline" :size="15" />
|
|
|
|
|
- <span v-if="artifacts.length" class="awb-aside__badge">{{ artifacts.length }}</span>
|
|
|
|
|
- </button>
|
|
|
|
|
-
|
|
|
|
|
- <template v-else>
|
|
|
|
|
|
|
+ <!-- 右栏产物面板:宽 340(可拖 280–560);收起由聊天头的产物按钮控制,收起后宽度为 0 -->
|
|
|
|
|
+ <aside class="awb-aside" :class="{ 'is-collapsed': collapsed }" :style="{ width: collapsed ? '0px' : `${width}px` }">
|
|
|
|
|
+ <template v-if="!collapsed">
|
|
|
<header class="awb-aside__head">
|
|
<header class="awb-aside__head">
|
|
|
<span class="awb-aside__title">
|
|
<span class="awb-aside__title">
|
|
|
<Icon icon="mdi:file-delimited-outline" :size="15" />
|
|
<Icon icon="mdi:file-delimited-outline" :size="15" />
|
|
|
产物
|
|
产物
|
|
|
<em v-if="artifacts.length">{{ artifacts.length }}</em>
|
|
<em v-if="artifacts.length">{{ artifacts.length }}</em>
|
|
|
</span>
|
|
</span>
|
|
|
- <button class="awb-aside__btn" type="button" title="收起产物栏" @click="setCollapsed(true)">
|
|
|
|
|
- <Icon icon="mdi:chevron-double-right" :size="16" />
|
|
|
|
|
- </button>
|
|
|
|
|
</header>
|
|
</header>
|
|
|
|
|
|
|
|
<div class="awb-aside__body">
|
|
<div class="awb-aside__body">
|
|
@@ -88,14 +69,15 @@
|
|
|
import { artifactRowsText, artifactSizeText, openArtifactPreview } from '../utils/artifacts';
|
|
import { artifactRowsText, artifactSizeText, openArtifactPreview } from '../utils/artifacts';
|
|
|
import { toolLabel } from '../utils/constants';
|
|
import { toolLabel } from '../utils/constants';
|
|
|
|
|
|
|
|
- const props = defineProps<{ artifacts: SessionArtifact[] }>();
|
|
|
|
|
|
|
+ const props = withDefaults(defineProps<{ artifacts: SessionArtifact[]; collapsed?: boolean }>(), {
|
|
|
|
|
+ collapsed: false,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const emit = defineEmits<{ 'update:collapsed': [value: boolean] }>();
|
|
|
|
|
|
|
|
const { createMessage } = useMessage();
|
|
const { createMessage } = useMessage();
|
|
|
|
|
|
|
|
- /** 收起态占位宽度(触发条) */
|
|
|
|
|
- const COLLAPSED_WIDTH = 18;
|
|
|
|
|
const WIDTH_KEY = 'awb.artifact.width';
|
|
const WIDTH_KEY = 'awb.artifact.width';
|
|
|
- const COLLAPSED_KEY = 'awb.artifact.collapsed';
|
|
|
|
|
const MIN_WIDTH = 280;
|
|
const MIN_WIDTH = 280;
|
|
|
const MAX_WIDTH = 560;
|
|
const MAX_WIDTH = 560;
|
|
|
|
|
|
|
@@ -105,7 +87,6 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const width = ref(readWidth());
|
|
const width = ref(readWidth());
|
|
|
- const collapsed = ref(localStorage.getItem(COLLAPSED_KEY) === '1');
|
|
|
|
|
|
|
|
|
|
/** 会话里已有的产物(挂载时打底):之后新到的才标「新」、才触发自动展开 */
|
|
/** 会话里已有的产物(挂载时打底):之后新到的才标「新」、才触发自动展开 */
|
|
|
let knownCount = props.artifacts.length;
|
|
let knownCount = props.artifacts.length;
|
|
@@ -116,12 +97,22 @@
|
|
|
(next) => {
|
|
(next) => {
|
|
|
if (next > knownCount) {
|
|
if (next > knownCount) {
|
|
|
// 有新产物落盘:收起状态自动展开(Claude/Canvas 共性),否则用户感知不到
|
|
// 有新产物落盘:收起状态自动展开(Claude/Canvas 共性),否则用户感知不到
|
|
|
- if (collapsed.value) setCollapsed(false);
|
|
|
|
|
|
|
+ if (props.collapsed) emit('update:collapsed', false);
|
|
|
}
|
|
}
|
|
|
knownCount = next;
|
|
knownCount = next;
|
|
|
},
|
|
},
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
|
|
+ watch(
|
|
|
|
|
+ () => props.collapsed,
|
|
|
|
|
+ (value) => {
|
|
|
|
|
+ if (!value) {
|
|
|
|
|
+ // 展开后,此刻列表里的都算已读
|
|
|
|
|
+ props.artifacts.forEach((a) => seenIds.add(a.id));
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
/** 新在上 */
|
|
/** 新在上 */
|
|
|
const newestFirst = computed(() => [...props.artifacts].reverse());
|
|
const newestFirst = computed(() => [...props.artifacts].reverse());
|
|
|
|
|
|
|
@@ -129,15 +120,6 @@
|
|
|
return !seenIds.has(a.id);
|
|
return !seenIds.has(a.id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function setCollapsed(value: boolean): void {
|
|
|
|
|
- collapsed.value = value;
|
|
|
|
|
- localStorage.setItem(COLLAPSED_KEY, value ? '1' : '0');
|
|
|
|
|
- if (!value) {
|
|
|
|
|
- // 展开后,此刻列表里的都算已读
|
|
|
|
|
- props.artifacts.forEach((a) => seenIds.add(a.id));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
function onPreview(a: SessionArtifact): void {
|
|
function onPreview(a: SessionArtifact): void {
|
|
|
seenIds.add(a.id);
|
|
seenIds.add(a.id);
|
|
|
openArtifactPreview(a);
|
|
openArtifactPreview(a);
|
|
@@ -190,62 +172,36 @@
|
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
|
flex: 0 0 auto;
|
|
flex: 0 0 auto;
|
|
|
min-height: 0;
|
|
min-height: 0;
|
|
|
|
|
+ margin: 8px 10px 8px 0;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
- background: var(--ai-bg-page);
|
|
|
|
|
- border-left: 1px solid var(--ai-border);
|
|
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border: 1px solid #e7ebf3;
|
|
|
|
|
+ border-radius: 14px;
|
|
|
|
|
+ box-shadow: 0 1px 2px rgb(16 24 40 / 4%);
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
transition:
|
|
transition:
|
|
|
width 0.18s ease-out,
|
|
width 0.18s ease-out,
|
|
|
|
|
+ margin 0.18s ease-out,
|
|
|
border-color 0.18s ease-out;
|
|
border-color 0.18s ease-out;
|
|
|
|
|
|
|
|
|
|
+ /* 收起后不占位:宽度 0、无边距/描边/底色 */
|
|
|
&.is-collapsed {
|
|
&.is-collapsed {
|
|
|
|
|
+ margin: 0;
|
|
|
background: transparent;
|
|
background: transparent;
|
|
|
- border-left-color: var(--ai-border);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /* ── 收起态触发条 ── */
|
|
|
|
|
- .awb-aside__strip {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 6px;
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- padding: 10px 0 0;
|
|
|
|
|
- color: var(--ai-text-2);
|
|
|
|
|
- background: var(--ai-bg-subtle);
|
|
|
|
|
- border: none;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- transition: color 0.15s ease;
|
|
|
|
|
-
|
|
|
|
|
- &:hover {
|
|
|
|
|
- color: var(--ai-primary);
|
|
|
|
|
|
|
+ border: 0;
|
|
|
|
|
+ box-shadow: none;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .awb-aside__badge {
|
|
|
|
|
- display: inline-flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- min-width: 15px;
|
|
|
|
|
- height: 15px;
|
|
|
|
|
- padding: 0 4px;
|
|
|
|
|
- font-size: 10px;
|
|
|
|
|
- line-height: 15px;
|
|
|
|
|
- color: #fff;
|
|
|
|
|
- background: var(--ai-primary);
|
|
|
|
|
- border-radius: 99px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/* ── 头部 ── */
|
|
/* ── 头部 ── */
|
|
|
.awb-aside__head {
|
|
.awb-aside__head {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
gap: var(--ai-sp-2);
|
|
gap: var(--ai-sp-2);
|
|
|
flex: 0 0 auto;
|
|
flex: 0 0 auto;
|
|
|
- height: 40px;
|
|
|
|
|
- padding: 0 var(--ai-sp-2) 0 var(--ai-sp-3);
|
|
|
|
|
- border-bottom: 1px solid var(--ai-border);
|
|
|
|
|
|
|
+ height: 44px;
|
|
|
|
|
+ padding: 0 14px;
|
|
|
|
|
+ border-bottom: 1px solid #eff2f7;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.awb-aside__title {
|
|
.awb-aside__title {
|
|
@@ -254,33 +210,15 @@
|
|
|
gap: 6px;
|
|
gap: 6px;
|
|
|
flex: 1 1 auto;
|
|
flex: 1 1 auto;
|
|
|
min-width: 0;
|
|
min-width: 0;
|
|
|
- font-size: 13px;
|
|
|
|
|
|
|
+ color: #111827;
|
|
|
|
|
+ font-size: 13.5px;
|
|
|
font-weight: 600;
|
|
font-weight: 600;
|
|
|
- color: var(--ai-text);
|
|
|
|
|
|
|
|
|
|
em {
|
|
em {
|
|
|
|
|
+ color: #98a2b3;
|
|
|
font-style: normal;
|
|
font-style: normal;
|
|
|
- font-variant-numeric: tabular-nums;
|
|
|
|
|
- color: var(--ai-text-2);
|
|
|
|
|
font-weight: 500;
|
|
font-weight: 500;
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .awb-aside__btn {
|
|
|
|
|
- display: inline-flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- width: 26px;
|
|
|
|
|
- height: 26px;
|
|
|
|
|
- color: var(--ai-text-2);
|
|
|
|
|
- background: transparent;
|
|
|
|
|
- border: none;
|
|
|
|
|
- border-radius: 6px;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
-
|
|
|
|
|
- &:hover {
|
|
|
|
|
- color: var(--ai-primary);
|
|
|
|
|
- background: var(--ai-bg-hover);
|
|
|
|
|
|
|
+ font-variant-numeric: tabular-nums;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -298,18 +236,19 @@
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
gap: 6px;
|
|
gap: 6px;
|
|
|
padding: 48px var(--ai-sp-5);
|
|
padding: 48px var(--ai-sp-5);
|
|
|
- color: var(--ai-text-3, var(--ai-text-2));
|
|
|
|
|
|
|
+ color: #2a50ec;
|
|
|
text-align: center;
|
|
text-align: center;
|
|
|
|
|
|
|
|
.tip {
|
|
.tip {
|
|
|
margin: 6px 0 0;
|
|
margin: 6px 0 0;
|
|
|
|
|
+ color: #111827;
|
|
|
font-size: 13px;
|
|
font-size: 13px;
|
|
|
font-weight: 600;
|
|
font-weight: 600;
|
|
|
- color: var(--ai-text-2);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.sub {
|
|
.sub {
|
|
|
margin: 0;
|
|
margin: 0;
|
|
|
|
|
+ color: #98a2b3;
|
|
|
font-size: 12px;
|
|
font-size: 12px;
|
|
|
line-height: 1.7;
|
|
line-height: 1.7;
|
|
|
}
|
|
}
|
|
@@ -334,7 +273,7 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
|
&:hover {
|
|
|
- background: var(--ai-bg-hover);
|
|
|
|
|
|
|
+ background: #f4f6fa;
|
|
|
|
|
|
|
|
.awb-art__ops {
|
|
.awb-art__ops {
|
|
|
opacity: 1;
|
|
opacity: 1;
|
|
@@ -362,9 +301,9 @@
|
|
|
flex: 0 0 auto;
|
|
flex: 0 0 auto;
|
|
|
width: 30px;
|
|
width: 30px;
|
|
|
height: 30px;
|
|
height: 30px;
|
|
|
- color: var(--ai-primary);
|
|
|
|
|
- background: var(--ai-primary-soft);
|
|
|
|
|
- border-radius: 7px;
|
|
|
|
|
|
|
+ color: #2a50ec;
|
|
|
|
|
+ background: rgb(42 80 236 / 8%);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.awb-art__meta {
|
|
.awb-art__meta {
|
|
@@ -395,12 +334,12 @@
|
|
|
|
|
|
|
|
.awb-art__new {
|
|
.awb-art__new {
|
|
|
flex: 0 0 auto;
|
|
flex: 0 0 auto;
|
|
|
- padding: 0 5px;
|
|
|
|
|
|
|
+ padding: 0 6px;
|
|
|
|
|
+ color: #2a50ec;
|
|
|
font-size: 10.5px;
|
|
font-size: 10.5px;
|
|
|
line-height: 16px;
|
|
line-height: 16px;
|
|
|
- color: var(--ai-primary);
|
|
|
|
|
- background: var(--ai-primary-soft);
|
|
|
|
|
- border-radius: 99px;
|
|
|
|
|
|
|
+ background: rgb(42 80 236 / 8%);
|
|
|
|
|
+ border-radius: 6px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.awb-art__ops {
|
|
.awb-art__ops {
|
|
@@ -425,8 +364,8 @@
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
&:hover {
|
|
&:hover {
|
|
|
- color: var(--ai-primary);
|
|
|
|
|
- background: var(--ai-bg-page);
|
|
|
|
|
|
|
+ color: #2a50ec;
|
|
|
|
|
+ background: #f4f6fa;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|