@workiom/frappe-gantt 1.0.19 → 1.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -19
- package/dist/frappe-gantt.css +1 -1
- package/dist/frappe-gantt.es.js +524 -403
- package/dist/frappe-gantt.umd.js +46 -21
- package/package.json +1 -1
- package/src/arrow.js +171 -84
- package/src/bar.js +0 -70
- package/src/defaults.js +2 -2
- package/src/dependency_shifting.js +178 -0
- package/src/index.js +100 -151
- package/src/styles/dark.css +5 -0
- package/src/styles/gantt.css +13 -0
- package/src/styles/light.css +1 -0
package/README.md
CHANGED
|
@@ -86,7 +86,8 @@ Frappe Gantt offers a wide range of options to customize your chart.
|
|
|
86
86
|
| `column_width` | Width of each column in the timeline. | Any positive integer. | 45 |
|
|
87
87
|
| `critical_path` | Automatically calculate and highlight the critical path. | `true`, `false` | `false` |
|
|
88
88
|
| `date_format` | Format for displaying dates. | Any valid JS date format string. | `YYYY-MM-DD` |
|
|
89
|
-
| `dependencies_type` |
|
|
89
|
+
| `dependencies_type` | Sets the default relationship type used to validate each arrow (turns it red on violation). Dragging is always free. | `finish-to-start`, `start-to-start`, `finish-to-finish`, `start-to-finish` | `finish-to-start` |
|
|
90
|
+
| `dependency_shifting` | Controls how dependent tasks shift after a bar is dropped. See Dependency Shifting section below. | `none`, `maintain_buffer_all`, `maintain_buffer_downstream`, `consume_buffer` | `none` |
|
|
90
91
|
| `upper_header_height` | Height of the upper header in the timeline (in pixels). | Any positive integer. | `45` |
|
|
91
92
|
| `lower_header_height` | Height of the lower header in the timeline (in pixels). | Any positive integer. | `30` |
|
|
92
93
|
| `snap_at` | Snap tasks at particular intervel while resizing or dragging. | Any _interval_ (see below) | `1d` |
|
|
@@ -96,7 +97,6 @@ Frappe Gantt offers a wide range of options to customize your chart.
|
|
|
96
97
|
| `ignore` | Ignored areas in the rendering | `weekend` _or_ Array of strings or date objects (`weekend` can be present to the array also). | `[]` |
|
|
97
98
|
| `language` | Language for localization. | ISO 639-1 codes like `en`, `fr`, `es`. | `en` |
|
|
98
99
|
| `lines` | Determines which grid lines to display. | `none` for no lines, `vertical` for only vertical lines, `horizontal` for only horizontal lines, `both` for complete grid. | `both` |
|
|
99
|
-
| `move_dependencies` | Whether moving a task automatically moves its dependencies. | `true`, `false` | `true` |
|
|
100
100
|
| `padding` | Padding around task bars (in pixels). | Any positive integer. | `18` |
|
|
101
101
|
| `popup_on` | Event to trigger the popup display. | `click` _or_ `hover` | `click` |
|
|
102
102
|
| `readonly_progress` | Disables editing task progress. | `true`, `false` | `false` |
|
|
@@ -109,45 +109,39 @@ Frappe Gantt offers a wide range of options to customize your chart.
|
|
|
109
109
|
| `view_mode` | The initial view mode of the Gantt chart. | `Day`, `Week`, `Month`, `Year`. | `Day` |
|
|
110
110
|
| `view_mode_select` | Allows selecting the view mode from a dropdown. | `true`, `false` | `false` |
|
|
111
111
|
|
|
112
|
-
Apart from these ones,
|
|
112
|
+
Apart from these ones, two options - `popup` and `view_modes` (plural, not singular) - have additional details and are listed separately below. `dependencies_type` is also described in more detail in the Dependencies Type section below.
|
|
113
113
|
|
|
114
114
|
#### Dependencies Type Configuration
|
|
115
115
|
|
|
116
|
-
The `dependencies_type` option controls how dependent tasks behave when their parent tasks are moved. This
|
|
116
|
+
The `dependencies_type` option controls how dependent tasks behave when their parent tasks are moved. This is set globally and can be overridden per dependency entry (see the task `dependencies` format below).
|
|
117
117
|
|
|
118
118
|
**Available Types:**
|
|
119
119
|
|
|
120
|
-
- **`
|
|
121
|
-
|
|
122
|
-
- **`finish-to-start`**: Most common in project management. The dependent task can only start after the parent finishes.
|
|
120
|
+
- **`finish-to-start`** (default): Most common in project management. The dependent task can only start after the parent finishes.
|
|
123
121
|
- Constraint: Dependent start date ≥ Parent end date
|
|
124
|
-
- Auto-update: If parent ends after dependent starts, dependent moves forward
|
|
125
122
|
- Example: Development can only start after Design finishes
|
|
126
123
|
|
|
127
124
|
- **`start-to-start`**: The dependent task can only start after the parent starts.
|
|
128
125
|
- Constraint: Dependent start date ≥ Parent start date
|
|
129
|
-
- Auto-update: If parent starts after dependent, dependent moves forward
|
|
130
126
|
- Example: Testing can start after Development starts (parallel work)
|
|
131
127
|
|
|
132
128
|
- **`finish-to-finish`**: The dependent task can only finish after the parent finishes.
|
|
133
129
|
- Constraint: Dependent end date ≥ Parent end date
|
|
134
|
-
- Auto-update: If parent ends after dependent, dependent extends
|
|
135
130
|
- Example: Documentation must finish after Development finishes
|
|
136
131
|
|
|
137
132
|
- **`start-to-finish`**: The dependent task can only finish after the parent starts (rare).
|
|
138
133
|
- Constraint: Dependent end date ≥ Parent start date
|
|
139
|
-
- Auto-update: If parent starts after dependent ends, dependent extends
|
|
140
134
|
- Example: Legacy system runs until new system starts
|
|
141
135
|
|
|
142
136
|
**Usage:**
|
|
143
137
|
|
|
144
138
|
```js
|
|
145
|
-
// Global configuration
|
|
139
|
+
// Global configuration (fallback for all dependencies)
|
|
146
140
|
let gantt = new Gantt("#gantt", tasks, {
|
|
147
141
|
dependencies_type: 'finish-to-start'
|
|
148
142
|
});
|
|
149
143
|
|
|
150
|
-
// Per-
|
|
144
|
+
// Per-dependency override via the dependencies array
|
|
151
145
|
let tasks = [
|
|
152
146
|
{
|
|
153
147
|
id: 'design',
|
|
@@ -160,17 +154,53 @@ let tasks = [
|
|
|
160
154
|
name: 'Development',
|
|
161
155
|
start: '2023-01-05',
|
|
162
156
|
end: '2023-01-15',
|
|
163
|
-
dependencies:
|
|
164
|
-
|
|
157
|
+
dependencies: [
|
|
158
|
+
{ id: 'design', type: 'finish-to-start' } // Overrides global setting
|
|
159
|
+
]
|
|
165
160
|
}
|
|
166
161
|
];
|
|
167
162
|
```
|
|
168
163
|
|
|
169
164
|
**Behavior:**
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
165
|
+
- Dragging is always free — tasks can be moved to any position
|
|
166
|
+
- When a dependency constraint is violated, the arrow turns red
|
|
167
|
+
- Each arrow is validated independently based on its own `type`
|
|
168
|
+
- Constraints respect ignored dates/weekends
|
|
169
|
+
|
|
170
|
+
#### Dependency Shifting Configuration
|
|
171
|
+
|
|
172
|
+
The `dependency_shifting` option controls how dependent tasks respond when a bar is dragged and released.
|
|
173
|
+
|
|
174
|
+
**Available Modes:**
|
|
175
|
+
|
|
176
|
+
- **`none`** (default): No shifting. Dependency arrows may visually overlap — no correction is applied.
|
|
177
|
+
|
|
178
|
+
- **`maintain_buffer_all`**: When any task moves, every task in the chain (both upstream and downstream) shifts by the same number of days. All gaps between tasks are preserved exactly.
|
|
179
|
+
|
|
180
|
+
- **`maintain_buffer_downstream`**: When a task moves, only downstream tasks shift by the same delta. Tasks before it in the chain stay fixed.
|
|
181
|
+
|
|
182
|
+
- **`consume_buffer`**: Dependency-type-aware shifting. A shift only happens when a real conflict exists — the buffer is consumed first. If no conflict exists, nothing changes. If a conflict exists, only the minimum shift needed to resolve it is applied. Works in both directions.
|
|
183
|
+
|
|
184
|
+
Conflict conditions per dependency type:
|
|
185
|
+
| Type | Conflict when |
|
|
186
|
+
|---|---|
|
|
187
|
+
| `finish-to-start` | predecessor end > successor start |
|
|
188
|
+
| `start-to-start` | predecessor start > successor start |
|
|
189
|
+
| `finish-to-finish` | predecessor end > successor end |
|
|
190
|
+
| `start-to-finish` | predecessor start > successor end |
|
|
191
|
+
|
|
192
|
+
**Usage:**
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
let gantt = new Gantt("#gantt", tasks, {
|
|
196
|
+
dependency_shifting: 'consume_buffer'
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Behavior notes:**
|
|
201
|
+
- Shifting fires after drag release (mouseup), not during live dragging
|
|
202
|
+
- When a task has multiple predecessors, the maximum required shift is applied (ensures all constraints are satisfied)
|
|
203
|
+
- Cycles in the dependency graph are safely skipped
|
|
174
204
|
|
|
175
205
|
#### View Mode Configuration
|
|
176
206
|
|
package/dist/frappe-gantt.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--g-arrow-color: #1f2937;--g-arrow-critical-color: #f5c044;--g-arrow-invalid-color: #ff7676;--g-bar-color: #fff;--g-bar-border: #fff;--g-tick-color-thick: #ededed;--g-tick-color: #f3f3f3;--g-actions-background: #f3f3f3;--g-border-color: #ebeff2;--g-text-muted: #7c7c7c;--g-text-light: #fff;--g-text-dark: #171717;--g-progress-color: #dbdbdb;--g-handle-color: transparent;--g-weekend-label-color: #dcdce4;--g-expected-progress: #c4c4e9;--g-header-background: #fff;--g-row-color: #fdfdfd;--g-row-border-color: #c7c7c7;--g-today-highlight: #37352f;--g-popup-actions: #ebeff2;--g-weekend-highlight-color: #f7f7f7;--g-task-column-bg: #ffffff;--g-task-row-bg: #ffffff;--g-resize-handle-hover: rgba(59, 130, 246, .3);--g-resize-handle-active: rgba(59, 130, 246, .5)}.gantt-wrapper{display:flex;width:100%;position:relative}.gantt-wrapper.rtl{flex-direction:row-reverse}.gantt-container{line-height:14.5px;position:relative;overflow:auto;font-size:12px;height:var(--gv-grid-height);flex:1;min-width:0;border-radius:8px}.gantt-container .popup-wrapper{position:absolute;top:0;left:0;background:#fff;box-shadow:0 10px 24px -3px #0003;padding:10px;border-radius:5px;width:max-content;z-index:1000}.gantt-container .popup-wrapper .title{margin-bottom:2px;color:var(--g-text-dark);font-size:.85rem;font-weight:650;line-height:15px}.gantt-container .popup-wrapper .subtitle{color:var(--g-text-dark);font-size:.8rem;margin-bottom:5px}.gantt-container .popup-wrapper .details{color:var(--g-text-muted);font-size:.7rem}.gantt-container .popup-wrapper .actions{margin-top:10px;margin-left:3px}.gantt-container .popup-wrapper .action-btn{border:none;padding:5px 8px;background-color:var(--g-popup-actions);border-right:1px solid var(--g-text-light)}.gantt-container .popup-wrapper .action-btn:hover{background-color:brightness(97%)}.gantt-container .popup-wrapper .action-btn:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px}.gantt-container .popup-wrapper .action-btn:last-child{border-right:none;border-top-right-radius:4px;border-bottom-right-radius:4px}.gantt-container .grid-header{height:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);background-color:var(--g-header-background);position:sticky;top:0;left:0;border-bottom:1px solid var(--g-row-border-color);z-index:1000}.gantt-container .lower-text,.gantt-container .upper-text{text-anchor:middle}.gantt-container .upper-header{height:var(--gv-upper-header-height)}.gantt-container .lower-header{height:var(--gv-lower-header-height)}.gantt-container .lower-text{font-size:12px;position:absolute;width:calc(var(--gv-column-width) * .8);height:calc(var(--gv-lower-header-height) * .8);margin:0 calc(var(--gv-column-width) * .1);align-content:center;text-align:center;color:var(--g-text-muted)}.gantt-container .upper-text{position:absolute;width:fit-content;font-weight:500;font-size:14px;color:var(--g-text-dark);height:calc(var(--gv-lower-header-height) * .66)}.gantt-container .current-upper{position:sticky;left:0!important;padding-left:17px;background:#fff}.gantt-container .side-header{position:sticky;top:0;right:0;float:right;z-index:1000;line-height:20px;font-weight:400;width:max-content;margin-left:auto;padding-right:10px;padding-top:10px;background:var(--g-header-background);display:flex}.gantt-container .side-header *{transition-property:background-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:var(--g-actions-background);border-radius:.5rem;border:none;padding:5px 8px;color:var(--g-text-dark);font-size:14px;letter-spacing:.02em;font-weight:420;box-sizing:content-box;margin-right:5px}.gantt-container .side-header *:last-child{margin-right:0}.gantt-container .side-header *:hover{filter:brightness(97.5%)}.gantt-container .side-header select{width:60px;padding-top:2px;padding-bottom:2px}.gantt-container .side-header select:focus{outline:none}.gantt-container .date-range-highlight{background-color:var(--g-progress-color);border-radius:12px;height:calc(var(--gv-lower-header-height) - 6px);top:calc(var(--gv-upper-header-height) + 5px);position:absolute}.gantt-container .current-highlight{position:absolute;background:var(--g-today-highlight);width:1px;z-index:999}.gantt-container .current-ball-highlight{position:absolute;background:var(--g-today-highlight);z-index:1001;border-radius:50%}.gantt-container .current-date-highlight{background:var(--g-today-highlight);color:var(--g-text-light);border-radius:5px}.gantt-container .holiday-label{position:absolute;top:0;left:0;opacity:0;z-index:1000;background:--g-weekend-label-color;border-radius:5px;padding:2px 5px}.gantt-container .holiday-label.show{opacity:100}.gantt-container .extras{position:sticky;left:0}.gantt-container .extras .adjust{position:absolute;left:8px;top:calc(var(--gv-grid-height) - 60px);background-color:#000000b3;color:#fff;border:none;padding:8px;border-radius:3px}.gantt-container .hide{display:none}.gantt{user-select:none;-webkit-user-select:none;position:absolute;left:0}.gantt .grid-background{fill:none}.gantt .grid-row{fill:var(--g-row-color)}.gantt .row-line{stroke:var(--g-border-color)}.gantt .tick{stroke:var(--g-tick-color);stroke-width:.4}.gantt .tick.thick{stroke:var(--g-tick-color-thick);stroke-width:.7}.gantt .arrow{fill:none;stroke:var(--g-arrow-color);stroke-width:1.5}.gantt .arrow-critical{stroke:var(--g-arrow-critical-color)}.gantt .arrow-invalid{stroke:var(--g-arrow-invalid-color)}.gantt .bar-wrapper .bar{fill:var(--g-bar-color);stroke:var(--g-bar-border);stroke-width:0;transition:stroke-width .3s ease}.gantt .bar-progress{fill:var(--g-progress-color);border-radius:4px}.gantt .bar-expected-progress{fill:var(--g-expected-progress)}.gantt .bar-invalid{fill:transparent;stroke:var(--g-bar-border);stroke-width:1;stroke-dasharray:5}:is(.gantt .bar-invalid)~.bar-label{fill:var(--g-text-light)}.gantt .bar-label{fill:var(--g-text-dark);dominant-baseline:central;font-family:Helvetica;font-size:13px;font-weight:400}.gantt .bar-label.big{fill:var(--g-text-dark);text-anchor:start}.gantt .handle{fill:var(--g-handle-color);opacity:0;transition:opacity .3s ease}.gantt .handle.active,.gantt .handle.visible{cursor:ew-resize;opacity:1}.gantt .handle.progress{fill:var(--g-text-muted)}.gantt .bar-wrapper{cursor:pointer}.gantt .bar-wrapper .bar{outline:1px solid var(--g-row-border-color);border-radius:3px}.gantt .bar-wrapper:hover .bar{transition:transform .3s ease}.gantt .bar-wrapper:hover .date-range-highlight{display:block}.gantt .add-task-icon{cursor:pointer;transition:opacity .2s ease}.gantt .add-task-icon .add-task-icon-bg{fill:var(--g-bar-color);stroke:var(--g-bar-border);stroke-width:1;transition:all .2s ease}.gantt .add-task-icon .add-task-icon-plus{stroke:var(--g-text-dark);stroke-width:2;stroke-linecap:round;transition:stroke .2s ease}.gantt .add-task-icon.active .add-task-icon-bg,.gantt .add-task-icon:hover .add-task-icon-bg{fill:var(--g-progress-color);stroke:var(--g-progress-color)}.gantt .add-task-icon.active .add-task-icon-plus,.gantt .add-task-icon:hover .add-task-icon-plus{stroke:var(--g-text-light)}.task-column{flex-shrink:0;width:var(--gv-task-column-width, 150px);height:var(--gv-grid-height);background-color:var(--g-task-column-bg);border-right:1px solid var(--g-row-border-color);overflow-y:auto;overflow-x:hidden;-webkit-user-select:none;user-select:none;position:relative;scrollbar-width:none;-ms-overflow-style:none}.task-column::-webkit-scrollbar{display:none}.task-column-header{height:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);background-color:var(--g-header-background);border-bottom:1px solid var(--g-row-border-color);position:sticky;top:0;z-index:1001;display:flex;align-items:center;padding:0 12px;font-weight:600;font-size:13px;color:var(--g-text-dark)}.task-column-content{position:relative;width:100%;padding-top:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);overflow:visible}.task-row{position:absolute;width:100%;padding:0 12px;display:flex;align-items:center;font-size:13px;color:var(--g-text-dark);border-bottom:1px solid var(--g-row-border-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background-color:var(--g-task-row-bg)}.task-column-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;min-height:calc(var(--gv-task-column-content-height) + var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);cursor:col-resize;z-index:1002;background-color:transparent;transition:background-color .2s ease}.task-column-resize-handle:hover{background-color:var(--g-resize-handle-hover)}.task-column.resizing .task-column-resize-handle{background-color:var(--g-resize-handle-active)}.task-column.resizing{-webkit-user-select:none;user-select:none}.gantt-wrapper.rtl .task-column{border-right:none;border-left:1px solid var(--g-row-border-color)}.gantt-wrapper.rtl .task-column-resize-handle{right:auto;left:0}
|
|
1
|
+
:root{--g-arrow-color: #1f2937;--g-arrow-hover-color: #007bff;--g-arrow-critical-color: #f5c044;--g-arrow-invalid-color: #ff7676;--g-bar-color: #fff;--g-bar-border: #fff;--g-tick-color-thick: #ededed;--g-tick-color: #f3f3f3;--g-actions-background: #f3f3f3;--g-border-color: #ebeff2;--g-text-muted: #7c7c7c;--g-text-light: #fff;--g-text-dark: #171717;--g-progress-color: #dbdbdb;--g-handle-color: transparent;--g-weekend-label-color: #dcdce4;--g-expected-progress: #c4c4e9;--g-header-background: #fff;--g-row-color: #fdfdfd;--g-row-border-color: #c7c7c7;--g-today-highlight: #37352f;--g-popup-actions: #ebeff2;--g-weekend-highlight-color: #f7f7f7;--g-task-column-bg: #ffffff;--g-task-row-bg: #ffffff;--g-resize-handle-hover: rgba(59, 130, 246, .3);--g-resize-handle-active: rgba(59, 130, 246, .5)}.gantt-wrapper{display:flex;width:100%;position:relative}.gantt-wrapper.rtl{flex-direction:row-reverse}.gantt-container{line-height:14.5px;position:relative;overflow:auto;font-size:12px;height:var(--gv-grid-height);flex:1;min-width:0;border-radius:8px}.gantt-container .popup-wrapper{position:absolute;top:0;left:0;background:#fff;box-shadow:0 10px 24px -3px #0003;padding:10px;border-radius:5px;width:max-content;z-index:1000}.gantt-container .popup-wrapper .title{margin-bottom:2px;color:var(--g-text-dark);font-size:.85rem;font-weight:650;line-height:15px}.gantt-container .popup-wrapper .subtitle{color:var(--g-text-dark);font-size:.8rem;margin-bottom:5px}.gantt-container .popup-wrapper .details{color:var(--g-text-muted);font-size:.7rem}.gantt-container .popup-wrapper .actions{margin-top:10px;margin-left:3px}.gantt-container .popup-wrapper .action-btn{border:none;padding:5px 8px;background-color:var(--g-popup-actions);border-right:1px solid var(--g-text-light)}.gantt-container .popup-wrapper .action-btn:hover{background-color:brightness(97%)}.gantt-container .popup-wrapper .action-btn:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px}.gantt-container .popup-wrapper .action-btn:last-child{border-right:none;border-top-right-radius:4px;border-bottom-right-radius:4px}.gantt-container .grid-header{height:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);background-color:var(--g-header-background);position:sticky;top:0;left:0;border-bottom:1px solid var(--g-row-border-color);z-index:1000}.gantt-container .lower-text,.gantt-container .upper-text{text-anchor:middle}.gantt-container .upper-header{height:var(--gv-upper-header-height)}.gantt-container .lower-header{height:var(--gv-lower-header-height)}.gantt-container .lower-text{font-size:12px;position:absolute;width:calc(var(--gv-column-width) * .8);height:calc(var(--gv-lower-header-height) * .8);margin:0 calc(var(--gv-column-width) * .1);align-content:center;text-align:center;color:var(--g-text-muted)}.gantt-container .upper-text{position:absolute;width:fit-content;font-weight:500;font-size:14px;color:var(--g-text-dark);height:calc(var(--gv-lower-header-height) * .66)}.gantt-container .current-upper{position:sticky;left:0!important;padding-left:17px;background:#fff}.gantt-container .side-header{position:sticky;top:0;right:0;float:right;z-index:1000;line-height:20px;font-weight:400;width:max-content;margin-left:auto;padding-right:10px;padding-top:10px;background:var(--g-header-background);display:flex}.gantt-container .side-header *{transition-property:background-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:var(--g-actions-background);border-radius:.5rem;border:none;padding:5px 8px;color:var(--g-text-dark);font-size:14px;letter-spacing:.02em;font-weight:420;box-sizing:content-box;margin-right:5px}.gantt-container .side-header *:last-child{margin-right:0}.gantt-container .side-header *:hover{filter:brightness(97.5%)}.gantt-container .side-header select{width:60px;padding-top:2px;padding-bottom:2px}.gantt-container .side-header select:focus{outline:none}.gantt-container .date-range-highlight{background-color:var(--g-progress-color);border-radius:12px;height:calc(var(--gv-lower-header-height) - 6px);top:calc(var(--gv-upper-header-height) + 5px);position:absolute}.gantt-container .current-highlight{position:absolute;background:var(--g-today-highlight);width:1px;z-index:999}.gantt-container .current-ball-highlight{position:absolute;background:var(--g-today-highlight);z-index:1001;border-radius:50%}.gantt-container .current-date-highlight{background:var(--g-today-highlight);color:var(--g-text-light);border-radius:5px}.gantt-container .holiday-label{position:absolute;top:0;left:0;opacity:0;z-index:1000;background:--g-weekend-label-color;border-radius:5px;padding:2px 5px}.gantt-container .holiday-label.show{opacity:100}.gantt-container .extras{position:sticky;left:0}.gantt-container .extras .adjust{position:absolute;left:8px;top:calc(var(--gv-grid-height) - 60px);background-color:#000000b3;color:#fff;border:none;padding:8px;border-radius:3px}.gantt-container .hide{display:none}.gantt{user-select:none;-webkit-user-select:none;position:absolute;left:0}.gantt .grid-background{fill:none}.gantt .grid-row{fill:var(--g-row-color)}.gantt .row-line{stroke:var(--g-border-color)}.gantt .tick{stroke:var(--g-tick-color);stroke-width:.4}.gantt .tick.thick{stroke:var(--g-tick-color-thick);stroke-width:.7}.gantt .arrow{fill:none;stroke:var(--g-arrow-color);stroke-width:1.5}.gantt .arrow-critical{stroke:var(--g-arrow-critical-color)}.gantt .arrow-invalid{stroke:var(--g-arrow-invalid-color)}.gantt .arrow-hover{stroke:var(--g-arrow-hover-color)}.gantt .bar-wrapper .bar{fill:var(--g-bar-color);stroke:var(--g-bar-border);stroke-width:0;transition:stroke-width .3s ease}.gantt .bar-wrapper .bar.bar-arrow-critical{outline-color:var(--g-arrow-critical-color)}.gantt .bar-wrapper .bar.bar-arrow-invalid{outline-color:var(--g-arrow-invalid-color)}.gantt .bar-progress{fill:var(--g-progress-color);border-radius:4px}.gantt .bar-expected-progress{fill:var(--g-expected-progress)}.gantt .bar-invalid{fill:transparent;stroke:var(--g-bar-border);stroke-width:1;stroke-dasharray:5}:is(.gantt .bar-invalid)~.bar-label{fill:var(--g-text-light)}.gantt .bar-label{fill:var(--g-text-dark);dominant-baseline:central;font-family:Helvetica;font-size:13px;font-weight:400}.gantt .bar-label.big{fill:var(--g-text-dark);text-anchor:start}.gantt .handle{fill:var(--g-handle-color);opacity:0;transition:opacity .3s ease}.gantt .handle.active,.gantt .handle.visible{cursor:ew-resize;opacity:1}.gantt .handle.progress{fill:var(--g-text-muted)}.gantt .bar-wrapper{cursor:pointer}.gantt .bar-wrapper .bar{outline:1px solid var(--g-row-border-color);border-radius:3px}.gantt .bar-wrapper:hover .bar{transition:transform .3s ease}.gantt .bar-wrapper:hover .date-range-highlight{display:block}.gantt .add-task-icon{cursor:pointer;transition:opacity .2s ease}.gantt .add-task-icon .add-task-icon-bg{fill:var(--g-bar-color);stroke:var(--g-bar-border);stroke-width:1;transition:all .2s ease}.gantt .add-task-icon .add-task-icon-plus{stroke:var(--g-text-dark);stroke-width:2;stroke-linecap:round;transition:stroke .2s ease}.gantt .add-task-icon.active .add-task-icon-bg,.gantt .add-task-icon:hover .add-task-icon-bg{fill:var(--g-progress-color);stroke:var(--g-progress-color)}.gantt .add-task-icon.active .add-task-icon-plus,.gantt .add-task-icon:hover .add-task-icon-plus{stroke:var(--g-text-light)}.task-column{flex-shrink:0;width:var(--gv-task-column-width, 150px);height:var(--gv-grid-height);background-color:var(--g-task-column-bg);border-right:1px solid var(--g-row-border-color);overflow-y:auto;overflow-x:hidden;-webkit-user-select:none;user-select:none;position:relative;scrollbar-width:none;-ms-overflow-style:none}.task-column::-webkit-scrollbar{display:none}.task-column-header{height:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);background-color:var(--g-header-background);border-bottom:1px solid var(--g-row-border-color);position:sticky;top:0;z-index:1001;display:flex;align-items:center;padding:0 12px;font-weight:600;font-size:13px;color:var(--g-text-dark)}.task-column-content{position:relative;width:100%;padding-top:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);overflow:visible}.task-row{position:absolute;width:100%;padding:0 12px;display:flex;align-items:center;font-size:13px;color:var(--g-text-dark);border-bottom:1px solid var(--g-row-border-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background-color:var(--g-task-row-bg)}.task-column-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;min-height:calc(var(--gv-task-column-content-height) + var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);cursor:col-resize;z-index:1002;background-color:transparent;transition:background-color .2s ease}.task-column-resize-handle:hover{background-color:var(--g-resize-handle-hover)}.task-column.resizing .task-column-resize-handle{background-color:var(--g-resize-handle-active)}.task-column.resizing{-webkit-user-select:none;user-select:none}.gantt-wrapper.rtl .task-column{border-right:none;border-left:1px solid var(--g-row-border-color)}.gantt-wrapper.rtl .task-column-resize-handle{right:auto;left:0}
|