diff --git a/src/components/cards/WorkflowTaskCard.vue b/src/components/cards/WorkflowTaskCard.vue index 6643952e..5585cc90 100644 --- a/src/components/cards/WorkflowTaskCard.vue +++ b/src/components/cards/WorkflowTaskCard.vue @@ -541,6 +541,14 @@ const executionStatus = computed(() => { .workflow-task-card { --workflow-status-rgb: var(--v-theme-info); --workflow-status-on-rgb: var(--v-theme-on-info); + --workflow-card-header-content-rgb: var(--workflow-status-on-rgb); + --workflow-card-header-background: linear-gradient( + 118deg, + color-mix(in srgb, rgb(var(--workflow-status-rgb)) 88%, rgb(var(--v-theme-on-surface)) 12%) 0%, + rgb(var(--workflow-status-rgb)) 52%, + color-mix(in srgb, rgb(var(--workflow-status-rgb)) 78%, rgb(var(--v-theme-surface)) 22%) 100% + ); + --workflow-card-header-shadow: none; display: flex; min-block-size: 226px; @@ -581,25 +589,20 @@ const executionStatus = computed(() => { .workflow-task-card__header { flex: 0 0 auto; padding: 6px 10px !important; - border-block-end: 1px solid rgba(var(--workflow-status-on-rgb), 0.18); - background: linear-gradient( - 118deg, - color-mix(in srgb, rgb(var(--workflow-status-rgb)) 88%, rgb(var(--v-theme-on-surface)) 12%) 0%, - rgb(var(--workflow-status-rgb)) 52%, - color-mix(in srgb, rgb(var(--workflow-status-rgb)) 78%, rgb(var(--v-theme-surface)) 22%) 100% - ); + background: var(--workflow-card-header-background); + box-shadow: var(--workflow-card-header-shadow); } .workflow-task-card__trigger-icon { flex: 0 0 auto; - color: rgb(var(--workflow-status-on-rgb)) !important; + color: rgb(var(--workflow-card-header-content-rgb)) !important; } .workflow-task-card__title { display: -webkit-box; min-inline-size: 0; overflow: hidden; - color: rgb(var(--workflow-status-on-rgb)); + color: rgb(var(--workflow-card-header-content-rgb)); font-weight: 500; line-height: 20px !important; letter-spacing: 0; @@ -613,7 +616,7 @@ const executionStatus = computed(() => { min-inline-size: 0; margin-block-start: 1px; overflow: hidden; - color: rgba(var(--workflow-status-on-rgb), 0.78); + color: rgba(var(--workflow-card-header-content-rgb), 0.78); font-size: 0.75rem; letter-spacing: 0; line-height: 16px !important; @@ -623,7 +626,7 @@ const executionStatus = computed(() => { .workflow-task-card__menu { flex: 0 0 auto; - color: rgb(var(--workflow-status-on-rgb)) !important; + color: rgb(var(--workflow-card-header-content-rgb)) !important; } .workflow-task-card__body { diff --git a/src/components/cards/__tests__/WorkflowTaskCard.spec.ts b/src/components/cards/__tests__/WorkflowTaskCard.spec.ts index 8c058241..be8b4dc3 100644 --- a/src/components/cards/__tests__/WorkflowTaskCard.spec.ts +++ b/src/components/cards/__tests__/WorkflowTaskCard.spec.ts @@ -167,6 +167,8 @@ describe('WorkflowTaskCard redesign', () => { it('derives all custom card colors and geometry from global theme tokens', () => { const source = readFileSync('src/components/cards/WorkflowTaskCard.vue', 'utf8') + const transparentTheme = readFileSync('src/styles/themes/transparent.scss', 'utf8') + const glassTheme = readFileSync('src/styles/themes/glass.scss', 'utf8') expect(source).toContain('var(--v-theme-primary)') expect(source).toContain('var(--v-theme-info)') @@ -176,6 +178,16 @@ describe('WorkflowTaskCard redesign', () => { expect(source).toContain('var(--v-theme-on-surface)') expect(source).toContain('var(--app-control-radius)') expect(source).toContain('linear-gradient(') + expect(source).toContain('var(--workflow-card-header-background)') + expect(source).not.toContain('--workflow-card-header-border') expect(source).not.toMatch(/#[\da-f]{3,8}\b/i) + + expect(transparentTheme).toContain('.workflow-task-card') + expect(transparentTheme).toContain('var(--transparent-opacity-heavy)') + expect(transparentTheme).not.toContain('--workflow-card-header-border') + expect(glassTheme).toContain('var(--glass-sheen)') + expect(glassTheme).toContain("&[data-glass-appearance='frosted'] .workflow-task-card") + expect(glassTheme).toContain("&[data-glass-appearance='tinted'] .workflow-task-card") + expect(glassTheme).not.toContain('--workflow-card-header-border') }) }) diff --git a/src/styles/themes/glass.scss b/src/styles/themes/glass.scss index 989ce7e7..73f5b350 100644 --- a/src/styles/themes/glass.scss +++ b/src/styles/themes/glass.scss @@ -852,6 +852,24 @@ html[data-theme='glass'] { backdrop-filter: var(--glass-surface-backdrop-filter); } + // 工作流标题栏复用卡片的背景采样,只叠加状态色、吸收层与玻璃高光。 + .workflow-task-card { + --workflow-card-header-content-rgb: var(--v-theme-on-surface); + --workflow-card-header-background: + var(--glass-sheen), + linear-gradient( + 118deg, + rgba(var(--workflow-status-rgb), calc(0.16 + var(--glass-tint-density, 0.65) * 0.34)) 0%, + rgba(var(--workflow-status-rgb), calc(0.09 + var(--glass-tint-density, 0.65) * 0.22)) 58%, + rgba(var(--workflow-status-rgb), calc(0.04 + var(--glass-tint-density, 0.65) * 0.1)) 100% + ), + linear-gradient( + rgba(var(--v-theme-background), calc(0.08 + var(--glass-surface-density, 0.62) * 0.08)), + rgba(var(--v-theme-background), calc(0.14 + var(--glass-surface-density, 0.62) * 0.12)) + ); + --workflow-card-header-shadow: inset 0 1px 0 var(--glass-highlight), inset 0 -1px 0 rgba(2, 6, 16, 14%); + } + // 插件卡片头部改为染色玻璃:图标主色只作为透光色相,压暗遮罩换成玻璃吸收与高光。 .plugin-card__banner { border-block-end: 1px solid var(--glass-border); @@ -896,6 +914,21 @@ html[data-theme='glass'] { ); } + &[data-glass-appearance='frosted'] .workflow-task-card { + --workflow-card-header-background: + var(--glass-sheen), + linear-gradient( + 118deg, + rgba(var(--workflow-status-rgb), calc(0.1 + var(--glass-tint-density, 0.65) * 0.2)) 0%, + rgba(var(--workflow-status-rgb), calc(0.05 + var(--glass-tint-density, 0.65) * 0.13)) 58%, + rgba(var(--workflow-status-rgb), calc(0.02 + var(--glass-tint-density, 0.65) * 0.06)) 100% + ), + linear-gradient( + rgba(var(--v-theme-background), calc(0.04 + var(--glass-surface-density, 0.86) * 0.04)), + rgba(var(--v-theme-background), calc(0.08 + var(--glass-surface-density, 0.86) * 0.08)) + ); + } + // 色调材质本身带主色语义,头部染色向主色收敛保持整页同一色温。 &[data-glass-appearance='tinted'] .plugin-card__banner { --plugin-card-banner-tint: linear-gradient( @@ -916,6 +949,31 @@ html[data-theme='glass'] { ); } + &[data-glass-appearance='tinted'] .workflow-task-card { + --workflow-card-header-background: + var(--glass-sheen), + linear-gradient( + 118deg, + color-mix( + in srgb, + rgba(var(--workflow-status-rgb), calc(0.14 + var(--glass-tint-density, 0.65) * 0.33)) 74%, + rgba(var(--v-theme-primary), calc(0.14 + var(--glass-tint-density, 0.65) * 0.33)) + ) + 0%, + color-mix( + in srgb, + rgba(var(--workflow-status-rgb), calc(0.07 + var(--glass-tint-density, 0.65) * 0.2)) 74%, + rgba(var(--v-theme-primary), calc(0.07 + var(--glass-tint-density, 0.65) * 0.2)) + ) + 58%, + rgba(var(--workflow-status-rgb), calc(0.04 + var(--glass-tint-density, 0.65) * 0.095)) 100% + ), + linear-gradient( + rgba(var(--v-theme-background), calc(0.08 + var(--glass-surface-density, 0.72) * 0.08)), + rgba(var(--v-theme-background), calc(0.14 + var(--glass-surface-density, 0.72) * 0.12)) + ); + } + // 文件夹卡片保留用户自选渐变作为色相,只降低不透明度让卡片本体的玻璃透出来。 .plugin-folder-card__bg { opacity: calc(0.34 + var(--glass-surface-density, 0.62) * 0.145); diff --git a/src/styles/themes/transparent.scss b/src/styles/themes/transparent.scss index 1289bb13..58bc13f1 100644 --- a/src/styles/themes/transparent.scss +++ b/src/styles/themes/transparent.scss @@ -49,6 +49,24 @@ html[data-theme="transparent"] { } } + // 工作流标题栏只叠加半透明状态染色,底层模糊仍由卡片统一承担。 + .workflow-task-card { + --workflow-card-header-content-rgb: var(--v-theme-on-surface); + --workflow-card-header-background: + linear-gradient(145deg, rgba(var(--v-theme-on-surface), 0.12), transparent 36%), + linear-gradient( + 118deg, + rgba(var(--workflow-status-rgb), var(--transparent-opacity-heavy)) 0%, + rgba(var(--workflow-status-rgb), var(--transparent-opacity)) 56%, + rgba(var(--workflow-status-rgb), var(--transparent-opacity-light)) 100% + ), + linear-gradient( + rgba(var(--v-theme-surface), var(--transparent-opacity-light)), + rgba(var(--v-theme-surface), var(--transparent-opacity-light)) + ); + --workflow-card-header-shadow: inset 0 1px 0 rgba(var(--v-theme-on-surface), 0.14); + } + // 订阅文件弹窗使用独立的玻璃表面参数,避免组件内通过全局选择器穿透主题。 .subscribe-files-dialog { --sfd-accent-opacity: 0.12;