v1.8.1 - hotfix - move theme settings from HTML root to Gantt Component root.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -37,3 +37,4 @@ ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
yarn.lock
|
||||
.ai/
|
||||
|
||||
@@ -1864,7 +1864,6 @@ const handleCustomMenuAction = (action: string, task: Task) => {
|
||||
:tasks="tasks"
|
||||
:milestones="milestones"
|
||||
:locale="controlMode === 'props' ? propsLocale : undefined"
|
||||
:theme="controlMode === 'props' ? propsTheme : undefined"
|
||||
:time-scale="controlMode === 'props' ? propsTimeScale : undefined"
|
||||
:fullscreen="controlMode === 'props' ? propsFullscreen : undefined"
|
||||
:expand-all="controlMode === 'props' ? propsExpandAll : undefined"
|
||||
|
||||
@@ -492,5 +492,19 @@
|
||||
"🎉 Optimized: The assignee and avatar properties of the Task object now accept arrays to mark multiple assignees",
|
||||
"<span style=\"font-weight: bold; color: #f00;\">Special thanks to yunlbs/fhjfhj/jakepan@gitee for their use and suggestions</span>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.8.1",
|
||||
"date": "2026-02-05",
|
||||
"notes": [
|
||||
"🎉 优化:重构组件,Theme作用域从全局调整至局部.gantt-root",
|
||||
"🎉 优化:重构组件,Theme自动跟随系统设置",
|
||||
"🎉 优化:重构组件,完美支持Nuxt3、TailwindCSS等框架",
|
||||
"<span style=\"font-weight: bold; color: #f00;\">特别感谢andrijor@gmail.com的专业反馈</span>",
|
||||
"🎉 Optimized: Refactored components, Theme scope adjusted from global to local .gantt-root",
|
||||
"🎉 Optimized: Refactored components, Theme automatically follows system settings",
|
||||
"🎉 Optimized: Refactored components, Perfectly supports Nuxt3, TailwindCSS and other frameworks",
|
||||
"<span style=\"font-weight: bold; color: #f00;\">Special thanks to andrijor@gmail.com for their professional feedback</span>"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jordium-gantt-vue3",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"type": "module",
|
||||
"main": "npm-package/dist/jordium-gantt-vue3.cjs.js",
|
||||
"module": "npm-package/dist/jordium-gantt-vue3.es.js",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
const props = defineProps({
|
||||
@@ -78,7 +78,7 @@ const messageTaskName = computed(() => {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .confirm-timer-dialog {
|
||||
:global(.gantt-root[data-theme='dark']) .confirm-timer-dialog {
|
||||
background: var(--gantt-bg-primary, #6b6b6b);
|
||||
}
|
||||
.dialog-message {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
|
||||
@@ -1519,48 +1519,48 @@ const timePickerStyle = computed(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式适配 */
|
||||
:global(html[data-theme='dark']) .el-input__wrapper {
|
||||
:global(.gantt-root[data-theme='dark']) .el-input__wrapper {
|
||||
background-color: var(--gantt-bg-secondary, #2c2c2c);
|
||||
box-shadow: 0 0 0 1px var(--gantt-border-dark, #414243) inset;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-input__inner,
|
||||
:global(html[data-theme='dark']) .el-range-input__start,
|
||||
:global(html[data-theme='dark']) .el-range-input__end,
|
||||
:global(html[data-theme='dark']) .el-range-separator {
|
||||
:global(.gantt-root[data-theme='dark']) .el-input__inner,
|
||||
:global(.gantt-root[data-theme='dark']) .el-range-input__start,
|
||||
:global(.gantt-root[data-theme='dark']) .el-range-input__end,
|
||||
:global(.gantt-root[data-theme='dark']) .el-range-separator {
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-input__inner-input::placeholder,
|
||||
:global(html[data-theme='dark']) .el-range-input__start::placeholder,
|
||||
:global(html[data-theme='dark']) .el-range-input__end::placeholder {
|
||||
:global(.gantt-root[data-theme='dark']) .el-input__inner-input::placeholder,
|
||||
:global(.gantt-root[data-theme='dark']) .el-range-input__start::placeholder,
|
||||
:global(.gantt-root[data-theme='dark']) .el-range-input__end::placeholder {
|
||||
color: var(--gantt-text-muted, #9e9e9e);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-picker.is-focused .el-input__wrapper {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker.is-focused .el-input__wrapper {
|
||||
box-shadow: 0 0 0 1px var(--gantt-primary, #409eff) inset;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-picker:hover .el-input__wrapper {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker:hover .el-input__wrapper {
|
||||
box-shadow: 0 0 0 1px var(--gantt-border-hover, #606266) inset;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-picker.is-focused:hover .el-input__wrapper {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker.is-focused:hover .el-input__wrapper {
|
||||
box-shadow: 0 0 0 1px var(--gantt-primary, #409eff) inset;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-picker.is-disabled .el-input__wrapper {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker.is-disabled .el-input__wrapper {
|
||||
background-color: var(--gantt-bg-disabled, #3c3e40);
|
||||
box-shadow: 0 0 0 1px var(--gantt-border-disabled, #4c4d4f) inset;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-picker.is-disabled .el-input__inner,
|
||||
:global(html[data-theme='dark']) .el-date-picker.is-disabled .el-range-input__start,
|
||||
:global(html[data-theme='dark']) .el-date-picker.is-disabled .el-range-input__end {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker.is-disabled .el-input__inner,
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker.is-disabled .el-range-input__start,
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker.is-disabled .el-range-input__end {
|
||||
color: var(--gantt-text-disabled, #73767a);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-input__clear:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .el-input__clear:hover {
|
||||
color: var(--gantt-text-secondary, #909399);
|
||||
}
|
||||
|
||||
@@ -1894,51 +1894,51 @@ const timePickerStyle = computed(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式下的日期选择器面板 */
|
||||
:global(html[data-theme='dark']) .el-picker-panel {
|
||||
:global(.gantt-root[data-theme='dark']) .el-picker-panel {
|
||||
background: var(--gantt-bg-secondary, #2c2c2c);
|
||||
border-color: var(--gantt-border-dark, #414243);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-picker__header {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker__header {
|
||||
border-bottom-color: var(--gantt-border-dark, #414243);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-picker__header-label {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker__header-label {
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-picker-panel__icon-btn {
|
||||
:global(.gantt-root[data-theme='dark']) .el-picker-panel__icon-btn {
|
||||
color: var(--gantt-text-secondary, #909399);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-picker-panel__icon-btn:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .el-picker-panel__icon-btn:hover {
|
||||
background: var(--gantt-bg-hover-dark, #3c3e40);
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-table__header-cell {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-table__header-cell {
|
||||
color: var(--gantt-text-secondary, #909399);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-table__cell:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-table__cell:hover {
|
||||
background: var(--gantt-bg-hover-dark, #3c3e40);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-table__cell-inner {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-table__cell-inner {
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-table__cell.is-other-month .el-date-table__cell-inner {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-table__cell.is-other-month .el-date-table__cell-inner {
|
||||
color: var(--gantt-text-muted, #73767a);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-date-table__cell.is-in-range {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-table__cell.is-in-range {
|
||||
background: rgba(64, 158, 255, 0.2);
|
||||
}
|
||||
|
||||
/* 暗黑模式下的日期选择器确认按钮 */
|
||||
:global(html[data-theme='dark']) .el-date-picker-footer {
|
||||
:global(.gantt-root[data-theme='dark']) .el-date-picker-footer {
|
||||
border-top-color: var(--gantt-border-dark, #414243);
|
||||
}
|
||||
|
||||
@@ -2182,69 +2182,69 @@ const timePickerStyle = computed(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式下的时间选择器 */
|
||||
:global(html[data-theme='dark']) .el-time-picker-input {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-picker-input {
|
||||
border-top-color: var(--gantt-border-dark, #414243);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-picker-label {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-picker-label {
|
||||
color: var(--gantt-text-secondary, #909399);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-input {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-input {
|
||||
background: var(--gantt-bg-secondary, #2c2c2c);
|
||||
border-color: var(--gantt-border-dark, #414243);
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-input:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-input:hover {
|
||||
border-color: var(--gantt-border-hover, #606266);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-picker-panel {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-picker-panel {
|
||||
background: var(--gantt-bg-secondary, #2c2c2c);
|
||||
border-color: var(--gantt-border-dark, #414243);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-picker-header {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-picker-header {
|
||||
border-bottom-color: var(--gantt-border-dark, #414243);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-picker-title {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-picker-title {
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-column-header {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-column-header {
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-column-list {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-column-list {
|
||||
border-color: var(--gantt-border-dark, #414243);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-column-list:hover::-webkit-scrollbar-thumb {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-column-list:hover::-webkit-scrollbar-thumb {
|
||||
background: var(--gantt-border-hover, #606266);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-item {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-item {
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-item:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-item:hover {
|
||||
background: var(--gantt-bg-hover-dark, #3c3e40);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-picker-footer {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-picker-footer {
|
||||
border-top-color: var(--gantt-border-dark, #414243);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-picker-btn--cancel {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-picker-btn--cancel {
|
||||
background: var(--gantt-bg-secondary, #2c2c2c);
|
||||
border-color: var(--gantt-border-dark, #414243);
|
||||
color: var(--gantt-text-white, #ffffff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .el-time-picker-btn--cancel:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .el-time-picker-btn--cancel:hover {
|
||||
background: var(--gantt-bg-hover-dark, #3c3e40);
|
||||
border-color: var(--gantt-border-hover, #606266);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, onUnmounted, onMounted, computed, watch, nextTick, useSlots, provide } from 'vue'
|
||||
import type { StyleValue } from 'vue'
|
||||
import TaskList from './TaskList/TaskList.vue'
|
||||
@@ -27,6 +27,9 @@ import type { TaskBarConfig } from '../models/configs/TaskBarConfig'
|
||||
import { TimelineScale, SCALE_CONFIGS } from '../models/types/TimelineScale'
|
||||
import { useMessage } from '../composables/useMessage'
|
||||
|
||||
// 根元素引用
|
||||
const ganttRootRef = ref<HTMLElement>()
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
tasks: () => [],
|
||||
milestones: () => [],
|
||||
@@ -65,7 +68,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
expandAll: true,
|
||||
locale: 'zh-CN',
|
||||
timeScale: 'week',
|
||||
theme: 'light',
|
||||
theme: undefined, // 不设置默认值,允许自动检测系统主题
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
@@ -111,6 +114,20 @@ provide('enable-task-bar-context-menu', computed(() => props.enableTaskBarContex
|
||||
// 提供 LinkAnchor 配置给子组件
|
||||
provide('enable-link-anchor', computed(() => props.enableLinkAnchor))
|
||||
|
||||
// 检测系统主题偏好
|
||||
const detectSystemTheme = (): 'light' | 'dark' => {
|
||||
if (typeof window !== 'undefined' && window.matchMedia) {
|
||||
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
return isDark ? 'dark' : 'light'
|
||||
}
|
||||
return 'light'
|
||||
}
|
||||
|
||||
// 提供当前主题给子组件(用于GanttLinks等组件)
|
||||
// 初始值:先设置为'light',在onMounted中根据props或系统主题设置
|
||||
const currentThemeMode = ref<'light' | 'dark'>('light')
|
||||
provide('gantt-theme', currentThemeMode)
|
||||
|
||||
// 使用声明式右键菜单 composables
|
||||
const { hasDeclarativeContextMenu: hasDeclarativeTaskListContextMenu, declarativeContextMenu: declarativeTaskListContextMenu } =
|
||||
useTaskListContextMenu(slots)
|
||||
@@ -238,7 +255,6 @@ interface Props {
|
||||
// 总计: 1160px (已在 TaskListConfig 中定义)
|
||||
|
||||
// 甘特图容器宽度
|
||||
const ganttRootRef = ref<HTMLElement | null>(null)
|
||||
const ganttContainerWidth = ref(1920) // 默认使用常见的屏幕宽度作为初始值
|
||||
|
||||
// 监听容器宽度变化
|
||||
@@ -295,6 +311,16 @@ onMounted(() => {
|
||||
updateContainerWidth()
|
||||
// 使用节流版本监听窗口大小变化
|
||||
window.addEventListener('resize', throttledUpdateContainerWidth)
|
||||
|
||||
// 确保主题在DOM挂载后正确应用
|
||||
nextTick(() => {
|
||||
if (ganttRootRef.value) {
|
||||
// 如果明确设置了props.theme,使用设置的值;否则检测系统主题
|
||||
const initialTheme = props.theme ?? detectSystemTheme()
|
||||
ganttRootRef.value.setAttribute('data-theme', initialTheme)
|
||||
currentThemeMode.value = initialTheme
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -940,8 +966,7 @@ onUnmounted(() => {
|
||||
window.removeEventListener('context-menu', handleTaskContextMenu as EventListener)
|
||||
})
|
||||
|
||||
// 主题状态管理
|
||||
const currentThemeMode = ref<'light' | 'dark'>('light')
|
||||
// 主题状态管理(已在上面provide部分定义)
|
||||
|
||||
/**
|
||||
* 设置主题模式
|
||||
@@ -950,7 +975,10 @@ const currentThemeMode = ref<'light' | 'dark'>('light')
|
||||
const setTheme = (mode?: 'light' | 'dark') => {
|
||||
const targetMode = mode || 'dark'
|
||||
currentThemeMode.value = targetMode
|
||||
document.documentElement.setAttribute('data-theme', targetMode)
|
||||
// 在组件根元素上设置data-theme,而不是document.documentElement
|
||||
if (ganttRootRef.value) {
|
||||
ganttRootRef.value.setAttribute('data-theme', targetMode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -964,13 +992,37 @@ const currentTheme = (): string => {
|
||||
watch(
|
||||
() => props.theme,
|
||||
(newTheme) => {
|
||||
if (newTheme && newTheme !== currentThemeMode.value) {
|
||||
setTheme(newTheme)
|
||||
// 只在组件已挂载后处理
|
||||
if (!ganttRootRef.value) return
|
||||
|
||||
// 如果明确设置了theme,使用设置的值;如果是undefined,检测系统主题
|
||||
const targetTheme = newTheme ?? detectSystemTheme()
|
||||
if (targetTheme !== currentThemeMode.value) {
|
||||
setTheme(targetTheme)
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// 监听系统主题变化(仅在未明确设置theme时生效)
|
||||
if (typeof window !== 'undefined' && window.matchMedia) {
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
const handleSystemThemeChange = (e: MediaQueryListEvent) => {
|
||||
// 只有在用户未明确设置theme prop时才跟随系统
|
||||
if (!props.theme) {
|
||||
const systemTheme = e.matches ? 'dark' : 'light'
|
||||
setTheme(systemTheme)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加监听器
|
||||
mediaQuery.addEventListener('change', handleSystemThemeChange)
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
mediaQuery.removeEventListener('change', handleSystemThemeChange)
|
||||
})
|
||||
}
|
||||
|
||||
// 全屏状态管理
|
||||
const isFullscreen = ref(false)
|
||||
|
||||
@@ -1599,6 +1651,12 @@ const handleTimelineScaleChanged = (scale: TimelineScale) => {
|
||||
})
|
||||
}
|
||||
|
||||
// 主题变化处理函数
|
||||
const handleThemeChange = (isDark: boolean) => {
|
||||
const newTheme = isDark ? 'dark' : 'light'
|
||||
setTheme(newTheme)
|
||||
}
|
||||
|
||||
// === 时间维度相关方法 ===
|
||||
// 时间刻度顺序定义
|
||||
const TIME_SCALE_ORDER: TimelineScale[] = ['hour', 'day', 'week', 'month', 'quarter', 'year']
|
||||
@@ -2755,6 +2813,7 @@ defineExpose({
|
||||
@add-milestone="milestoneAddHandler"
|
||||
@expand-all="handleExpandAll"
|
||||
@collapse-all="handleCollapseAll"
|
||||
@theme-change="handleThemeChange"
|
||||
/>
|
||||
|
||||
<!-- 甘特图主体 -->
|
||||
@@ -3111,42 +3170,42 @@ defineExpose({
|
||||
}
|
||||
|
||||
/* 暗色主题支持 */
|
||||
:global(html[data-theme='dark']) .gantt-root {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-root {
|
||||
background: #1e1e1e !important;
|
||||
color: #e5e5e5 !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-panel {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-panel {
|
||||
background: #2c2c2c !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-panel-left {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-panel-left {
|
||||
border-right-color: #4c4c4c !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .focus-close-button {
|
||||
:global(.gantt-root[data-theme='dark']) .focus-close-button {
|
||||
background: #d85555;
|
||||
border-color: #d85555;
|
||||
box-shadow: 0 4px 12px rgba(216, 85, 85, 0.4);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .focus-close-button:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .focus-close-button:hover {
|
||||
background: #e67676;
|
||||
border-color: #e67676;
|
||||
box-shadow: 0 6px 16px rgba(216, 85, 85, 0.5);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .focus-close-button .close-icon,
|
||||
:global(html[data-theme='dark']) .focus-close-button .close-text {
|
||||
:global(.gantt-root[data-theme='dark']) .focus-close-button .close-icon,
|
||||
:global(.gantt-root[data-theme='dark']) .focus-close-button .close-text {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .focus-close-button:hover .close-icon,
|
||||
:global(html[data-theme='dark']) .focus-close-button:hover .close-text {
|
||||
:global(.gantt-root[data-theme='dark']) .focus-close-button:hover .close-icon,
|
||||
:global(.gantt-root[data-theme='dark']) .focus-close-button:hover .close-text {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-splitter {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-splitter {
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
@@ -3157,7 +3216,7 @@ defineExpose({
|
||||
box-shadow: inset 0 0 2px rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-splitter:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-splitter:hover {
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
@@ -3173,24 +3232,24 @@ defineExpose({
|
||||
}
|
||||
|
||||
/* 暗色主题支持 - TaskList切换按钮 */
|
||||
:global(html[data-theme='dark']) .task-list-toggle {
|
||||
:global(.gantt-root[data-theme='dark']) .task-list-toggle {
|
||||
background: rgba(42, 42, 42, 0.95) !important;
|
||||
border-color: #555555 !important;
|
||||
color: #cccccc !important;
|
||||
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-list-toggle.collapsed {
|
||||
:global(.gantt-root[data-theme='dark']) .task-list-toggle.collapsed {
|
||||
box-shadow: -1px 1px 4px rgba(0, 0, 0, 0.4) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-list-toggle:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .task-list-toggle:hover {
|
||||
background: rgba(42, 42, 42, 1) !important;
|
||||
color: #569cd6 !important;
|
||||
box-shadow: 1px 2px 8px rgba(86, 156, 214, 0.3) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-list-toggle.collapsed:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .task-list-toggle.collapsed:hover {
|
||||
box-shadow: -1px 2px 8px rgba(86, 156, 214, 0.3) !important;
|
||||
}
|
||||
|
||||
@@ -3245,11 +3304,11 @@ defineExpose({
|
||||
}
|
||||
|
||||
/* 暗色主题下的全屏模式 */
|
||||
:global(html[data-theme='dark']) .gantt-fullscreen {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-fullscreen {
|
||||
background: #1e1e1e !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-fullscreen .gantt-toolbar {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-fullscreen .gantt-toolbar {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import '../styles/app.css'
|
||||
const props = defineProps({
|
||||
visible: Boolean,
|
||||
@@ -102,7 +102,7 @@ const onNo = () => emit('no')
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-confirm-dialog {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-confirm-dialog {
|
||||
background: var(--gantt-bg-secondary, #f8f9fa) !important;
|
||||
border-color: var(--gantt-border-dark, #999999) !important;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, nextTick, onMounted, onUnmounted } from 'vue'
|
||||
import { ref, watch, nextTick, onMounted, onUnmounted, computed, inject, type Ref } from 'vue'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
import { getPredecessorIds } from '../utils/predecessorUtils'
|
||||
import { CanvasContextManager } from '../utils/canvasUtils'
|
||||
@@ -32,6 +32,7 @@ interface Props {
|
||||
// 月份分隔线配置
|
||||
verticalLines?: VerticalLine[]
|
||||
showVerticalLines?: boolean
|
||||
// 主题模式通过inject获取,不再需要props
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -41,6 +42,9 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
offsetTop: 0,
|
||||
})
|
||||
|
||||
// 通过inject获取主题
|
||||
const injectedTheme = inject<Ref<'light' | 'dark'>>('gantt-theme', ref('light'))
|
||||
|
||||
// Canvas 引用
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
@@ -50,16 +54,9 @@ const canvasManager = new CanvasContextManager()
|
||||
// requestAnimationFrame 防抖控制
|
||||
let rafId: number | null = null
|
||||
let pendingRedraw = false
|
||||
let themeObserver: MutationObserver | null = null
|
||||
|
||||
// 当前主题(用于分隔线颜色)
|
||||
const isDarkTheme = ref(document.documentElement.getAttribute('data-theme') === 'dark')
|
||||
|
||||
// 监听主题变化
|
||||
const updateTheme = () => {
|
||||
isDarkTheme.value = document.documentElement.getAttribute('data-theme') === 'dark'
|
||||
scheduleRedraw()
|
||||
}
|
||||
const isDarkTheme = computed(() => injectedTheme.value === 'dark')
|
||||
|
||||
/**
|
||||
* 绘制关系线到 Canvas
|
||||
@@ -445,6 +442,7 @@ watch(
|
||||
() => props.showVerticalLines,
|
||||
() => props.offsetLeft, // 监听虚拟渲染的偏移量变化
|
||||
() => props.offsetTop,
|
||||
injectedTheme, // 监听inject的主题变化(computed会自动响应)
|
||||
],
|
||||
() => {
|
||||
// 使用 RAF 调度重绘,合并连续的多次变化为单次绘制
|
||||
@@ -455,21 +453,7 @@ watch(
|
||||
|
||||
// 组件挂载后初始化绘制
|
||||
onMounted(() => {
|
||||
// 监听主题变化
|
||||
themeObserver = new MutationObserver(mutations => {
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.attributeName === 'data-theme') {
|
||||
updateTheme()
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme'],
|
||||
})
|
||||
|
||||
// 不再监听 document.documentElement,直接使用props.theme
|
||||
nextTick(() => {
|
||||
drawLinks()
|
||||
})
|
||||
@@ -477,12 +461,6 @@ onMounted(() => {
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
// 清理主题观察器
|
||||
if (themeObserver) {
|
||||
themeObserver.disconnect()
|
||||
themeObserver = null
|
||||
}
|
||||
|
||||
// 取消待处理的 RAF
|
||||
if (rafId !== null) {
|
||||
cancelAnimationFrame(rafId)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
import type { ToolbarConfig } from '../models/configs/ToolbarConfig'
|
||||
@@ -117,7 +117,7 @@ watch(
|
||||
const newMode = newTheme === 'dark'
|
||||
if (isDarkMode.value !== newMode) {
|
||||
isDarkMode.value = newMode
|
||||
document.documentElement.setAttribute('data-theme', newTheme)
|
||||
// 不再直接设置document.documentElement,由GanttChart统一管理
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -304,7 +304,7 @@ const handleThemeToggle = () => {
|
||||
|
||||
// 立即应用主题变化
|
||||
isDarkMode.value = newTheme
|
||||
document.documentElement.setAttribute('data-theme', newTheme ? 'dark' : 'light')
|
||||
// 不再直接设置document.documentElement,由GanttChart统一管理
|
||||
|
||||
// 立即触发主题变化事件
|
||||
if (props.onThemeChange && typeof props.onThemeChange === 'function') {
|
||||
@@ -447,23 +447,12 @@ onMounted(() => {
|
||||
const currentLocale = locale.value
|
||||
currentLanguage.value = currentLocale === 'zh-CN' ? 'zh' : 'en'
|
||||
|
||||
// 初始化主题状态并应用到DOM
|
||||
document.documentElement.setAttribute('data-theme', isDarkMode.value ? 'dark' : 'light')
|
||||
// 不再直接设置document.documentElement,由GanttChart统一管理
|
||||
|
||||
// 添加点击外部关闭下拉菜单的监听
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
|
||||
// 监听系统主题变化(仅在用户未手动设置时)
|
||||
if (
|
||||
window.matchMedia &&
|
||||
typeof window !== 'undefined' &&
|
||||
!localStorage.getItem(THEME_STORAGE_KEY)
|
||||
) {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
|
||||
isDarkMode.value = e.matches
|
||||
document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light')
|
||||
})
|
||||
}
|
||||
// 不再监听系统主题变化,由GanttChart统一管理
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -1058,34 +1047,34 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式样式 */
|
||||
:global(html[data-theme='dark']) .toolbar-icon-btn:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .toolbar-icon-btn:hover {
|
||||
background: var(--gantt-bg-hover, rgba(255, 255, 255, 0.08));
|
||||
color: var(--gantt-primary, #66b1ff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .toolbar-icon-btn:focus {
|
||||
:global(.gantt-root[data-theme='dark']) .toolbar-icon-btn:focus {
|
||||
background: var(--gantt-bg-hover, rgba(255, 255, 255, 0.1));
|
||||
color: var(--gantt-primary, #66b1ff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .toolbar-lang-btn:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .toolbar-lang-btn:hover {
|
||||
background: var(--gantt-bg-hover, rgba(255, 255, 255, 0.06));
|
||||
border-color: var(--gantt-primary, #66b1ff);
|
||||
color: var(--gantt-primary, #66b1ff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .toolbar-lang-btn:focus {
|
||||
:global(.gantt-root[data-theme='dark']) .toolbar-lang-btn:focus {
|
||||
background: var(--gantt-bg-hover, rgba(255, 255, 255, 0.08));
|
||||
border-color: var(--gantt-primary, #66b1ff);
|
||||
color: var(--gantt-primary, #66b1ff);
|
||||
box-shadow: 0 0 0 2px rgba(102, 177, 255, 0.4);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .dialog-content {
|
||||
:global(.gantt-root[data-theme='dark']) .dialog-content {
|
||||
background: var(--gantt-bg-secondary, #2c2c2c);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .dialog-message {
|
||||
:global(.gantt-root[data-theme='dark']) .dialog-message {
|
||||
color: var(--gantt-text-primary, #e5eaf3);
|
||||
}
|
||||
|
||||
@@ -1270,40 +1259,40 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式下的按钮组样式 */
|
||||
:global(html[data-theme='dark']) .gantt-btn-group {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-btn-group {
|
||||
box-shadow:
|
||||
0 1px 3px 0 rgba(0, 0, 0, 0.3),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-btn-group:hover,
|
||||
:global(html[data-theme='dark']) .gantt-btn-group:focus-within {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-btn-group:hover,
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-btn-group:focus-within {
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .add-btn-group .gantt-btn-group-item {
|
||||
:global(.gantt-root[data-theme='dark']) .add-btn-group .gantt-btn-group-item {
|
||||
background: #337ecc;
|
||||
border-color: #337ecc;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .add-btn-group .gantt-btn-group-item:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .add-btn-group .gantt-btn-group-item:hover {
|
||||
background: #4d94d4;
|
||||
border-color: #4d94d4;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .add-btn-group .gantt-btn-group-item:focus {
|
||||
:global(.gantt-root[data-theme='dark']) .add-btn-group .gantt-btn-group-item:focus {
|
||||
background: #2c5aa0;
|
||||
border-color: #2c5aa0;
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .add-btn-group .gantt-btn-group-item:active {
|
||||
:global(.gantt-root[data-theme='dark']) .add-btn-group .gantt-btn-group-item:active {
|
||||
background: #1f4872;
|
||||
border-color: #1f4872;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-btn-group:not(.gantt-add-btn-group) .gantt-btn-group-item {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-btn-group:not(.gantt-add-btn-group) .gantt-btn-group-item {
|
||||
background: #2c2c2c;
|
||||
border-color: #4c4c4c;
|
||||
color: #e5e5e5;
|
||||
@@ -1396,41 +1385,41 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式下的分段控制器样式 */
|
||||
:global(html[data-theme='dark']) .segmented-control {
|
||||
:global(.gantt-root[data-theme='dark']) .segmented-control {
|
||||
background: var(--gantt-bg-secondary, #4b4b4b);
|
||||
border-color: var(--gantt-border-color, #808080);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .segmented-control:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .segmented-control:hover {
|
||||
border-color: var(--gantt-primary, #3399ff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .segmented-thumb {
|
||||
:global(.gantt-root[data-theme='dark']) .segmented-thumb {
|
||||
background: var(--gantt-primary, #3399ff);
|
||||
box-shadow:
|
||||
0 1px 2px rgba(0, 0, 0, 0.3),
|
||||
0 1px 6px -1px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .segmented-item {
|
||||
:global(.gantt-root[data-theme='dark']) .segmented-item {
|
||||
color: #ffffff !important; /* 强制使用纯白色,更加突出 */
|
||||
}
|
||||
|
||||
/* 特别针对时间刻度分段控制器的暗黑模式样式 */
|
||||
:global(html[data-theme='dark']) .time-scale-segmented .segmented-item {
|
||||
:global(.gantt-root[data-theme='dark']) .time-scale-segmented .segmented-item {
|
||||
color: #ffffff !important; /* 确保时间刻度按钮也使用纯白色 */
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .segmented-item:hover:not(.active) {
|
||||
:global(.gantt-root[data-theme='dark']) .segmented-item:hover:not(.active) {
|
||||
color: var(--gantt-primary, #3399ff); /* 使用主色调,更加鲜艳 */
|
||||
background: rgba(51, 153, 255, 0.12); /* 调整背景透明度,与主色调匹配 */
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .segmented-item:active:not(.active) {
|
||||
:global(.gantt-root[data-theme='dark']) .segmented-item:active:not(.active) {
|
||||
background: rgba(51, 153, 255, 0.2); /* 调整背景透明度,与主色调匹配 */
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .segmented-item.active {
|
||||
:global(.gantt-root[data-theme='dark']) .segmented-item.active {
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onUnmounted } from 'vue'
|
||||
|
||||
interface Props {
|
||||
@@ -245,16 +245,16 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
/* 暗色主题支持 */
|
||||
:global(html[data-theme='dark']) .link-anchor {
|
||||
:global(.gantt-root[data-theme='dark']) .link-anchor {
|
||||
border-color: #1a1a1a;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .link-anchor.valid-target,
|
||||
:global(html[data-theme='dark']) .link-anchor.invalid-target {
|
||||
:global(.gantt-root[data-theme='dark']) .link-anchor.valid-target,
|
||||
:global(.gantt-root[data-theme='dark']) .link-anchor.invalid-target {
|
||||
border-color: #1a1a1a;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .anchor-tooltip {
|
||||
:global(.gantt-root[data-theme='dark']) .anchor-tooltip {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, computed } from 'vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
import DatePicker from './DatePicker.vue'
|
||||
@@ -792,12 +792,12 @@ const t = (key: string) => {
|
||||
}
|
||||
|
||||
/* 暗黑模式下的确认弹窗 */
|
||||
:global(html[data-theme='dark']) .milestone-confirm-dialog {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-confirm-dialog {
|
||||
background: var(--gantt-bg-dark, #1d1e1f);
|
||||
border-color: var(--gantt-border-dark, #3c3e40);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .milestone-confirm-footer {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-confirm-footer {
|
||||
background: var(--gantt-bg-darker, #141414);
|
||||
border-color: var(--gantt-border-dark, #3c3e40);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onUnmounted } from 'vue'
|
||||
import type { Milestone } from '../models/classes/Milestone'
|
||||
@@ -1067,23 +1067,23 @@ const calculateMilestonePositionFromTimelineData = (
|
||||
}
|
||||
|
||||
/* 暗黑模式下的适配 */
|
||||
:global(html[data-theme='dark']) .milestone-label {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-label {
|
||||
color: var(--gantt-text-white, #ffffff) !important;
|
||||
}
|
||||
|
||||
/* 暗黑模式下的粘性标签样式 */
|
||||
:global(html[data-theme='dark']) .milestone-label[style*='position: absolute'] {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-label[style*='position: absolute'] {
|
||||
background: rgba(30, 30, 30, 0.9) !important;
|
||||
border-color: rgba(246, 124, 124, 0.3) !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .milestone svg {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone svg {
|
||||
filter: drop-shadow(0 0 8px var(--gantt-danger, #f67c7c));
|
||||
animation: milestone-glow-dark 2s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .milestone:hover svg {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone:hover svg {
|
||||
filter: drop-shadow(0 0 16px var(--gantt-danger, #f67c7c))
|
||||
drop-shadow(0 0 24px rgba(246, 124, 124, 0.4));
|
||||
animation: milestone-glow-intense-dark 1.5s ease-in-out infinite alternate;
|
||||
@@ -1125,7 +1125,7 @@ const calculateMilestonePositionFromTimelineData = (
|
||||
animation: none;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .milestone.dragging svg {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone.dragging svg {
|
||||
filter: drop-shadow(0 0 20px var(--gantt-danger, #f67c7c))
|
||||
drop-shadow(0 0 32px rgba(246, 124, 124, 0.6));
|
||||
}
|
||||
@@ -1164,14 +1164,14 @@ const calculateMilestonePositionFromTimelineData = (
|
||||
}
|
||||
|
||||
/* 暗黑模式下的停靠状态样式 */
|
||||
:global(html[data-theme='dark']) .milestone-sticky-left svg,
|
||||
:global(html[data-theme='dark']) .milestone-sticky-right svg {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-sticky-left svg,
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-sticky-right svg {
|
||||
animation: milestone-glow-sticky-dark 3s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
/* 暗黑模式下半图标显示时取消发光效果 */
|
||||
:global(html[data-theme='dark']) .milestone-sticky-left svg[style*='clip-path'],
|
||||
:global(html[data-theme='dark']) .milestone-sticky-right svg[style*='clip-path'] {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-sticky-left svg[style*='clip-path'],
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-sticky-right svg[style*='clip-path'] {
|
||||
animation: none;
|
||||
filter: none;
|
||||
}
|
||||
@@ -1259,7 +1259,7 @@ const calculateMilestonePositionFromTimelineData = (
|
||||
}
|
||||
|
||||
/* 暗黑模式下的Tooltip样式 */
|
||||
:global(html[data-theme='dark']) .milestone-tooltip {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-tooltip {
|
||||
background: rgba(30, 30, 30, 0.95) !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
|
||||
@@ -184,17 +184,17 @@ watch(
|
||||
}
|
||||
|
||||
/* 暗黑模式 */
|
||||
:global(html[data-theme='dark']) .predecessor-tag {
|
||||
:global(.gantt-root[data-theme='dark']) .predecessor-tag {
|
||||
background: var(--gantt-primary-dark, #337ecc);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .form-select {
|
||||
:global(.gantt-root[data-theme='dark']) .form-select {
|
||||
background: var(--gantt-bg-primary, #2b2b2b);
|
||||
border-color: var(--gantt-border-medium, #4c4d4f);
|
||||
color: var(--gantt-text-primary, #e5eaf3);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .form-select:focus {
|
||||
:global(.gantt-root[data-theme='dark']) .form-select:focus {
|
||||
border-color: var(--gantt-primary, #409eff);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onUnmounted, onMounted, nextTick, watch, useSlots, inject, type ComputedRef } from 'vue'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
@@ -3406,7 +3406,7 @@ const handleAnchorDragEnd = (anchorEvent: { taskId: number; type: 'predecessor'
|
||||
}
|
||||
|
||||
/* 暗黑主题下的标题颜色 */
|
||||
:global(html[data-theme='dark']) .actual-task-name {
|
||||
:global(.gantt-root[data-theme='dark']) .actual-task-name {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
@@ -3971,14 +3971,14 @@ const handleAnchorDragEnd = (anchorEvent: { taskId: number; type: 'predecessor'
|
||||
}
|
||||
|
||||
/* 暗色主题支持 */
|
||||
:global(html[data-theme='dark']) .task-bar {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar {
|
||||
border-color: #111827 !important;
|
||||
box-shadow:
|
||||
0 4px 12px rgba(0, 0, 0, 0.7),
|
||||
0 2px 4px rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar:hover {
|
||||
box-shadow:
|
||||
0 6px 20px rgba(0, 0, 0, 0.8),
|
||||
0 4px 8px rgba(0, 0, 0, 0.4) !important;
|
||||
@@ -3986,58 +3986,58 @@ const handleAnchorDragEnd = (anchorEvent: { taskId: number; type: 'predecessor'
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar:hover::after {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar:hover::after {
|
||||
background: rgba(7, 10, 15, 0.98) !important;
|
||||
color: #f9fafb !important;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.6) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar.normal {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.normal {
|
||||
background: linear-gradient(135deg, #1e40af, #1e3a8a) !important;
|
||||
border-color: #1e3a8a !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar.milestone {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.milestone {
|
||||
background: linear-gradient(135deg, #c2410c, #9a3412) !important;
|
||||
border-color: #9a3412 !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar.completed {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.completed {
|
||||
background: linear-gradient(135deg, #14532d, #16a34a) !important;
|
||||
border-color: #14532d !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar.delayed {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.delayed {
|
||||
background: linear-gradient(135deg, #991b1b, #dc2626) !important;
|
||||
border-color: #991b1b !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar.parent {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.parent {
|
||||
background: linear-gradient(135deg, #581c87, #7c3aed) !important;
|
||||
border-color: #581c87 !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-content {
|
||||
:global(.gantt-root[data-theme='dark']) .task-content {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-name {
|
||||
:global(.gantt-root[data-theme='dark']) .task-name {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .progress-bar {
|
||||
:global(.gantt-root[data-theme='dark']) .progress-bar {
|
||||
background: rgba(255, 255, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .progress-fill {
|
||||
:global(.gantt-root[data-theme='dark']) .progress-fill {
|
||||
background: rgba(255, 255, 255, 0.8) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .resize-handle {
|
||||
:global(.gantt-root[data-theme='dark']) .resize-handle {
|
||||
background: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .resize-handle:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .resize-handle:hover {
|
||||
background: rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
@@ -4099,42 +4099,42 @@ const handleAnchorDragEnd = (anchorEvent: { taskId: number; type: 'predecessor'
|
||||
}
|
||||
|
||||
/* 暗色主题下的短TaskBar溢出效果 */
|
||||
:global(html[data-theme='dark']) .task-bar.overflow-effect .resize-handle {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.overflow-effect .resize-handle {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar.overflow-effect .resize-handle:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.overflow-effect .resize-handle:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
/* 暗色主题下的进度百分比样式 */
|
||||
:global(html[data-theme='dark']) .task-bar.overflow-effect .task-progress {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.overflow-effect .task-progress {
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-bar.week-view {
|
||||
:global(.gantt-root[data-theme='dark']) .task-bar.week-view {
|
||||
border-color: var(--gantt-border-light, #555555);
|
||||
}
|
||||
|
||||
/* 暗色主题下的头像样式 */
|
||||
:global(html[data-theme='dark']) .task-avatar {
|
||||
:global(.gantt-root[data-theme='dark']) .task-avatar {
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
/* 暗色主题下的默认头像 */
|
||||
:global(html[data-theme='dark']) .task-avatar.avatar-default {
|
||||
:global(.gantt-root[data-theme='dark']) .task-avatar.avatar-default {
|
||||
background: var(--gantt-bg-tertiary, #4a5568);
|
||||
color: var(--gantt-text-tertiary, #718096);
|
||||
}
|
||||
|
||||
/* 暗色主题下的图标颜色 */
|
||||
:global(html[data-theme='dark']) .task-avatar .avatar-icon {
|
||||
:global(.gantt-root[data-theme='dark']) .task-avatar .avatar-icon {
|
||||
color: var(--gantt-text-tertiary, #718096);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-avatar.avatar-outside {
|
||||
:global(.gantt-root[data-theme='dark']) .task-avatar.avatar-outside {
|
||||
border-color: rgba(255, 255, 255, 0.4);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
@@ -661,23 +661,23 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
/* 暗色主题支持 */
|
||||
:global(html[data-theme='dark']) .task-context-menu {
|
||||
:global(.gantt-root[data-theme='dark']) .task-context-menu {
|
||||
background-color: #2c2c2c;
|
||||
border-color: #444444;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .menu-item {
|
||||
:global(.gantt-root[data-theme='dark']) .menu-item {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .menu-item:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .menu-item:hover {
|
||||
background-color: #3a3a3a;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
/* 暗色主题下箭头颜色 */
|
||||
:global(html[data-theme='dark']) .menu-arrow {
|
||||
:global(.gantt-root[data-theme='dark']) .menu-arrow {
|
||||
border-bottom-color: #2c2c2c; /* 匹配暗色菜单背景色 */
|
||||
filter: drop-shadow(0 -1px 2px rgba(0, 0, 0, 0.25));
|
||||
}
|
||||
@@ -784,13 +784,13 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
/* 暗色主题下的子菜单 */
|
||||
:global(html[data-theme='dark']) .submenu {
|
||||
:global(.gantt-root[data-theme='dark']) .submenu {
|
||||
background-color: #2c2c2c;
|
||||
border-color: #444444;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .submenu-item:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .submenu-item:hover {
|
||||
background-color: #3a1f1f;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
import { useMessage } from '../composables/useMessage'
|
||||
@@ -1467,29 +1467,29 @@ const taskStatus = computed(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式样式 */
|
||||
:global(html[data-theme='dark']) .progress-input-group {
|
||||
:global(.gantt-root[data-theme='dark']) .progress-input-group {
|
||||
border-color: var(--gantt-border-medium, #4c4d4f);
|
||||
background: var(--gantt-bg-primary, #2b2b2b);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .progress-input-group:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .progress-input-group:hover {
|
||||
border-color: var(--gantt-primary, #409eff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .progress-input-group:focus-within {
|
||||
:global(.gantt-root[data-theme='dark']) .progress-input-group:focus-within {
|
||||
border-color: var(--gantt-primary, #409eff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .progress-input {
|
||||
:global(.gantt-root[data-theme='dark']) .progress-input {
|
||||
color: var(--gantt-text-primary, #e5eaf3);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .progress-input::placeholder {
|
||||
:global(.gantt-root[data-theme='dark']) .progress-input::placeholder {
|
||||
color: var(--gantt-text-placeholder, #8b949e);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .progress-unit {
|
||||
:global(.gantt-root[data-theme='dark']) .progress-unit {
|
||||
color: var(--gantt-text-secondary, #a8a8a8);
|
||||
}
|
||||
|
||||
@@ -1547,27 +1547,27 @@ const taskStatus = computed(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式样式优化 */
|
||||
:global(html[data-theme='dark']) .drawer-overlay {
|
||||
:global(.gantt-root[data-theme='dark']) .drawer-overlay {
|
||||
background: rgba(0, 0, 0, 0.7) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .drawer-container {
|
||||
:global(.gantt-root[data-theme='dark']) .drawer-container {
|
||||
box-shadow: -4px 0 15px rgba(0, 0, 0, 0.4) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .drawer-close-btn:hover {
|
||||
:global(.gantt-root[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']) .form-input:focus,
|
||||
:global(html[data-theme='dark']) .form-select:focus,
|
||||
:global(html[data-theme='dark']) .form-textarea:focus {
|
||||
:global(.gantt-root[data-theme='dark']) .form-input:focus,
|
||||
:global(.gantt-root[data-theme='dark']) .form-select:focus,
|
||||
:global(.gantt-root[data-theme='dark']) .form-textarea:focus {
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .form-input::placeholder,
|
||||
:global(html[data-theme='dark']) .form-textarea::placeholder {
|
||||
:global(.gantt-root[data-theme='dark']) .form-input::placeholder,
|
||||
:global(.gantt-root[data-theme='dark']) .form-textarea::placeholder {
|
||||
color: var(--gantt-text-muted, #9e9e9e) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, useSlots, toRef, inject, type ComputedRef } from 'vue'
|
||||
import type { StyleValue } from 'vue'
|
||||
import { useI18n } from '../../../composables/useI18n'
|
||||
@@ -636,20 +636,20 @@ const assigneeDisplayData = computed(() => {
|
||||
border-left: 5px solid var(--gantt-danger, #f56c6c) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .milestone-group-row {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-group-row {
|
||||
border-left-color: var(--gantt-danger, #f67c7c);
|
||||
}
|
||||
|
||||
/* 暗黑模式下的任务类型左边框颜色 */
|
||||
:global(html[data-theme='dark']) .task-type-story {
|
||||
:global(.gantt-root[data-theme='dark']) .task-type-story {
|
||||
border-left-color: var(--gantt-primary, #7db4f0);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-type-task {
|
||||
:global(.gantt-root[data-theme='dark']) .task-type-task {
|
||||
border-left-color: var(--gantt-warning, #f0b83c);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-type-milestone {
|
||||
:global(.gantt-root[data-theme='dark']) .task-type-milestone {
|
||||
border-left-color: var(--gantt-danger, #f67c7c);
|
||||
}
|
||||
|
||||
@@ -775,44 +775,44 @@ const assigneeDisplayData = computed(() => {
|
||||
}
|
||||
|
||||
/* 暗黑模式适配 */
|
||||
:global(html[data-theme='dark']) .milestone-row-icon {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-row-icon {
|
||||
color: var(--gantt-danger, #f67c7c);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .milestone-empty-col {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-empty-col {
|
||||
color: var(--gantt-text-disabled, #606266);
|
||||
/* 确保暗黑模式下边框颜色与普通数据行一致 */
|
||||
border-right-color: var(--gantt-border-light) !important;
|
||||
}
|
||||
|
||||
/* 暗黑模式的悬停效果 */
|
||||
:global(html[data-theme='dark']) .task-row:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .task-row:hover {
|
||||
box-shadow:
|
||||
0 4px 12px rgba(255, 255, 255, 0.1),
|
||||
0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-row.task-row-hovered {
|
||||
:global(.gantt-root[data-theme='dark']) .task-row.task-row-hovered {
|
||||
background-color: var(--gantt-bg-hover) !important;
|
||||
box-shadow:
|
||||
0 4px 12px rgba(255, 255, 255, 0.1),
|
||||
0 2px 8px rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-row.parent-task:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .task-row.parent-task:hover {
|
||||
box-shadow:
|
||||
0 6px 16px rgba(255, 255, 255, 0.15),
|
||||
0 2px 8px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-row.parent-task.task-row-hovered {
|
||||
:global(.gantt-root[data-theme='dark']) .task-row.parent-task.task-row-hovered {
|
||||
background: var(--gantt-bg-hover-parent) !important;
|
||||
box-shadow:
|
||||
0 6px 16px rgba(255, 255, 255, 0.15),
|
||||
0 2px 8px rgba(0, 0, 0, 0.4) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .milestone-group-row:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-group-row:hover {
|
||||
box-shadow:
|
||||
0 6px 16px rgba(246, 124, 124, 0.4),
|
||||
0 2px 8px rgba(255, 255, 255, 0.1);
|
||||
@@ -835,11 +835,11 @@ const assigneeDisplayData = computed(() => {
|
||||
background-color: rgba(64, 158, 255, 0.05) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-row-drop-target.drop-after {
|
||||
:global(.gantt-root[data-theme='dark']) .task-row-drop-target.drop-after {
|
||||
background-color: rgba(125, 180, 240, 0.1) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .task-row-drop-target.drop-child {
|
||||
:global(.gantt-root[data-theme='dark']) .task-row-drop-target.drop-child {
|
||||
background-color: rgba(125, 180, 240, 0.1) !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
isMilestoneGroup: boolean
|
||||
isParentTask: boolean
|
||||
@@ -75,7 +75,7 @@ withDefaults(defineProps<Props>(), {
|
||||
}
|
||||
|
||||
/* 暗黑模式下的里程碑图标 */
|
||||
:global(html[data-theme='dark']) .milestone-group-icon {
|
||||
:global(.gantt-root[data-theme='dark']) .milestone-group-icon {
|
||||
color: var(--gantt-danger, #f67c7c);
|
||||
fill: var(--gantt-danger, #f67c7c);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, computed, watch, nextTick, shallowRef } from 'vue'
|
||||
import TaskBar from './TaskBar.vue'
|
||||
import MilestonePoint from './MilestonePoint.vue'
|
||||
@@ -4784,11 +4784,11 @@ const handleAddSuccessor = (task: Task) => {
|
||||
}
|
||||
|
||||
/* 暗色主题下的旗帜样式 */
|
||||
:global(html[data-theme='dark']) .flag-pole {
|
||||
:global(.gantt-root[data-theme='dark']) .flag-pole {
|
||||
background-color: var(--gantt-primary-light, #66b1ff);
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .flag-content {
|
||||
:global(.gantt-root[data-theme='dark']) .flag-content {
|
||||
background-color: var(--gantt-primary-light, #66b1ff);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
@@ -5024,72 +5024,72 @@ const handleAddSuccessor = (task: Task) => {
|
||||
}
|
||||
|
||||
/* 暗色主题支持 */
|
||||
:global(html[data-theme='dark']) .timeline {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline {
|
||||
background: var(--gantt-bg-primary, #3a3a3a) !important;
|
||||
color: var(--gantt-text-primary, #e5e5e5) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-header {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-header {
|
||||
background: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-header-row {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-header-row {
|
||||
border-bottom-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-month {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-month {
|
||||
border-right-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .year-month-label {
|
||||
:global(.gantt-root[data-theme='dark']) .year-month-label {
|
||||
color: var(--gantt-text-header, #ffffff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-day {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-day {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-day.today {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-day.today {
|
||||
background: #1a365d !important;
|
||||
color: #e3f2fd !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-day.weekend {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-day.weekend {
|
||||
background: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
color: var(--gantt-text-muted, #b0b0b0) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .day-label {
|
||||
:global(.gantt-root[data-theme='dark']) .day-label {
|
||||
color: var(--gantt-text-header, #ffffff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-body {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-body {
|
||||
background: var(--gantt-bg-primary, #6b6b6b) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-body-content {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-body-content {
|
||||
background: var(--gantt-bg-primary, #6b6b6b) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .day-columns {
|
||||
:global(.gantt-root[data-theme='dark']) .day-columns {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .month-day-columns {
|
||||
:global(.gantt-root[data-theme='dark']) .month-day-columns {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .day-column {
|
||||
:global(.gantt-root[data-theme='dark']) .day-column {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
/* 非周末列:透明背景,继承timeline-body的背景色 */
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .day-column.today {
|
||||
:global(.gantt-root[data-theme='dark']) .day-column.today {
|
||||
border-left-color: var(--gantt-primary, #409eff) !important;
|
||||
background-color: var(--gantt-primary, #409eff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .day-column.today::before {
|
||||
:global(.gantt-root[data-theme='dark']) .day-column.today::before {
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(64, 158, 255, 0.15) 0%,
|
||||
@@ -5098,17 +5098,17 @@ const handleAddSuccessor = (task: Task) => {
|
||||
) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .day-column.today.weekend {
|
||||
:global(.gantt-root[data-theme='dark']) .day-column.today.weekend {
|
||||
background-color: var(--gantt-primary-color, #409eff) !important;
|
||||
}
|
||||
|
||||
/* 暗色主题下的今日定位高亮效果 */
|
||||
:global(html[data-theme='dark']) .day-column.today-highlight {
|
||||
:global(.gantt-root[data-theme='dark']) .day-column.today-highlight {
|
||||
background-color: var(--gantt-primary-color, #409eff) !important;
|
||||
box-shadow: 0 0 8px rgba(64, 158, 255, 0.6) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .day-column.today-highlight::before {
|
||||
:global(.gantt-root[data-theme='dark']) .day-column.today-highlight::before {
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(64, 158, 255, 0.4) 0%,
|
||||
@@ -5118,23 +5118,23 @@ const handleAddSuccessor = (task: Task) => {
|
||||
}
|
||||
|
||||
/* 暗黑模式下的任务行悬停效果 */
|
||||
:global(html[data-theme='dark']) .timeline-body .task-row-hovered {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-body .task-row-hovered {
|
||||
background-color: var(--gantt-bg-hover) !important; /* 与TaskList保持一致,使用透明背景 */
|
||||
/* 降低层级,避免覆盖任务条等元素 */
|
||||
z-index: 11 !important;
|
||||
}
|
||||
|
||||
/* 确保暗黑模式下子元素能继续响应事件 */
|
||||
:global(html[data-theme='dark']) .timeline-body .task-row-hovered > * {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-body .task-row-hovered > * {
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
/* 暗黑模式下的非工作时间样式 */
|
||||
:global(html[data-theme='dark']) .timeline-hour-item.non-working-hour {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-hour-item.non-working-hour {
|
||||
background-color: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-hour-item.non-working-hour .hour-label {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-hour-item.non-working-hour .hour-label {
|
||||
color: var(--gantt-text-muted, #b0b0b0) !important;
|
||||
}
|
||||
|
||||
@@ -5300,98 +5300,98 @@ const handleAddSuccessor = (task: Task) => {
|
||||
}
|
||||
|
||||
/* 月度视图暗色主题样式 */
|
||||
:global(html[data-theme='dark']) .year-row {
|
||||
:global(.gantt-root[data-theme='dark']) .year-row {
|
||||
background: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
border-bottom-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-year {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-year {
|
||||
border-right-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .year-label {
|
||||
:global(.gantt-root[data-theme='dark']) .year-label {
|
||||
color: var(--gantt-text-header, #ffffff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .months-row {
|
||||
:global(.gantt-root[data-theme='dark']) .months-row {
|
||||
background: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
border-bottom-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-month-item {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-month-item {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
border-bottom-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-month-item.today {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-month-item.today {
|
||||
background-color: var(--gantt-primary);
|
||||
border-left-color: var(--gantt-primary, #409eff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .month-label {
|
||||
:global(.gantt-root[data-theme='dark']) .month-label {
|
||||
color: var(--gantt-text-header, #ffffff) !important;
|
||||
}
|
||||
|
||||
/* 季度视图暗色主题样式 */
|
||||
:global(html[data-theme='dark']) .quarters-row {
|
||||
:global(.gantt-root[data-theme='dark']) .quarters-row {
|
||||
background: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
border-bottom-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-quarter-item {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-quarter-item {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
border-bottom-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-quarter-item.today {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-quarter-item.today {
|
||||
background-color: var(--gantt-primary);
|
||||
border-left-color: var(--gantt-primary, #409eff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .quarter-label {
|
||||
:global(.gantt-root[data-theme='dark']) .quarter-label {
|
||||
color: var(--gantt-text-header, #ffffff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .quarter-column {
|
||||
:global(.gantt-root[data-theme='dark']) .quarter-column {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
background-color: var(--gantt-bg-primary, #6b6b6b) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .quarter-column.today {
|
||||
:global(.gantt-root[data-theme='dark']) .quarter-column.today {
|
||||
background-color: var(--gantt-primary, #409eff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .month-column {
|
||||
:global(.gantt-root[data-theme='dark']) .month-column {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .month-column.today {
|
||||
:global(.gantt-root[data-theme='dark']) .month-column.today {
|
||||
background-color: var(--gantt-primary-color, #409eff);
|
||||
border-left-color: var(--gantt-primary-color, #409eff) !important;
|
||||
}
|
||||
|
||||
/* 年度视图暗色主题样式 */
|
||||
:global(html[data-theme='dark']) .half-years-row {
|
||||
:global(.gantt-root[data-theme='dark']) .half-years-row {
|
||||
background: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
border-bottom-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-half-year-item {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-half-year-item {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
border-bottom-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .half-year-label {
|
||||
:global(.gantt-root[data-theme='dark']) .half-year-label {
|
||||
color: var(--gantt-text-header, #ffffff) !important;
|
||||
}
|
||||
|
||||
/* 年度视图背景列暗色主题样式 */
|
||||
:global(html[data-theme='dark']) .half-year-column {
|
||||
:global(.gantt-root[data-theme='dark']) .half-year-column {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
background-color: var(--gantt-bg-primary, #6b6b6b) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .half-year-column:hover {
|
||||
:global(.gantt-root[data-theme='dark']) .half-year-column:hover {
|
||||
background-color: var(--gantt-bg-hover, rgba(64, 158, 255, 0.1)) !important;
|
||||
}
|
||||
|
||||
@@ -5407,7 +5407,7 @@ const handleAddSuccessor = (task: Task) => {
|
||||
}
|
||||
|
||||
/* 暗黑模式下的年度视图今日标记线 */
|
||||
:global(html[data-theme='dark']) .today-line-year-view {
|
||||
:global(.gantt-root[data-theme='dark']) .today-line-year-view {
|
||||
background-color: var(--gantt-primary, #66b1ff);
|
||||
box-shadow: 0 0 4px rgba(102, 177, 255, 0.4);
|
||||
}
|
||||
@@ -5569,65 +5569,65 @@ const handleAddSuccessor = (task: Task) => {
|
||||
}
|
||||
|
||||
/* 小时视图暗色主题样式 */
|
||||
:global(html[data-theme='dark']) .date-row {
|
||||
:global(.gantt-root[data-theme='dark']) .date-row {
|
||||
background: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
border-bottom-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-day-item {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-day-item {
|
||||
border-right-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .date-label {
|
||||
:global(.gantt-root[data-theme='dark']) .date-label {
|
||||
color: var(--gantt-text-header, #ffffff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .hours-row {
|
||||
:global(.gantt-root[data-theme='dark']) .hours-row {
|
||||
background: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
border-bottom-color: var(--gantt-border-medium, #333333) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-hour-item {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-hour-item {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
border-bottom-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-hour-item.today {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-hour-item.today {
|
||||
background-color: var(--gantt-primary, #1a365d) !important;
|
||||
color: var(--gantt-text-white, #e3f2fd) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .hour-label {
|
||||
:global(.gantt-root[data-theme='dark']) .hour-label {
|
||||
color: var(--gantt-text-primary, #e5e5e5) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .timeline-hour-item.today .hour-label {
|
||||
:global(.gantt-root[data-theme='dark']) .timeline-hour-item.today .hour-label {
|
||||
color: var(--gantt-text-white, #e3f2fd) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .hour-column {
|
||||
:global(.gantt-root[data-theme='dark']) .hour-column {
|
||||
border-right-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .hour-column.weekend {
|
||||
:global(.gantt-root[data-theme='dark']) .hour-column.weekend {
|
||||
background-color: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .hour-column.rest-hour {
|
||||
:global(.gantt-root[data-theme='dark']) .hour-column.rest-hour {
|
||||
background-color: var(--gantt-bg-secondary, #1a1a1a) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .hour-column.working-hour {
|
||||
:global(.gantt-root[data-theme='dark']) .hour-column.working-hour {
|
||||
background-color: var(--gantt-bg-primary, #6b6b6b) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .hour-column.today {
|
||||
:global(.gantt-root[data-theme='dark']) .hour-column.today {
|
||||
background-color: var(--gantt-primary-color, #409eff) !important;
|
||||
border-left-color: var(--gantt-primary-color, #409eff) !important;
|
||||
}
|
||||
|
||||
/* 暗色主题:15分钟刻度线样式 */
|
||||
:global(html[data-theme='dark']) .quarter-line {
|
||||
:global(.gantt-root[data-theme='dark']) .quarter-line {
|
||||
background-color: var(--gantt-border-light, #555555) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -36,13 +36,13 @@
|
||||
}
|
||||
|
||||
/* 暗黑主题下 .gantt-btn-default 全局样式 */
|
||||
:global(html[data-theme='dark']) .gantt-btn-default {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-btn-default {
|
||||
background: var(--gantt-bg-tertiary, #454545) !important;
|
||||
border-color: var(--gantt-border-color, #dcdfe6) !important;
|
||||
color: var(--gantt-text-white, #ffffff) !important;
|
||||
}
|
||||
|
||||
:global(html[data-theme='dark']) .gantt-btn-default:hover:not(:disabled) {
|
||||
:global(.gantt-root[data-theme='dark']) .gantt-btn-default:hover:not(:disabled) {
|
||||
background: var(--gantt-bg-hover, rgba(255, 255, 255, 0.1)) !important;
|
||||
border-color: var(--gantt-primary, #409eff) !important;
|
||||
color: var(--gantt-primary, #409eff) !important;
|
||||
@@ -82,23 +82,17 @@
|
||||
}
|
||||
|
||||
/* 黑暗模式全局样式 */
|
||||
html[data-theme='dark'] {
|
||||
background: #1e1e1e !important;
|
||||
color-scheme: dark !important;
|
||||
.gantt-root[data-theme='dark'] {
|
||||
background: #1e1e1e;
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] body {
|
||||
background: #1e1e1e !important;
|
||||
color: #e5e5e5 !important;
|
||||
}
|
||||
/* 移除body样式,因为不再全局污染 */
|
||||
|
||||
/* 明亮模式全局样式 */
|
||||
html[data-theme='light'] {
|
||||
background: #ffffff !important;
|
||||
color-scheme: light !important;
|
||||
.gantt-root[data-theme='light'] {
|
||||
background: #ffffff;
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html[data-theme='light'] body {
|
||||
background: #ffffff !important;
|
||||
color: #333333 !important;
|
||||
}
|
||||
/* 移除body样式,因为不再全局污染 */
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
}
|
||||
|
||||
/* 暗黑主题 */
|
||||
html[data-theme='dark'] {
|
||||
.gantt-root[data-theme='dark'] {
|
||||
/* 背景色 - 大幅提升亮度,接近中性灰 */
|
||||
--gantt-bg-primary: #6b6b6b; /* Body主体 - 明显更亮,接近中性灰 */
|
||||
--gantt-bg-secondary: #4b4b4b; /* Header背景 - 中等亮度,保持层次 */
|
||||
|
||||
Reference in New Issue
Block a user