优化个人中心与界面交互
This commit is contained in:
@@ -382,8 +382,17 @@ watch(
|
||||
}
|
||||
|
||||
.legend-dot.active {
|
||||
border-color: var(--ctms-primary);
|
||||
box-shadow: 0 0 0 2px rgba(63, 93, 117, 0.18);
|
||||
position: relative;
|
||||
border: 3px solid #2f5f86;
|
||||
box-shadow: 0 0 0 3px rgba(47, 95, 134, 0.14);
|
||||
}
|
||||
|
||||
.legend-dot.active::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 2px;
|
||||
border-radius: inherit;
|
||||
background: #2f5f86;
|
||||
}
|
||||
|
||||
.legend-dot.pending {
|
||||
|
||||
@@ -100,7 +100,7 @@ const connectorClass = (status: StageStatus) => `connector-${status.toLowerCase(
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 4px;
|
||||
padding: 10px 0 4px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ const connectorClass = (status: StageStatus) => `connector-${status.toLowerCase(
|
||||
height: 2px;
|
||||
background-color: var(--ctms-border-color);
|
||||
border-radius: 999px;
|
||||
margin-top: 6px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.stage-connector::after {
|
||||
@@ -145,7 +145,9 @@ const connectorClass = (status: StageStatus) => `connector-${status.toLowerCase(
|
||||
}
|
||||
|
||||
.connector-in_progress {
|
||||
background: linear-gradient(90deg, var(--ctms-primary), rgba(63, 93, 117, 0.3));
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #2f5f86 0%, rgba(47, 95, 134, 0.42) 68%, rgba(47, 95, 134, 0.14) 100%);
|
||||
box-shadow: 0 2px 8px rgba(47, 95, 134, 0.18);
|
||||
}
|
||||
|
||||
.connector-blocked {
|
||||
@@ -158,8 +160,10 @@ const connectorClass = (status: StageStatus) => `connector-${status.toLowerCase(
|
||||
}
|
||||
|
||||
.connector-in_progress::after {
|
||||
border-top-color: var(--ctms-primary);
|
||||
border-right-color: var(--ctms-primary);
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-top-color: #2f5f86;
|
||||
border-right-color: #2f5f86;
|
||||
}
|
||||
|
||||
.connector-blocked::after {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
const readStageNode = () => readFileSync(resolve(__dirname, "./StageNode.vue"), "utf8");
|
||||
const readCenterProgressRow = () => readFileSync(resolve(__dirname, "./CenterProgressRow.vue"), "utf8");
|
||||
const readProjectOverview = () => readFileSync(resolve(__dirname, "../ProjectOverview.vue"), "utf8");
|
||||
|
||||
describe("project overview stage progress styling", () => {
|
||||
it("makes the in-progress stage visually distinct from pending stages", () => {
|
||||
const source = readStageNode();
|
||||
|
||||
expect(source).toContain(".stage-in_progress .stage-dot");
|
||||
expect(source).toContain("border: 3px solid #2f5f86");
|
||||
expect(source).toContain(".stage-in_progress .stage-dot::after");
|
||||
expect(source).toContain(".stage-in_progress .stage-dot::before");
|
||||
expect(source).toContain("animation: progress-halo");
|
||||
expect(source).toContain(".stage-in_progress .stage-label");
|
||||
expect(source).toContain("font-weight: 800");
|
||||
});
|
||||
|
||||
it("highlights the active connector and legend consistently", () => {
|
||||
const rowSource = readCenterProgressRow();
|
||||
const overviewSource = readProjectOverview();
|
||||
|
||||
expect(rowSource).toContain(".connector-in_progress");
|
||||
expect(rowSource).toContain("height: 3px");
|
||||
expect(rowSource).toContain("linear-gradient(90deg, #2f5f86");
|
||||
expect(overviewSource).toContain(".legend-dot.active::after");
|
||||
expect(overviewSource).toContain("background: #2f5f86");
|
||||
});
|
||||
});
|
||||
@@ -44,11 +44,14 @@ const statusClass = computed(() => `stage-${props.status.toLowerCase()}`);
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
min-width: 64px;
|
||||
position: relative;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.stage-dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
position: relative;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--ctms-border-color);
|
||||
background-color: #ffffff;
|
||||
@@ -60,7 +63,7 @@ const statusClass = computed(() => `stage-${props.status.toLowerCase()}`);
|
||||
color: var(--ctms-text-secondary);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
transition: color 0.2s ease;
|
||||
transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.stage-date {
|
||||
@@ -80,15 +83,55 @@ const statusClass = computed(() => `stage-${props.status.toLowerCase()}`);
|
||||
}
|
||||
|
||||
.stage-in_progress .stage-dot {
|
||||
border-color: var(--ctms-primary);
|
||||
box-shadow: 0 0 0 3px rgba(63, 93, 117, 0.15);
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 3px solid #2f5f86;
|
||||
background-color: #ffffff;
|
||||
animation: pulse-ring 2s ease-in-out infinite;
|
||||
box-shadow:
|
||||
0 0 0 4px rgba(47, 95, 134, 0.14),
|
||||
0 6px 14px rgba(47, 95, 134, 0.22);
|
||||
animation: progress-ring 1.8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-ring {
|
||||
0%, 100% { box-shadow: 0 0 0 3px rgba(63, 93, 117, 0.15); }
|
||||
50% { box-shadow: 0 0 0 5px rgba(63, 93, 117, 0.08); }
|
||||
.stage-in_progress .stage-dot::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 3px;
|
||||
border-radius: inherit;
|
||||
background: #2f5f86;
|
||||
}
|
||||
|
||||
.stage-in_progress .stage-dot::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -8px;
|
||||
border-radius: inherit;
|
||||
border: 1px solid rgba(47, 95, 134, 0.24);
|
||||
animation: progress-halo 1.8s ease-out infinite;
|
||||
}
|
||||
|
||||
@keyframes progress-ring {
|
||||
0%, 100% {
|
||||
box-shadow:
|
||||
0 0 0 4px rgba(47, 95, 134, 0.14),
|
||||
0 6px 14px rgba(47, 95, 134, 0.22);
|
||||
}
|
||||
50% {
|
||||
box-shadow:
|
||||
0 0 0 6px rgba(47, 95, 134, 0.08),
|
||||
0 8px 18px rgba(47, 95, 134, 0.26);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes progress-halo {
|
||||
0% {
|
||||
opacity: 0.65;
|
||||
transform: scale(0.82);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(1.25);
|
||||
}
|
||||
}
|
||||
|
||||
.stage-not_started .stage-dot {
|
||||
@@ -108,8 +151,13 @@ const statusClass = computed(() => `stage-${props.status.toLowerCase()}`);
|
||||
}
|
||||
|
||||
.stage-in_progress .stage-label {
|
||||
color: var(--ctms-primary);
|
||||
font-weight: 600;
|
||||
margin-top: 1px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
color: #244966;
|
||||
background: rgba(47, 95, 134, 0.1);
|
||||
box-shadow: inset 0 0 0 1px rgba(47, 95, 134, 0.14);
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.stage-blocked .stage-label {
|
||||
|
||||
Reference in New Issue
Block a user