@operato/gantt 8.0.0-alpha.6 → 8.0.0-beta.1

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/src/gantt-chart-controller.d.ts +5 -6
  3. package/dist/src/gantt-chart-controller.js +92 -37
  4. package/dist/src/gantt-chart-controller.js.map +1 -1
  5. package/dist/src/ox-gantt-chart.d.ts +378 -3
  6. package/dist/src/ox-gantt-chart.js +86 -180
  7. package/dist/src/ox-gantt-chart.js.map +1 -1
  8. package/dist/src/ox-gantt-resize-splitter.d.ts +6 -2
  9. package/dist/src/ox-gantt-resize-splitter.js +70 -39
  10. package/dist/src/ox-gantt-resize-splitter.js.map +1 -1
  11. package/dist/src/ox-gantt.js +11 -11
  12. package/dist/src/ox-gantt.js.map +1 -1
  13. package/dist/src/ox-resource-chart.js +2 -0
  14. package/dist/src/ox-resource-chart.js.map +1 -1
  15. package/dist/src/ox-task-tooltip.d.ts +3 -1
  16. package/dist/src/ox-task-tooltip.js +36 -11
  17. package/dist/src/ox-task-tooltip.js.map +1 -1
  18. package/dist/src/types.d.ts +1 -0
  19. package/dist/src/types.js.map +1 -1
  20. package/dist/stories/ox-gantt.stories.js +37 -1
  21. package/dist/stories/ox-gantt.stories.js.map +1 -1
  22. package/dist/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +13 -13
  24. package/themes/calendar-theme.css +3 -1
  25. package/.editorconfig +0 -29
  26. package/.storybook/main.js +0 -3
  27. package/.storybook/preview.js +0 -52
  28. package/.storybook/server.mjs +0 -8
  29. package/assets/images/icon-editor-gradient-direction.png +0 -0
  30. package/assets/images/icon-properties-label.png +0 -0
  31. package/assets/images/icon-properties-line-type.png +0 -0
  32. package/assets/images/icon-properties-table.png +0 -0
  33. package/src/draw-time-scale-header.ts +0 -142
  34. package/src/gantt-chart-controller.ts +0 -336
  35. package/src/index.ts +0 -0
  36. package/src/locales.ts +0 -78
  37. package/src/ox-gantt-chart.ts +0 -518
  38. package/src/ox-gantt-resize-splitter.ts +0 -131
  39. package/src/ox-gantt.ts +0 -532
  40. package/src/ox-resource-chart.ts +0 -145
  41. package/src/ox-task-tooltip.ts +0 -120
  42. package/src/resource-chart-controller.ts +0 -284
  43. package/src/types.ts +0 -32
  44. package/src/utils.ts +0 -13
  45. package/stories/ox-gantt-chart.stories.ts +0 -125
  46. package/stories/ox-gantt.stories.ts +0 -417
  47. package/tsconfig.json +0 -25
  48. package/web-dev-server.config.mjs +0 -27
  49. package/web-test-runner.config.mjs +0 -41
@@ -1,145 +0,0 @@
1
- import { LitElement, html, css } from 'lit'
2
- import { customElement, property, query } from 'lit/decorators.js'
3
- import { ResourceChartController } from './resource-chart-controller'
4
- import { Task, Resource, TimeScale } from './types'
5
-
6
- import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
7
- import { ScrollbarStyles } from '@operato/styles'
8
-
9
- @customElement('ox-resource-chart')
10
- export class OxResourceChart extends LitElement {
11
- static styles = [
12
- MDTypeScaleStyles,
13
- ScrollbarStyles,
14
- css`
15
- :host {
16
- display: flex;
17
- overflow: hidden;
18
- position: relative;
19
- }
20
-
21
- div[chart-container] {
22
- flex-direction: column;
23
- overflow-x: auto;
24
- overflow-y: hidden;
25
- }
26
-
27
- svg[header] {
28
- display: block;
29
- min-width: 100%;
30
- box-sizing: border-box;
31
- border-bottom: 1px solid var(--ox-gantt-header-border-color, var(--md-sys-color-outline));
32
- height: 30px;
33
- background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));
34
- color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));
35
- position: sticky;
36
- top: 0;
37
- z-index: 1;
38
- }
39
-
40
- svg[body] {
41
- display: block;
42
- min-width: 100%;
43
- }
44
-
45
- .grid line {
46
- stroke: #e0e0e0;
47
- }
48
-
49
- .grid path {
50
- stroke-width: 0;
51
- }
52
- `
53
- ]
54
-
55
- @property({ type: String }) fromDate: string = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0]
56
- @property({ type: String }) toDate: string = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0]
57
- @property({ type: String }) axisScale: TimeScale = 'week-day'
58
- @property({ type: Array }) resources: Resource[] = []
59
- @property({ type: Array }) tasks: Task[] = []
60
-
61
- @query('[chart-container]') container!: HTMLDivElement
62
- @query('svg[header]') svgHeader!: SVGSVGElement
63
- @query('svg[body]') svgBody!: SVGSVGElement
64
-
65
- private resourceChartController: ResourceChartController
66
-
67
- constructor() {
68
- super()
69
- this.resourceChartController = new ResourceChartController(this, this.fromDate, this.toDate, this.axisScale)
70
- }
71
-
72
- updated(changedProperties: Map<string | number | symbol, unknown>) {
73
- if (changedProperties.has('fromDate') || changedProperties.has('toDate')) {
74
- this.resourceChartController.updateRange(this.fromDate, this.toDate)
75
- }
76
-
77
- if (changedProperties.has('resources')) {
78
- this.resourceChartController.setResources(this.resources)
79
- this.updateChartHeight()
80
- }
81
-
82
- if (changedProperties.has('tasks')) {
83
- this.resourceChartController.setTasks(this.flattenTasks(this.tasks))
84
- this.updateChartHeight()
85
- }
86
-
87
- if (changedProperties.has('axisScale')) {
88
- this.resourceChartController.level = this.axisScale
89
- this.resourceChartController.updateTimeScale()
90
- }
91
-
92
- this.resourceChartController.drawAxes(this.svgHeader)
93
- this.resourceChartController.drawBody(this.svgBody)
94
- }
95
-
96
- updateChartHeight() {
97
- const resourceCount = this.resources.length
98
- const rowHeight = 30 // 리소스 하나당 할당된 높이 (픽셀)
99
- const minHeight = 200 // 최소 높이
100
- const chartHeight = Math.max(resourceCount * rowHeight, minHeight)
101
-
102
- this.svgBody.style.height = `${chartHeight}px`
103
- }
104
-
105
- render() {
106
- return html`
107
- <div
108
- chart-container
109
- @wheel=${(e: WheelEvent) => this.resourceChartController.handleWheelForBody(e, this.container)}
110
- @touchstart=${(e: TouchEvent) => this.resourceChartController.handleTouchStartForBody(e, this.container)}
111
- @touchmove=${(e: TouchEvent) => this.resourceChartController.handleTouchMoveForBody(e, this.container)}
112
- >
113
- <svg header></svg>
114
- <svg body></svg>
115
- </div>
116
- `
117
- }
118
-
119
- syncTimeScale(detail: { baseWidth: number; level: TimeScale }) {
120
- this.resourceChartController.syncTimeScale(detail)
121
- this.requestUpdate()
122
- }
123
-
124
- getHorizontalOffset(): number {
125
- return this.container.scrollLeft
126
- }
127
-
128
- setHorizontalOffset(offset: number) {
129
- this.container.scrollLeft = offset
130
- }
131
-
132
- getVerticalOffset(): number {
133
- return this.container.scrollTop
134
- }
135
-
136
- setVerticalOffset(offset: number) {
137
- this.container.scrollTop = offset
138
- }
139
-
140
- flattenTasks(tasks: Task[], level: number = 0): Task[] {
141
- return tasks.flatMap(task =>
142
- task.collapsed ? [{ ...task, level }] : [{ ...task, level }, ...this.flattenTasks(task.children || [], level + 1)]
143
- )
144
- }
145
- }
@@ -1,120 +0,0 @@
1
- import { LitElement, html, css } from 'lit'
2
- import { customElement, property } from 'lit/decorators.js'
3
-
4
- @customElement('ox-task-tooltip')
5
- export class OxTaskTooltip extends LitElement {
6
- static styles = css`
7
- :host {
8
- position: fixed; /* position: absolute로 변경 */
9
- background-color: var(--ox-gantt-tooltip-background-color, var(--md-sys-color-surface-variant, #f9f9f9));
10
- border: 1px solid var(--ox-gantt-tooltip-border-color, var(--md-sys-color-outline, #ccc));
11
- padding: var(--spacing-medium, 10px);
12
- border-radius: var(--spacing-medium, 8px);
13
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
14
- visibility: hidden;
15
- z-index: 10;
16
- max-width: 300px;
17
- font-family: Roboto;
18
- font-size: 14px;
19
- line-height: 1.6;
20
- color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));
21
- transition:
22
- visibility 0.1s,
23
- opacity 0.1s;
24
- opacity: 0; /* 초기에는 보이지 않음 */
25
- }
26
- :host([visible]) {
27
- visibility: visible;
28
- opacity: 1; /* 보일 때는 불투명 */
29
- }
30
- .title {
31
- font-weight: bold;
32
- font-size: 16px;
33
- margin-bottom: 8px;
34
- color: var(--ox-gantt-tooltip-title-color, var(--md-sys-color-primary, #0078d4)); /* 파란색 텍스트 */
35
- }
36
- .detail {
37
- display: grid;
38
- grid-template-columns: auto auto 1fr;
39
- gap: 4px;
40
- align-items: center;
41
- }
42
- .label {
43
- font-weight: bold;
44
- color: var(--ox-gantt-tooltip-color, var(--md-sys-color-secondary, #333));
45
- text-align: right; /* 라벨을 우측 정렬 */
46
- }
47
- .colon {
48
- text-align: center;
49
- color: var(--ox-gantt-tooltip-color, var(--md-sys-color-secondary, #333));
50
- }
51
- .value {
52
- text-align: left; /* 값을 좌측 정렬 */
53
- color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));
54
- }
55
- `
56
-
57
- @property({ type: String }) title = ''
58
- @property({ type: String }) startDate = ''
59
- @property({ type: String }) endDate = ''
60
- @property({ type: Number }) progress = 0
61
- @property({ type: String }) type = ''
62
-
63
- show(x: number, y: number) {
64
- const tooltipWidth = this.offsetWidth
65
- const tooltipHeight = this.offsetHeight
66
- const offsetX = 10
67
- const offsetY = 10
68
-
69
- // 기본 위치 계산
70
- let left = x + offsetX
71
- let top = y + offsetY
72
-
73
- // 화면 경계 확인 및 조정
74
- const screenWidth = window.innerWidth
75
- const screenHeight = window.innerHeight
76
-
77
- if (left + tooltipWidth > screenWidth) {
78
- left = x - tooltipWidth - offsetX
79
- }
80
- if (top + tooltipHeight > screenHeight) {
81
- top = y - tooltipHeight - offsetY
82
- }
83
-
84
- // offsetParent 요소를 기준으로 위치 설정
85
- if (this.offsetParent) {
86
- const parentRect = this.offsetParent!.getBoundingClientRect()
87
- this.style.left = `${left - parentRect.left}px`
88
- this.style.top = `${top - parentRect.top}px`
89
- } else {
90
- this.style.left = `${left}px`
91
- this.style.top = `${top}px`
92
-
93
- const myRect = this.getBoundingClientRect()
94
-
95
- /* 실제 바운드와 설정한 left/top 이 일치하지 않는다면, 부모 어딘가에서 transform 되었다고 판단하고, 보정해줌 */
96
- if (myRect.left !== left || myRect.top !== top) {
97
- this.style.left = `${left + (left - myRect.left)}px`
98
- this.style.top = `${top + (top - myRect.top)}px`
99
- }
100
- }
101
-
102
- this.setAttribute('visible', '')
103
- }
104
-
105
- hide() {
106
- this.removeAttribute('visible')
107
- }
108
-
109
- render() {
110
- return html`
111
- <div class="title">${this.title}</div>
112
- <div class="detail">
113
- <span class="label">Type</span><span class="colon">:</span><span class="value">${this.type}</span>
114
- <span class="label">Start Date</span><span class="colon">:</span><span class="value">${this.startDate}</span>
115
- <span class="label">End Date</span><span class="colon">:</span><span class="value">${this.endDate}</span>
116
- <span class="label">Progress</span><span class="colon">:</span><span class="value">${this.progress}%</span>
117
- </div>
118
- `
119
- }
120
- }
@@ -1,284 +0,0 @@
1
- import { LitElement, ReactiveController, ReactiveControllerHost } from 'lit'
2
- import * as d3 from 'd3'
3
- import { TimeScale, Task, Resource } from './types'
4
- import { drawTimeScaleHeader, getScale, getChartWidth } from './draw-time-scale-header'
5
-
6
- export class ResourceChartController implements ReactiveController {
7
- private host: ReactiveControllerHost & LitElement
8
- private fromTime: Date
9
- private toTime: Date
10
- private totalDays: number
11
- private _timeScale?: d3.ScaleTime<number, number, never>
12
-
13
- private touchStartY?: number
14
- private touchStartX?: number
15
- private scrollStartX?: number
16
- private scrollStartY?: number
17
-
18
- public baseWidth: number = 30
19
- public level: TimeScale
20
- public resources: Resource[] = []
21
- public tasks: Task[] = []
22
-
23
- constructor(host: ReactiveControllerHost & LitElement, fromDate: string, toDate: string, axisScale: TimeScale) {
24
- this.host = host
25
- this.fromTime = new Date(fromDate)
26
- this.toTime = new Date(toDate)
27
- this.level = axisScale
28
- this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))
29
- this.host.addController(this)
30
- }
31
-
32
- hostConnected() {
33
- this.updateTimeScale()
34
- }
35
-
36
- get timeScale() {
37
- if (!this._timeScale) {
38
- this._timeScale = d3
39
- .scaleTime()
40
- .domain([d3.timeDay.floor(this.fromTime), d3.timeDay.offset(this.toTime, 1)])
41
- .range([0, this.getChartWidth()])
42
- }
43
- return this._timeScale
44
- }
45
-
46
- public syncTimeScale(detail: { baseWidth: number; level: TimeScale }) {
47
- this.baseWidth = detail.baseWidth
48
- this.level = detail.level
49
-
50
- this.updateTimeScale()
51
- }
52
-
53
- updateRange(fromDate: string, toDate: string) {
54
- this.fromTime = new Date(fromDate)
55
- this.toTime = new Date(toDate)
56
- this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))
57
- this._timeScale = undefined
58
- this.host.requestUpdate()
59
- }
60
-
61
- setResources(resources: Resource[]) {
62
- this.resources = resources
63
- this.host.requestUpdate()
64
- }
65
-
66
- setTasks(tasks: Task[]) {
67
- this.tasks = tasks
68
- this.host.requestUpdate()
69
- }
70
-
71
- updateTimeScale() {
72
- this.timeScale.range([0, this.getChartWidth()])
73
- }
74
-
75
- getScale() {
76
- return getScale(this.level)
77
- }
78
-
79
- getChartWidth() {
80
- return getChartWidth(this.fromTime, this.toTime, this.baseWidth, this.level)
81
- }
82
-
83
- drawAxes(svgHeader: SVGElement) {
84
- drawTimeScaleHeader(svgHeader, this.timeScale, this.fromTime, this.toTime, this.baseWidth, this.level, false)
85
- }
86
-
87
- drawBody(svgBody: SVGElement) {
88
- const body = d3.select(svgBody)
89
-
90
- body.selectAll('*').remove()
91
- body.attr('width', this.getChartWidth())
92
-
93
- if (this.resources.length > 0) {
94
- const chartHeight = this.resources.length * 30
95
-
96
- const addGridLines = (ticks: Date[]) => {
97
- ticks.forEach(tick => {
98
- const startX = this.timeScale(tick)
99
- body
100
- .append('line')
101
- .attr('x1', startX)
102
- .attr('x2', startX)
103
- .attr('y1', 0)
104
- .attr('y2', chartHeight) // Ensure vertical lines extend to the bottom
105
- .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')
106
- .attr('stroke-width', 1)
107
- })
108
- }
109
-
110
- let ticks
111
- if (this.level === 'week-day') {
112
- ticks = d3.timeDay.every(1)!.range(d3.timeDay.floor(this.fromTime), d3.timeDay.offset(this.toTime, 1))
113
- } else if (this.level === 'quarter-week') {
114
- ticks = d3.timeWeek.every(1)!.range(d3.timeWeek.floor(this.fromTime), d3.timeWeek.offset(this.toTime, 1))
115
- } else if (this.level === 'year-month') {
116
- ticks = d3.timeMonth.every(1)!.range(d3.timeMonth.floor(this.fromTime), d3.timeMonth.offset(this.toTime, 1))
117
- } else if (this.level === 'year-quarter') {
118
- ticks = d3.timeMonth.every(3)!.range(d3.timeMonth.floor(this.fromTime), d3.timeMonth.offset(this.toTime, 3))
119
- }
120
-
121
- addGridLines(ticks!)
122
-
123
- this.renderResourceAllocations(body, ticks!, chartHeight)
124
- }
125
- }
126
-
127
- renderResourceAllocations(
128
- body: d3.Selection<SVGElement, unknown, null, undefined>,
129
- ticks: Date[],
130
- chartHeight: number
131
- ) {
132
- const resourceAllocations = this.calculateResourceAllocations(ticks)
133
-
134
- this.resources.forEach((resource, index) => {
135
- const y = index * 30 + 15 // Center the text vertically in the row
136
- ticks.forEach(tick => {
137
- const tickEnd = this.getTickEnd(tick)
138
- const dateKey = this.formatDateKey(tick, tickEnd)
139
- const allocation = resourceAllocations[resource.type][dateKey]
140
- if (allocation > 0) {
141
- const startX = this.timeScale(tick)
142
- const tickInterval = this.timeScale(tickEnd) - startX
143
-
144
- body
145
- .append('text')
146
- .attr('x', startX + tickInterval / 2)
147
- .attr('y', y)
148
- .attr('text-anchor', 'middle')
149
- .attr('alignment-baseline', 'middle')
150
- .attr('dominant-baseline', 'middle')
151
- .attr('stroke', 'var(--ox-gantt-color-text, var(--md-sys-color-on-primary-container))')
152
- .text(allocation)
153
- .style('font-size', '12px')
154
- }
155
- })
156
- })
157
-
158
- // Draw horizontal grid lines for each resource row
159
- for (let i = 0; i <= this.resources.length; i++) {
160
- body
161
- .append('line')
162
- .attr('x1', 0)
163
- .attr('x2', this.getChartWidth())
164
- .attr('y1', i * 30)
165
- .attr('y2', i * 30)
166
- .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')
167
- .attr('stroke-width', 1)
168
- }
169
- }
170
-
171
- calculateResourceAllocations(ticks: Date[]): { [key: string]: { [key: string]: number } } {
172
- const resourceAllocations: { [key: string]: { [key: string]: number } } = {}
173
-
174
- this.resources.forEach(resource => {
175
- resourceAllocations[resource.type] = {}
176
- ticks.forEach(tick => {
177
- const tickEnd = this.getTickEnd(tick)
178
- const dateKey = this.formatDateKey(tick, tickEnd)
179
- resourceAllocations[resource.type][dateKey] = 0
180
- })
181
- })
182
-
183
- this.tasks.forEach(task => {
184
- const startDate = new Date(task.startDate)
185
- const endDate = new Date(task.endDate)
186
- let currentDate = startDate
187
-
188
- while (currentDate <= endDate) {
189
- const tick = ticks.find(t => currentDate >= t && currentDate < this.getTickEnd(t))
190
- if (tick) {
191
- const tickEnd = this.getTickEnd(tick)
192
- const dateKey = this.formatDateKey(tick, tickEnd)
193
-
194
- ;(task.resources || []).forEach(resource => {
195
- if (resourceAllocations[resource.type][dateKey] !== undefined) {
196
- resourceAllocations[resource.type][dateKey] += resource.allocated
197
- }
198
- })
199
- }
200
-
201
- currentDate.setDate(currentDate.getDate() + 1)
202
- }
203
- })
204
-
205
- return resourceAllocations
206
- }
207
-
208
- getTickEnd(tick: Date): Date {
209
- if (this.level === 'week-day') {
210
- return d3.timeDay.offset(tick, 1)
211
- } else if (this.level === 'quarter-week') {
212
- return d3.timeWeek.offset(tick, 1)
213
- } else if (this.level === 'year-month') {
214
- return d3.timeMonth.offset(tick, 1)
215
- } else if (this.level === 'year-quarter') {
216
- return d3.timeMonth.offset(tick, 3)
217
- }
218
- return d3.timeDay.offset(tick, 1)
219
- }
220
-
221
- formatDateKey(start: Date, end: Date): string {
222
- return `${start.toISOString().split('T')[0]}_${end.toISOString().split('T')[0]}`
223
- }
224
-
225
- handleWheelForBody(event: WheelEvent, container: HTMLDivElement) {
226
- event.preventDefault()
227
- event.stopPropagation()
228
-
229
- const deltaModeFactor =
230
- event.deltaMode === WheelEvent.DOM_DELTA_LINE
231
- ? 16
232
- : event.deltaMode === WheelEvent.DOM_DELTA_PAGE
233
- ? container.clientHeight
234
- : 1
235
- const deltaX = event.deltaX * deltaModeFactor
236
- const deltaY = event.deltaY * deltaModeFactor
237
-
238
- container.scrollLeft += deltaX
239
- container.scrollTop += deltaY
240
-
241
- const customEvent = new CustomEvent('scroll', {
242
- detail: {
243
- scrollLeft: container.scrollLeft,
244
- scrollTop: container.scrollTop
245
- },
246
- bubbles: true,
247
- composed: true
248
- })
249
-
250
- this.host.dispatchEvent(customEvent)
251
- }
252
-
253
- handleTouchStartForBody(event: TouchEvent, container: HTMLDivElement) {
254
- event.stopPropagation()
255
-
256
- this.touchStartX = event.touches[0].clientX
257
- this.touchStartY = event.touches[0].clientY
258
-
259
- this.scrollStartX = container.scrollLeft
260
- this.scrollStartY = container.scrollTop
261
- }
262
-
263
- handleTouchMoveForBody(event: TouchEvent, container: HTMLDivElement) {
264
- const touchCurrentX = event.touches[0].clientX
265
- const touchCurrentY = event.touches[0].clientY
266
-
267
- const deltaX = this.touchStartX! - touchCurrentX
268
- const deltaY = this.touchStartY! - touchCurrentY
269
-
270
- container.scrollLeft = this.scrollStartX! + deltaX
271
- container.scrollTop = this.scrollStartY! + deltaY
272
-
273
- const customEvent = new CustomEvent('scroll', {
274
- detail: {
275
- scrollLeft: container.scrollLeft,
276
- scrollTop: container.scrollTop
277
- },
278
- bubbles: true,
279
- composed: true
280
- })
281
-
282
- this.host.dispatchEvent(customEvent)
283
- }
284
- }
package/src/types.ts DELETED
@@ -1,32 +0,0 @@
1
- export type TaskTag = 'done' | 'active' | 'critical' | 'milestone'
2
- export type TaskType = 'group' | 'task' | 'milestone' | 'phase'
3
-
4
- export interface Task {
5
- id: string
6
- title: string
7
- type: TaskType
8
- startDate: Date | string
9
- endDate: Date | string
10
- progress?: number
11
- dependsOn?: string
12
- duration: number
13
- tags?: TaskTag[]
14
- children?: Task[]
15
- resources?: Resource[]
16
- collapsed?: boolean
17
- }
18
-
19
- export interface ColumnConfig {
20
- name: string
21
- label: string
22
- visible: boolean
23
- width: number
24
- order: number
25
- }
26
-
27
- export type TimeScale = 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'
28
-
29
- export interface Resource {
30
- type: string
31
- allocated: number
32
- }
package/src/utils.ts DELETED
@@ -1,13 +0,0 @@
1
- import { TimeScale } from './types'
2
-
3
- const levels: TimeScale[] = ['week-day', 'quarter-week', 'year-month', 'year-quarter']
4
-
5
- export function levelUp(level: 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'): TimeScale {
6
- const current = Math.min(levels.length, levels.indexOf(level) + 1)
7
- return levels[current]
8
- }
9
-
10
- export function levelDown(level: 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'): TimeScale {
11
- const current = Math.max(0, levels.indexOf(level) - 1)
12
- return levels[current]
13
- }