react-timelane 0.0.0 → 0.0.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 (110) hide show
  1. package/dist/components/TimelineAside.d.ts +13 -0
  2. package/dist/components/TimelineBackground.d.ts +5 -0
  3. package/dist/components/TimelineBody.d.ts +13 -0
  4. package/dist/components/TimelineHeader/DaysHeader.d.ts +15 -0
  5. package/dist/components/TimelineHeader/MonthsHeader.d.ts +15 -0
  6. package/dist/components/TimelineHeader/TimelineHeader.d.ts +24 -0
  7. package/dist/components/TimelineHeader/WeeksHeader.d.ts +15 -0
  8. package/dist/components/TimelineHeader/index.d.ts +5 -0
  9. package/dist/components/TimelineHeader/renderingUtils.d.ts +4 -0
  10. package/dist/components/TimelineSelectionLayer.d.ts +6 -0
  11. package/dist/components/TimelineSettingsContext.d.ts +7 -0
  12. package/dist/components/TimelineSettingsProvider.d.ts +7 -0
  13. package/dist/components/TimelineWrapper.d.ts +17 -0
  14. package/dist/components/core/CoreItem/CoreItemComponent.d.ts +14 -0
  15. package/dist/components/core/CoreItem/DragResizeComponent.d.ts +20 -0
  16. package/dist/components/core/CoreSwimlane/AvailableSpaceIndicator.d.ts +21 -0
  17. package/dist/components/core/CoreSwimlane/CoreSwimlane.d.ts +16 -0
  18. package/dist/components/core/CoreSwimlane/DropPreview.d.ts +9 -0
  19. package/dist/components/core/CoreSwimlane/DropTarget.d.ts +11 -0
  20. package/dist/components/core/CoreSwimlane/OverlapIndicator.d.ts +6 -0
  21. package/dist/components/core/CoreSwimlane/utils.d.ts +13 -0
  22. package/dist/components/core/utils.d.ts +15 -0
  23. package/dist/components/layout/TimelineLayout.d.ts +23 -0
  24. package/dist/hooks/useScroll.d.ts +10 -0
  25. package/dist/hooks/useTimelineContext.d.ts +1 -0
  26. package/dist/index.d.ts +13 -0
  27. package/dist/react-timelane.css +1 -0
  28. package/dist/react-timelane.js +4744 -0
  29. package/dist/types/AvailableSpace.d.ts +6 -0
  30. package/dist/types/CoreItem.d.ts +12 -0
  31. package/dist/types/DateBounds.d.ts +4 -0
  32. package/dist/types/Dimensions.d.ts +4 -0
  33. package/dist/types/GrabInfo.d.ts +5 -0
  34. package/dist/types/Grid.d.ts +6 -0
  35. package/dist/types/OffsetBounds.d.ts +4 -0
  36. package/dist/types/Pixels.d.ts +4 -0
  37. package/{src/types/Position.ts → dist/types/Position.d.ts} +2 -2
  38. package/dist/types/Rectangle.d.ts +6 -0
  39. package/dist/types/SwimlaneT.d.ts +5 -0
  40. package/dist/types/TimeRange.d.ts +4 -0
  41. package/dist/types/TimelineSettings.d.ts +11 -0
  42. package/dist/types/index.d.ts +15 -0
  43. package/package.json +1 -1
  44. package/vite.config.ts +1 -1
  45. package/.github/workflows/static.yml +0 -55
  46. package/docs/README.md +0 -54
  47. package/docs/eslint.config.js +0 -28
  48. package/docs/index.html +0 -12
  49. package/docs/package-lock.json +0 -5101
  50. package/docs/package.json +0 -35
  51. package/docs/src/App.css +0 -5
  52. package/docs/src/App.tsx +0 -59
  53. package/docs/src/assets/react.svg +0 -1
  54. package/docs/src/components/AllocationComponent.tsx +0 -82
  55. package/docs/src/components/Timeline.tsx +0 -183
  56. package/docs/src/constants.ts +0 -42
  57. package/docs/src/hooks/useLocalStorage.ts +0 -21
  58. package/docs/src/main.tsx +0 -9
  59. package/docs/src/models/Allocation.ts +0 -11
  60. package/docs/src/models/AllocationId.ts +0 -1
  61. package/docs/src/models/Resource.ts +0 -8
  62. package/docs/src/models/ResourceId.ts +0 -1
  63. package/docs/src/vite-env.d.ts +0 -1
  64. package/docs/tsconfig.json +0 -27
  65. package/docs/vite.config.ts +0 -8
  66. package/src/components/Timeline.scss +0 -297
  67. package/src/components/TimelineAside.tsx +0 -81
  68. package/src/components/TimelineBackground.tsx +0 -53
  69. package/src/components/TimelineBody.tsx +0 -54
  70. package/src/components/TimelineHeader/DaysHeader.tsx +0 -44
  71. package/src/components/TimelineHeader/MonthsHeader.tsx +0 -62
  72. package/src/components/TimelineHeader/TimelineHeader.tsx +0 -64
  73. package/src/components/TimelineHeader/WeeksHeader.tsx +0 -63
  74. package/src/components/TimelineHeader/index.ts +0 -9
  75. package/src/components/TimelineHeader/renderingUtils.tsx +0 -57
  76. package/src/components/TimelineSelectionLayer.tsx +0 -179
  77. package/src/components/TimelineSettingsContext.tsx +0 -27
  78. package/src/components/TimelineSettingsProvider.tsx +0 -24
  79. package/src/components/TimelineWrapper.tsx +0 -51
  80. package/src/components/core/CoreItem/CoreItemComponent.tsx +0 -69
  81. package/src/components/core/CoreItem/DragResizeComponent.tsx +0 -180
  82. package/src/components/core/CoreSwimlane/AvailableSpaceIndicator.tsx +0 -156
  83. package/src/components/core/CoreSwimlane/CoreSwimlane.tsx +0 -245
  84. package/src/components/core/CoreSwimlane/DropPreview.tsx +0 -30
  85. package/src/components/core/CoreSwimlane/DropTarget.tsx +0 -83
  86. package/src/components/core/CoreSwimlane/OverlapIndicator.tsx +0 -22
  87. package/src/components/core/CoreSwimlane/utils.ts +0 -375
  88. package/src/components/core/utils.ts +0 -154
  89. package/src/components/layout/TimelineLayout.tsx +0 -93
  90. package/src/components/layout/layout.scss +0 -107
  91. package/src/global.d.ts +0 -9
  92. package/src/hooks/useScroll.tsx +0 -71
  93. package/src/hooks/useTimelineContext.tsx +0 -6
  94. package/src/index.ts +0 -15
  95. package/src/types/AvailableSpace.ts +0 -6
  96. package/src/types/CoreItem.ts +0 -23
  97. package/src/types/DateBounds.ts +0 -4
  98. package/src/types/Dimensions.ts +0 -4
  99. package/src/types/GrabInfo.ts +0 -6
  100. package/src/types/Grid.ts +0 -6
  101. package/src/types/OffsetBounds.ts +0 -4
  102. package/src/types/Pixels.ts +0 -4
  103. package/src/types/Rectangle.ts +0 -6
  104. package/src/types/SwimlaneT.ts +0 -6
  105. package/src/types/TimeRange.ts +0 -4
  106. package/src/types/TimelineSettings.ts +0 -11
  107. package/src/types/index.ts +0 -15
  108. package/tsconfig.json +0 -32
  109. /package/{src/types/ItemId.ts → dist/types/ItemId.d.ts} +0 -0
  110. /package/{src/types/SwimlaneId.ts → dist/types/SwimlaneId.d.ts} +0 -0
@@ -1,375 +0,0 @@
1
- import { max, min } from "date-fns";
2
- import {
3
- getItemDimensions,
4
- getItemRectangle,
5
- getDropTargetDimensions,
6
- } from "../utils";
7
- import {
8
- AvailableSpace,
9
- CoreItem,
10
- DateBounds,
11
- Dimensions,
12
- GrabInfo,
13
- Grid,
14
- OffsetBounds,
15
- Pixels,
16
- Position,
17
- Rectangle,
18
- SwimlaneT,
19
- TimeRange,
20
- } from "../../../types";
21
-
22
- export function getDropPreviewRectangle<S, T>(
23
- swimlane: SwimlaneT,
24
- items: CoreItem<T>[],
25
- item: CoreItem<S>,
26
- mousePosition: Position | null,
27
- grabInfo: GrabInfo,
28
- pixels: Pixels,
29
- grid: Grid,
30
- range: TimeRange,
31
- allowOverlaps: boolean
32
- ): Rectangle | null {
33
- if (mousePosition === null) {
34
- return null;
35
- }
36
-
37
- const dropTargetDimensions: Dimensions = getDropTargetDimensions(
38
- swimlane,
39
- pixels,
40
- range
41
- );
42
-
43
- const itemRectangles: Rectangle[] = items
44
- .filter((a) => a.id !== item.id)
45
- .map((a) => getItemRectangle(a, swimlane, range, pixels));
46
-
47
- let dropPreviewRectangle: Rectangle | null = null;
48
-
49
- dropPreviewRectangle = getRectangleUnderCursor(
50
- swimlane,
51
- item,
52
- grabInfo,
53
- pixels,
54
- mousePosition
55
- );
56
-
57
- dropPreviewRectangle = fitToGrid(dropPreviewRectangle, grid);
58
-
59
- dropPreviewRectangle = fitToDropTarget(
60
- dropPreviewRectangle,
61
- dropTargetDimensions
62
- );
63
-
64
- dropPreviewRectangle = getNearestDropDestinationWithoutOverlap(
65
- dropPreviewRectangle,
66
- itemRectangles,
67
- dropTargetDimensions,
68
- allowOverlaps
69
- );
70
-
71
- return dropPreviewRectangle;
72
- }
73
-
74
- /**
75
- * computes rectangle for DropPreview that is under the cursor, in pixel coordinates relative to the current DropTarget
76
- * @param dragData
77
- * @param swimlane
78
- * @param pixels
79
- * @param mousePosition
80
- * @returns
81
- */
82
- function getRectangleUnderCursor<T>(
83
- swimlane: SwimlaneT,
84
- item: CoreItem<T>,
85
- grabInfo: GrabInfo,
86
- pixels: Pixels,
87
- mousePosition: Position
88
- ): Rectangle {
89
- const { width, height } = getItemDimensions(item, swimlane, pixels);
90
- const x = mousePosition.x + width * grabInfo.relative.x;
91
- const y = mousePosition.y + height * grabInfo.relative.y;
92
-
93
- return {
94
- x,
95
- y,
96
- width,
97
- height,
98
- };
99
- }
100
-
101
- function fitToDropTarget(
102
- rect: Rectangle,
103
- dropTargetDimensions: Dimensions
104
- ): Rectangle {
105
- // adjust coordinates to always be in DropTarget rectangle
106
-
107
- const x = Math.max(
108
- 0,
109
- Math.min(rect.x, dropTargetDimensions.width - rect.width)
110
- );
111
- const y = Math.max(
112
- 0,
113
- Math.min(rect.y, dropTargetDimensions.height - rect.height)
114
- );
115
-
116
- return {
117
- ...rect,
118
- x,
119
- y,
120
- };
121
- }
122
-
123
- function fitToGrid(rect: Rectangle, grid: Grid | null | undefined): Rectangle {
124
- const destination = {
125
- ...rect,
126
- };
127
-
128
- if (grid && grid.x) {
129
- destination.x = roundToNearest(destination.x, grid.x, grid.offsetX || 0);
130
- }
131
-
132
- if (grid && grid.y) {
133
- destination.y = roundToNearest(destination.y, grid.y, grid.offsetY || 0);
134
- }
135
-
136
- return destination;
137
- }
138
-
139
- function roundToNearest(
140
- value: number,
141
- interval: number,
142
- offset: number
143
- ): number {
144
- return Math.max(
145
- offset,
146
- offset + Math.round((value - offset) / interval) * interval
147
- );
148
- }
149
-
150
- function getNearestDropDestinationWithoutOverlap(
151
- item: Rectangle,
152
- allItems: Rectangle[],
153
- targetDimensions: Dimensions,
154
- allowOverlaps: boolean
155
- ): Rectangle | null {
156
- const newItem: Rectangle = {
157
- ...item,
158
- };
159
-
160
- if (!allowOverlaps) {
161
- let isOverlapping = true;
162
-
163
- while (isOverlapping) {
164
- const firstOverlapping: Rectangle | undefined = allItems.find((other) => {
165
- return doOverlap(newItem, other);
166
- });
167
-
168
- if (firstOverlapping !== undefined) {
169
- // move the element below the one it overlaps with
170
- newItem.y = firstOverlapping.y + firstOverlapping.height;
171
- } else {
172
- isOverlapping = false;
173
- }
174
- }
175
- }
176
-
177
- if (!isWithinTargetDimensions(newItem, targetDimensions)) {
178
- return null;
179
- } else {
180
- return newItem;
181
- }
182
- }
183
-
184
- /**
185
- * Returns true if two rectangles (l1, r1) and (l2, r2) overlap
186
- * @param el1
187
- * @param el2
188
- * @returns
189
- */
190
- export function doOverlap(el1: Rectangle, el2: Rectangle): boolean {
191
- if (el1.x >= el2.x + el2.width || el2.x >= el1.x + el1.width) {
192
- return false;
193
- }
194
-
195
- if (el1.y >= el2.y + el2.height || el2.y >= el1.y + el1.height) {
196
- return false;
197
- }
198
-
199
- return true;
200
- }
201
-
202
- export function getOverlap(
203
- rect1: Rectangle,
204
- rect2: Rectangle
205
- ): Rectangle | null {
206
- // Calculate the coordinates of the overlapping region
207
- const overlapX1 = Math.max(rect1.x, rect2.x);
208
- const overlapY1 = Math.max(rect1.y, rect2.y);
209
- const overlapX2 = Math.min(rect1.x + rect1.width, rect2.x + rect2.width);
210
- const overlapY2 = Math.min(rect1.y + rect1.height, rect2.y + rect2.height);
211
-
212
- // Check if there is an overlap
213
- if (overlapX1 < overlapX2 && overlapY1 < overlapY2) {
214
- return {
215
- x: overlapX1,
216
- y: overlapY1,
217
- width: overlapX2 - overlapX1,
218
- height: overlapY2 - overlapY1,
219
- };
220
- } else {
221
- // No overlap
222
- return null;
223
- }
224
- }
225
-
226
- export function itemsDoOverlap<T>(a: CoreItem<T>, b: CoreItem<T>): boolean {
227
- if (
228
- a.start >= b.end ||
229
- b.start >= a.end ||
230
- a.offset >= b.offset + b.size ||
231
- b.offset >= a.offset + a.size
232
- ) {
233
- return false;
234
- }
235
-
236
- return true;
237
- }
238
-
239
- export function isWithinTargetDimensions(
240
- item: Rectangle,
241
- targetDimensions: Dimensions
242
- ): boolean {
243
- return (
244
- item.x >= 0 &&
245
- item.y >= 0 &&
246
- item.x + item.width <= targetDimensions.width &&
247
- item.y + item.height <= targetDimensions.height
248
- );
249
- }
250
-
251
- export function getAvailableSpace<T>(
252
- clickedDate: Date,
253
- clickedOffset: number,
254
- swimlane: SwimlaneT,
255
- items: CoreItem<T>[],
256
- range: TimeRange
257
- ): AvailableSpace | null {
258
- const offsetBounds = getOffsetBounds(
259
- clickedDate,
260
- clickedOffset,
261
- swimlane.capacity,
262
- items
263
- );
264
-
265
- if (offsetBounds) {
266
- const dateBounds = getDateBounds(
267
- clickedDate,
268
- range.start,
269
- range.end,
270
- items,
271
- offsetBounds
272
- );
273
-
274
- if (dateBounds) {
275
- return {
276
- start: dateBounds.lower,
277
- end: dateBounds.upper,
278
- minOffset: offsetBounds.lower,
279
- maxOffset: offsetBounds.upper,
280
- };
281
- }
282
- }
283
-
284
- return null;
285
- }
286
-
287
- function getOffsetBounds<T>(
288
- clickedDate: Date,
289
- clickedOffset: number,
290
- maxUpperBound: number,
291
- items: CoreItem<T>[]
292
- ): null | OffsetBounds {
293
- const allocationsAtDate: CoreItem<T>[] = items.filter((a) => {
294
- return a.start <= clickedDate && a.end >= clickedDate;
295
- });
296
-
297
- // 1. check if there is an allocation at the place where the click occurred
298
- const allocationAtClick: CoreItem<T> | undefined = allocationsAtDate.find(
299
- (a) => a.offset <= clickedOffset && a.offset + a.size >= clickedOffset
300
- );
301
-
302
- if (allocationAtClick) {
303
- return null;
304
- }
305
- // part remaining allocations by whether they are above or below the click
306
- const allocationsAboveClick = allocationsAtDate.filter((a) => {
307
- return a.offset + a.size <= clickedOffset;
308
- });
309
-
310
- const allocationsBelowClick = allocationsAtDate.filter((a) => {
311
- return a.offset >= clickedOffset;
312
- });
313
-
314
- // the minimum available space in offset coordinates is the
315
- // maximum (offset + size) of all allocations above
316
- const lowerOffsetBound =
317
- allocationsAboveClick.length > 0
318
- ? Math.max(...allocationsAboveClick.map((a) => a.offset + a.size))
319
- : 0;
320
-
321
- const upperOffsetBound =
322
- allocationsBelowClick.length > 0
323
- ? Math.min(...allocationsBelowClick.map((a) => a.offset))
324
- : maxUpperBound;
325
-
326
- return {
327
- lower: lowerOffsetBound,
328
- upper: upperOffsetBound,
329
- };
330
- }
331
-
332
- function getDateBounds<T>(
333
- clickedDate: Date,
334
- minLowerBound: Date,
335
- maxUpperBound: Date,
336
- items: CoreItem<T>[],
337
- offsetBounds: OffsetBounds
338
- ): DateBounds | null {
339
- const dummyItem: CoreItem<null> = {
340
- id: -1,
341
- swimlaneId: -1,
342
- start: minLowerBound,
343
- end: maxUpperBound,
344
- offset: offsetBounds.lower,
345
- size: offsetBounds.upper - offsetBounds.lower,
346
- payload: null,
347
- };
348
-
349
- const overlappingItems: CoreItem<T>[] = items.filter((a) =>
350
- itemsDoOverlap(a, dummyItem)
351
- );
352
-
353
- if (overlappingItems.length === 0) {
354
- return {
355
- lower: minLowerBound,
356
- upper: maxUpperBound,
357
- };
358
- }
359
-
360
- const itemsBefore = overlappingItems.filter((a) => a.end <= clickedDate);
361
-
362
- const itemsAfter = overlappingItems.filter((a) => a.start >= clickedDate);
363
-
364
- // the minimum available space in offset coordinates is the
365
- // maximum (offset + size) of all allocations above
366
- const lowerDateBound =
367
- itemsBefore.length > 0 ? max(itemsBefore.map((a) => a.end)) : minLowerBound;
368
- const upperDateBound =
369
- itemsAfter.length > 0 ? min(itemsAfter.map((a) => a.start)) : maxUpperBound;
370
-
371
- return {
372
- lower: lowerDateBound,
373
- upper: upperDateBound,
374
- };
375
- }
@@ -1,154 +0,0 @@
1
- import {
2
- DragLocationHistory,
3
- ElementDragPayload,
4
- } from "@atlaskit/pragmatic-drag-and-drop/dist/types/internal-types";
5
- import { addDays, differenceInCalendarDays, setHours } from "date-fns";
6
- import {
7
- CoreItem,
8
- Dimensions,
9
- Pixels,
10
- Position,
11
- Rectangle,
12
- SwimlaneT,
13
- TimeRange,
14
- } from "../../types";
15
-
16
- export function getDropTargetDimensions(
17
- swimlane: SwimlaneT,
18
- pixels: Pixels,
19
- range: TimeRange
20
- ): Dimensions {
21
- const width = getDropTargetWidth(swimlane, pixels, range);
22
- const height = getDropTargetHeight(swimlane, pixels);
23
-
24
- return { width, height };
25
- }
26
-
27
- export function getDropTargetHeight(
28
- swimlane: SwimlaneT,
29
- pixels: Pixels
30
- ): number {
31
- return pixels.pixelsPerResource;
32
- }
33
-
34
- export function getDropTargetWidth(
35
- swimlane: SwimlaneT,
36
- pixels: Pixels,
37
- range: TimeRange
38
- ): number {
39
- return Math.abs(
40
- (differenceInCalendarDays(range.end, range.start) + 1) * pixels.pixelsPerDay
41
- );
42
- }
43
-
44
- export function getItemRectangle<T>(
45
- item: CoreItem<T>,
46
- swimlane: SwimlaneT,
47
- range: TimeRange,
48
- pixels: Pixels
49
- ): Rectangle {
50
- const dimensions = getItemDimensions(item, swimlane, pixels);
51
- const position = getItemPosition(item, swimlane, range.start, pixels);
52
-
53
- return {
54
- ...dimensions,
55
- ...position,
56
- };
57
- }
58
-
59
- export function getItemDimensions<T>(
60
- item: CoreItem<T>,
61
- swimlane: SwimlaneT,
62
- pixels: Pixels
63
- ): Dimensions {
64
- const width =
65
- differenceInCalendarDays(item.end, item.start) * pixels.pixelsPerDay;
66
-
67
- const height = (item.size / swimlane.capacity) * pixels.pixelsPerResource;
68
-
69
- return { width, height };
70
- }
71
-
72
- export function dateToPixel(date: Date, start: Date, pixels: Pixels) {
73
- return (
74
- differenceInCalendarDays(date, start) * pixels.pixelsPerDay +
75
- pixels.pixelsPerDay / 2
76
- );
77
- }
78
-
79
- export function offsetToPixel(
80
- offset: number,
81
- capacity: number,
82
- pixels: Pixels
83
- ) {
84
- return (offset / capacity) * pixels.pixelsPerResource;
85
- }
86
-
87
- export function getItemPosition<T>(
88
- item: CoreItem<T>,
89
- swimlane: SwimlaneT,
90
- start: Date,
91
- pixels: Pixels
92
- ): Position {
93
- const x = dateToPixel(item.start, start, pixels);
94
- const y = offsetToPixel(item.offset, swimlane.capacity, pixels);
95
-
96
- return { x, y };
97
- }
98
-
99
- export function getGrabPosition(
100
- source: ElementDragPayload,
101
- location: DragLocationHistory
102
- ) {
103
- const sourceRect = source.element.getBoundingClientRect();
104
-
105
- const grabPosition: Position = {
106
- x: sourceRect.x - location.initial.input.pageX,
107
- y: sourceRect.y - location.initial.input.pageY,
108
- };
109
-
110
- const relativeGrabPosition: Position = {
111
- x: grabPosition.x / sourceRect.width,
112
- y: grabPosition.y / sourceRect.height,
113
- };
114
-
115
- return {
116
- absolute: grabPosition,
117
- relative: relativeGrabPosition,
118
- };
119
- }
120
-
121
- export function getUpdatedItem<T>(
122
- oldItem: CoreItem<T>,
123
- swimlane: SwimlaneT,
124
- dropPreviewRect: Rectangle,
125
- pixels: Pixels,
126
- range: TimeRange
127
- ): CoreItem<T> {
128
- // convert drop preview position to item
129
- return {
130
- id: oldItem.id,
131
- swimlaneId: swimlane.id,
132
-
133
- start: setHours(
134
- addDays(range.start, Math.floor(dropPreviewRect.x / pixels.pixelsPerDay)),
135
- 12
136
- ),
137
- end: setHours(
138
- addDays(
139
- range.start,
140
- Math.floor(
141
- (dropPreviewRect.x + dropPreviewRect.width) / pixels.pixelsPerDay
142
- )
143
- ),
144
- 12
145
- ),
146
- offset: Math.floor(
147
- (dropPreviewRect.y / pixels.pixelsPerResource) * swimlane.capacity
148
- ),
149
- size: Math.floor(
150
- (dropPreviewRect.height / pixels.pixelsPerResource) * swimlane.capacity
151
- ),
152
- payload: oldItem.payload,
153
- };
154
- }
@@ -1,93 +0,0 @@
1
- import { PropsWithChildren, useRef } from "react";
2
- import "./layout.scss";
3
-
4
- function TimelineLayout({ children }: PropsWithChildren<{}>) {
5
- const ref = useRef<HTMLDivElement>(null);
6
- return (
7
- <div
8
- className="timeline-layout"
9
- onWheel={(e) => {
10
- if (ref.current && (e.ctrlKey || e.shiftKey)) {
11
- ref.current.scrollLeft += e.deltaY;
12
- e.preventDefault();
13
- }
14
- }}
15
- ref={ref}
16
- >
17
- <div className="timeline-layout-inner">{children}</div>
18
- </div>
19
- );
20
- }
21
- function TimelineLayoutHeader({ children }: PropsWithChildren<{}>) {
22
- return <div className="timeline-layout-header">{children}</div>;
23
- }
24
-
25
- function TimelineLayoutBackground({ children }: PropsWithChildren<{}>) {
26
- return <div className="timeline-layout-background">{children}</div>;
27
- }
28
- function TimelineLayoutBody({ children }: PropsWithChildren<{}>) {
29
- return <div className="timeline-layout-body">{children}</div>;
30
- }
31
- function TimelineLayoutFooter({ children }: PropsWithChildren<{}>) {
32
- return <div className="timeline-layout-footer">{children}</div>;
33
- }
34
-
35
- interface TimelineLayoutAsideProps {
36
- side?: "left" | "right";
37
- }
38
-
39
- function TimelineLayoutAside({
40
- side = "left",
41
- children,
42
- }: PropsWithChildren<TimelineLayoutAsideProps>) {
43
- return (
44
- <div
45
- className={`timeline-layout-aside ${
46
- side == "left"
47
- ? "timeline-layout-aside-left"
48
- : "timeline-layout-aside-right"
49
- }`}
50
- >
51
- {children}
52
- </div>
53
- );
54
- }
55
-
56
- interface TimelineLayoutCornerProps {
57
- corner?: "top left" | "top right" | "bottom left" | "bottom right";
58
- }
59
-
60
- function TimelineLayoutCorner({
61
- corner = "top left",
62
- children,
63
- }: PropsWithChildren<TimelineLayoutCornerProps>) {
64
- let className = "";
65
-
66
- switch (corner) {
67
- case "top left":
68
- className = "timeline-layout-corner-top-left";
69
- break;
70
- case "top right":
71
- className = "timeline-layout-corner-top-right";
72
- break;
73
- case "bottom left":
74
- className = "timeline-layout-corner-bottom-left";
75
- break;
76
- case "bottom right":
77
- className = "timeline-layout-corner-bottom-right";
78
- break;
79
- }
80
-
81
- return (
82
- <div className={`timeline-layout-corner ${className}`}>{children}</div>
83
- );
84
- }
85
-
86
- TimelineLayout.Header = TimelineLayoutHeader;
87
- TimelineLayout.Body = TimelineLayoutBody;
88
- TimelineLayout.Background = TimelineLayoutBackground;
89
- TimelineLayout.Footer = TimelineLayoutFooter;
90
- TimelineLayout.Aside = TimelineLayoutAside;
91
- TimelineLayout.Corner = TimelineLayoutCorner;
92
-
93
- export default TimelineLayout;
@@ -1,107 +0,0 @@
1
- .timeline-layout {
2
- position: relative;
3
- width: 100%;
4
- height: 100%;
5
- overflow: auto;
6
-
7
- .timeline-layout-inner {
8
- position: relative;
9
- width: fit-content;
10
- height: fit-content;
11
- display: grid;
12
-
13
- grid-template-areas:
14
- "corner-tl header corner-tr"
15
- "aside-l body aside-r"
16
- "corner-bl footer corner-br";
17
-
18
- .timeline-layout-header,
19
- .timeline-layout-footer,
20
- .timeline-layout-aside,
21
- .timeline-layout-corner {
22
- background: white;
23
- }
24
-
25
- .timeline-layout-header {
26
- grid-area: header;
27
-
28
- position: sticky;
29
- position: -webkit-sticky;
30
- top: 0;
31
- z-index: 101;
32
- overflow: hidden;
33
- }
34
-
35
- .timeline-layout-body {
36
- grid-area: body;
37
- z-index: 100;
38
- }
39
-
40
- .timeline-layout-background {
41
- grid-area: body;
42
- z-index: -1;
43
- }
44
-
45
- .timeline-layout-footer {
46
- grid-area: footer;
47
-
48
- position: sticky;
49
- position: -webkit-sticky;
50
- bottom: 0;
51
- z-index: 101;
52
- border-top: 1px solid lightgray;
53
- }
54
-
55
- .timeline-layout-aside {
56
- grid-area: aside-l;
57
-
58
- position: sticky;
59
- position: -webkit-sticky;
60
- left: 0;
61
- z-index: 101;
62
-
63
- &.timeline-layout-aside-right {
64
- grid-area: aside-r;
65
-
66
- right: 0;
67
- left: initial;
68
- border-left: 1px solid lightgray;
69
- }
70
- }
71
-
72
- .timeline-layout-corner {
73
- position: sticky;
74
- position: -webkit-sticky;
75
- z-index: 102;
76
-
77
- &.timeline-layout-corner-top-left {
78
- grid-area: corner-tl;
79
- top: 0;
80
- left: 0;
81
- border-bottom: 1px solid lightgray;
82
- border-right: 1px solid lightgray;
83
- }
84
- &.timeline-layout-corner-top-right {
85
- grid-area: corner-tr;
86
- top: 0;
87
- right: 0;
88
- border-bottom: 1px solid lightgray;
89
- border-left: 1px solid lightgray;
90
- }
91
- &.timeline-layout-corner-bottom-left {
92
- grid-area: corner-bl;
93
- bottom: 0;
94
- left: 0;
95
- border-top: 1px solid lightgray;
96
- border-right: 1px solid lightgray;
97
- }
98
- &.timeline-layout-corner-bottom-right {
99
- grid-area: corner-br;
100
- bottom: 0;
101
- right: 0;
102
- border-top: 1px solid lightgray;
103
- border-left: 1px solid lightgray;
104
- }
105
- }
106
- }
107
- }