Files
jordium-gantt-vue3/demo/VersionHistoryDrawer.vue
2025-12-17 18:09:55 +08:00

333 lines
9.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { ref, onMounted } from 'vue'
const props = defineProps<{ visible: boolean }>()
const versionList = ref<any[]>([])
onMounted(async () => {
const res = await fetch(new URL('./version-history.json', import.meta.url).href)
const data = await res.json()
// 按日期和版本号倒序排列
versionList.value = data.sort((a, b) => {
if (a.date === b.date) {
// 版本号倒序
return b.version.localeCompare(a.version, undefined, { numeric: true })
}
return b.date.localeCompare(a.date)
})
})
</script>
<template>
<div>
<div v-if="props.visible" class="drawer-mask" @click="$emit('close')"></div>
<div class="version-history-drawer" :class="{ open: props.visible }">
<div class="drawer-header">
<h3 class="drawer-title">版本历史</h3>
<button class="drawer-close-btn" type="button" @click="$emit('close')">
<svg class="close-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<div class="drawer-body">
<div class="version-timeline">
<div
v-for="(item, idx) in versionList"
:key="item.version"
class="version-timeline-group"
>
<div :class="['version-timeline-dot', idx === 0 ? 'latest' : '']">
<div class="dot-label">
<span class="dot-version">{{ item.version }}</span>
<span class="dot-date">{{ item.date }}</span>
</div>
</div>
<div class="version-timeline-content version-card">
<ul class="version-notes">
<li v-for="(note, nidx) in item.notes" :key="nidx" v-html="note"></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.version-history-drawer {
position: fixed;
top: 0;
left: 0;
width: 50%; /* 增加Drawer宽度适中大气 */
height: 100vh;
background: var(--gantt-bg-primary, #fff);
box-shadow: 2px 0 24px rgba(0, 0, 0, 0.1);
z-index: 2000;
transform: translateX(-100%);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
flex-direction: column;
/* 去除圆角 */
}
.version-history-drawer.open {
transform: translateX(0);
}
.drawer-mask {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5); /* 与TaskDrawer一致 */
z-index: 1999;
transition: background 0.2s;
}
.drawer-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 24px;
border-bottom: 1px solid var(--gantt-border-light, #ebeef5);
background: var(--gantt-bg-secondary, #f5f7fa);
}
.drawer-title {
margin: 0;
font-size: 18px;
font-weight: 600;
color: var(--gantt-text-primary, #303133);
}
.drawer-close-btn {
background: none;
border: none;
cursor: pointer;
padding: 4px;
color: var(--gantt-text-muted, #909399);
transition: color 0.2s;
}
.drawer-close-btn:hover {
color: var(--gantt-text-secondary, #606266);
}
.close-icon {
width: 16px;
height: 16px;
stroke-width: 2;
}
.drawer-body {
flex: 1;
overflow-y: auto;
padding: 32px 32px 32px 60px;
background: var(--gantt-bg-primary, #fff); /* 统一用变量,便于主题切换 */
scrollbar-width: thin;
scrollbar-color: #b3c6e0 #f0f2f5;
/* 去除圆角 */
}
.drawer-body::-webkit-scrollbar {
width: 6px;
background: #f0f2f5;
}
.drawer-body::-webkit-scrollbar-thumb {
background: #b3c6e0;
border-radius: 4px;
}
.drawer-body::-webkit-scrollbar-track {
background: #f0f2f5;
}
.version-timeline {
position: relative;
margin-left: 140px;
border-left: 0;
}
.version-timeline::before {
content: '';
position: absolute;
left: -8px;
top: 0;
width: 2px;
height: 100%;
background: repeating-linear-gradient(
to bottom,
var(--gantt-timeline-line, #a0cfff) 0 8px,
transparent 8px 16px
);
border-radius: 1px;
z-index: 0;
}
.version-timeline-group {
position: relative;
margin-bottom: 40px;
padding-left: 18px;
min-height: 60px;
transition: box-shadow 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.version-timeline-dot {
position: absolute;
left: -13px;
top: 18px;
width: 10px;
height: 10px;
background: var(--gantt-timeline-dot, #a0cfff); /* 更柔和主色 */
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 0 0 0 2px var(--gantt-timeline-line, #b3d8ff);
z-index: 3;
display: flex;
align-items: flex-start;
justify-content: flex-end;
transition:
background 0.2s,
box-shadow 0.2s;
}
.version-timeline-group:hover .version-timeline-dot {
background: var(--gantt-timeline-dot-hover, #409eff); /* hover主色 */
}
.version-timeline-dot.latest {
background: var(--gantt-primary, #409eff);
}
.dot-label {
position: absolute;
left: -140px;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
align-items: flex-end;
min-width: 90px;
max-width: 110px;
font-size: 13px;
pointer-events: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: left 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.version-timeline-group:hover .dot-label {
left: -110px; /* 悬停时向右移动,接近原点 */
}
.version-timeline-content.version-card {
background: #fff;
border-radius: 10px;
box-shadow: 0 2px 12px rgba(64, 158, 255, 0.08); /* 主色阴影 */
padding: 18px 18px 12px 18px;
margin-left: 0;
margin-top: 0;
margin-bottom: 0;
min-width: 0;
border: none;
transition: box-shadow 0.2s;
position: relative;
z-index: 2;
}
.version-timeline-group:hover .version-timeline-content.version-card {
box-shadow: 0 8px 24px rgba(64, 158, 255, 0.16);
}
.version-timeline-content.version-card::before {
content: '';
position: absolute;
left: -16px; /* 让箭头更靠近原点但不覆盖 */
top: 18px;
width: 0;
height: 0;
filter: drop-shadow(-2px 0 2px var(--gantt-timeline-line, #a0cfff));
z-index: 1;
}
.version-timeline-group:hover .version-timeline-content.version-card::before {
filter: drop-shadow(-2px 0 2px var(--gantt-primary, #409eff));
}
.version-notes {
margin: 0;
padding-left: 18px;
color: #aaa;
font-size: 14px;
list-style: disc;
transition: color 0.2s;
}
.version-timeline-group:hover .version-notes {
color: #333;
}
.dot-version {
font-weight: 700;
font-size: 16px;
color: var(--gantt-primary, #409eff); /* 统一主色 */
letter-spacing: 0.5px;
line-height: 1.2;
text-shadow: 0 1px 4px rgba(64, 158, 255, 0.08);
}
.dot-date {
color: #b0b3bb;
font-size: 12px;
margin-top: 2px;
font-weight: 400;
letter-spacing: 0.2px;
line-height: 1.1;
}
/* 暗黑主题适配完全对齐TaskDrawer风格 */
:global(html[data-theme='dark']) .version-history-drawer {
background: var(--gantt-bg-primary, #6b6b6b) !important;
box-shadow: 2px 0 24px rgba(0, 0, 0, 0.4) !important;
}
:global(html[data-theme='dark']) .drawer-header {
background: var(--gantt-bg-secondary, #4b4b4b) !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08) !important;
}
:global(html[data-theme='dark']) .drawer-title {
color: var(--gantt-text-white, #fff) !important;
}
:global(html[data-theme='dark']) .drawer-close-btn:hover {
background: var(--gantt-bg-hover, rgba(255, 255, 255, 0.1)) !important;
border-radius: 4px;
}
:global(html[data-theme='dark']) .drawer-body {
background: var(--gantt-bg-primary, #6b6b6b) !important;
scrollbar-color: #888888 #4b4b4b !important;
}
:global(html[data-theme='dark']) .drawer-body::-webkit-scrollbar-thumb {
background: #888888 !important;
}
:global(html[data-theme='dark']) .drawer-body::-webkit-scrollbar-track {
background: #4b4b4b !important;
}
:global(html[data-theme='dark']) .version-timeline-content.version-card {
background: var(--gantt-bg-secondary, #4b4b4b) !important;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.32) !important;
color: var(--gantt-text-white, #fff) !important;
}
:global(html[data-theme='dark'])
.version-timeline-group:hover
.version-timeline-content.version-card {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.44) !important;
}
:global(html[data-theme='dark']) .version-timeline-content.version-card::before {
filter: drop-shadow(-2px 0 2px #222) !important;
}
:global(html[data-theme='dark']) .dot-version {
color: var(--gantt-primary, #3399ff) !important;
text-shadow: 0 1px 4px rgba(51, 153, 255, 0.12) !important;
}
:global(html[data-theme='dark']) .dot-date {
color: #e0e0e0 !important;
}
:global(html[data-theme='dark']) .version-notes {
color: #e0e0e0 !important;
}
:global(html[data-theme='dark']) .version-timeline-dot {
background: var(--gantt-timeline-dot, #3399ff) !important;
box-shadow: 0 0 0 2px #222 !important;
}
:global(html[data-theme='dark']) .version-timeline-dot.latest {
background: var(--gantt-primary, #3399ff) !important;
}
:global(html[data-theme='dark']) .version-timeline-group:hover .version-timeline-dot {
background: var(--gantt-primary, #3399ff) !important;
}
:global(html[data-theme='dark']) .version-timeline::before {
background: repeating-linear-gradient(to bottom, #3399ff 0 8px, transparent 8px 16px) !important;
}
</style>