sprintify-ui 0.6.8 → 0.6.9

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.
@@ -16,6 +16,10 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
16
16
  type: import("vue").PropType<number>;
17
17
  default: number;
18
18
  };
19
+ includeToday: {
20
+ type: import("vue").PropType<boolean>;
21
+ default: boolean;
22
+ };
19
23
  }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
24
  "item:click": (...args: any[]) => void;
21
25
  "row:click": (...args: any[]) => void;
@@ -36,6 +40,10 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
36
40
  type: import("vue").PropType<number>;
37
41
  default: number;
38
42
  };
43
+ includeToday: {
44
+ type: import("vue").PropType<boolean>;
45
+ default: boolean;
46
+ };
39
47
  }>> & {
40
48
  "onItem:click"?: ((...args: any[]) => any) | undefined;
41
49
  "onRow:click"?: ((...args: any[]) => any) | undefined;
@@ -43,6 +51,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
43
51
  maxHeight: number;
44
52
  rowHeight: number;
45
53
  rowPadding: number;
54
+ includeToday: boolean;
46
55
  }, {}>, {
47
56
  sidebarItem?(_: {
48
57
  row: {
@@ -1,5 +1,5 @@
1
1
  import { DateTime } from "luxon";
2
- import { FormatConfig, GanttItem, GanttItemFormatted, GanttRow, GanttRowFormatted } from "./types";
2
+ import { FormatConfig, GanttItem, GanttItemFormatted, GanttRow, GanttRowFormatted, NowLine } from "./types";
3
3
  export declare class Format {
4
4
  private rows;
5
5
  private config;
@@ -13,6 +13,7 @@ export declare class Format {
13
13
  width: number;
14
14
  groups: import("./types").Group[];
15
15
  ticks: import("./types").Tick[];
16
+ nowLine: NowLine | null;
16
17
  };
17
18
  formatGanttRows(): GanttRowFormatted[];
18
19
  formatGanttRow(row: GanttRow): GanttRowFormatted;
@@ -1,5 +1,5 @@
1
1
  import { DateTime } from "luxon";
2
- import { Group, Tick } from "./types";
2
+ import { Group, Scale, Tick } from "./types";
3
3
  export declare class Timescale {
4
4
  private minWidth;
5
5
  private width;
@@ -9,6 +9,7 @@ export declare class Timescale {
9
9
  private millisecondToPixel;
10
10
  constructor(minWidth: number, min: DateTime, max: DateTime);
11
11
  handle(): {
12
+ scale: Scale;
12
13
  groups: Group[];
13
14
  ticks: Tick[];
14
15
  width: number;
@@ -37,6 +37,7 @@ export interface FormatConfig {
37
37
  minWidth: number;
38
38
  rowHeight: number;
39
39
  rowPadding: number;
40
+ includeToday: boolean;
40
41
  }
41
42
  export interface Tick {
42
43
  date: DateTime;
@@ -65,3 +66,6 @@ export interface Scale {
65
66
  format: string;
66
67
  };
67
68
  }
69
+ export interface NowLine {
70
+ x: number;
71
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprintify-ui",
3
- "version": "0.6.8",
3
+ "version": "0.6.9",
4
4
  "scripts": {
5
5
  "build": "rimraf dist && vue-tsc && vite build",
6
6
  "build-fast": "rimraf dist && vite build",
@@ -7,14 +7,14 @@ import { random } from 'lodash';
7
7
 
8
8
  const rows = [];
9
9
 
10
- for (let i = 0; i < 2; i++) {
10
+ for (let i = 0; i < 10; i++) {
11
11
 
12
12
  const items = [];
13
13
 
14
14
  for (let j = 0; j < 1; j++) {
15
15
 
16
- const start = DateTime.now().plus({ days: i * 1 });
17
- const end = start.plus({ days: 0.5 });
16
+ const start = DateTime.now().minus({ days: 50 }).plus({ days: i * 2 });
17
+ const end = start.plus({ days: 50 });
18
18
 
19
19
  const colors = ['blue', 'green', 'red', 'yellow', 'indigo', 'pink', 'purple', 'gray'];
20
20
 
@@ -114,7 +114,12 @@ const SlotSidebarItemTemplate = (args) => ({
114
114
  Icon,
115
115
  },
116
116
  setup() {
117
- return { args };
117
+
118
+ function onItemClick(item) {
119
+ alert(`Item "${item.name}" clicked`);
120
+ }
121
+
122
+ return { args, onItemClick };
118
123
  },
119
124
  template: `
120
125
  <BaseCard clipped>
@@ -54,7 +54,7 @@
54
54
 
55
55
  <div
56
56
  ref="contentRef"
57
- class="grow flex flex-col relative overflow-hidden"
57
+ class="grow flex flex-col items-stretch relative overflow-hidden"
58
58
  >
59
59
  <!-- Time Scale Header -->
60
60
 
@@ -138,7 +138,7 @@
138
138
 
139
139
  <ul
140
140
  ref="itemsRef"
141
- class="relative overflow-scroll grow"
141
+ class="relative w-full overflow-scroll grow"
142
142
  >
143
143
  <li
144
144
  v-for="row in rowsInternal"
@@ -228,6 +228,35 @@
228
228
  </g>
229
229
  </svg>
230
230
  </div>
231
+
232
+ <!-- Now line -->
233
+
234
+ <div
235
+ v-if="nowLine"
236
+ class="absolute left-0 pointer-events-none"
237
+ :style="{
238
+ top: `${HEADER_HEIGHT}px`,
239
+ width: `${width}px`,
240
+ height: height + 'px',
241
+ transform: `translateX(${scrollX}px)`,
242
+ }"
243
+ >
244
+ <svg
245
+ :view-box="`${width} ${height}`"
246
+ :width="width"
247
+ :height="height"
248
+ >
249
+ <line
250
+ :x1="nowLine.x"
251
+ :x2="nowLine.x"
252
+ y1="0"
253
+ :y2="height"
254
+ stroke="red"
255
+ stroke-width="2"
256
+ style="filter: drop-shadow(0px 0px 2px rgb(0 0 0 / 0.1));"
257
+ ></line>
258
+ </svg>
259
+ </div>
231
260
  </div>
232
261
  </div>
233
262
  </template>
@@ -235,7 +264,7 @@
235
264
  <script lang="ts" setup>
236
265
  import { useElementSize, useScroll } from '@vueuse/core';
237
266
  import { Format } from '@/services/gantt/format';
238
- import { FormatConfig, GanttRow, GanttRowFormatted, Group, Tick } from '@/services/gantt/types';
267
+ import { FormatConfig, GanttRow, GanttRowFormatted, Group, Tick, NowLine } from '@/services/gantt/types';
239
268
  import { debounce } from 'lodash';
240
269
  import { slate } from 'tailwindcss/colors';
241
270
 
@@ -244,10 +273,12 @@ const props = withDefaults(defineProps<{
244
273
  rowHeight?: number,
245
274
  rowPadding?: number,
246
275
  maxHeight?: number,
276
+ includeToday?: boolean,
247
277
  }>(), {
248
278
  rowHeight: 40,
249
279
  rowPadding: 4,
250
280
  maxHeight: undefined,
281
+ includeToday: true,
251
282
  });
252
283
 
253
284
  defineEmits([
@@ -264,6 +295,7 @@ const HEADER_HEIGHT = 40;
264
295
 
265
296
  const contentRef = ref<HTMLDivElement | null>(null);
266
297
  const contentSize = useElementSize(contentRef);
298
+ const itemsRef = ref<HTMLUListElement | null>(null);
267
299
 
268
300
  const width = ref(800);
269
301
  const height = ref(100);
@@ -271,6 +303,7 @@ const height = ref(100);
271
303
  const rowsInternal = ref<GanttRowFormatted[]>([]);
272
304
  const groups = ref<Group[]>([]);
273
305
  const ticks = ref<Tick[]>([]);
306
+ const nowLine = ref<NowLine | null>(null);
274
307
 
275
308
  const config = computed<FormatConfig>(() => {
276
309
  return {
@@ -278,11 +311,11 @@ const config = computed<FormatConfig>(() => {
278
311
  minWidth: contentSize.width.value,
279
312
  rowHeight: props.rowHeight,
280
313
  rowPadding: props.rowPadding,
314
+ includeToday: props.includeToday,
281
315
  };
282
316
  });
283
317
 
284
318
  function init() {
285
-
286
319
  const format = (new Format(config.value)).handle();
287
320
 
288
321
  width.value = format.width;
@@ -292,18 +325,33 @@ function init() {
292
325
 
293
326
  groups.value = format.groups;
294
327
  ticks.value = format.ticks;
328
+
329
+ nowLine.value = format.nowLine;
330
+
331
+ // Scroll to now line
332
+
333
+ nextTick(() => {
334
+ if (nowLine.value && itemsRef.value) {
335
+ const scrollLeft = nowLine.value.x + contentSize.width.value / 2;
336
+ itemsRef.value.scrollLeft = scrollLeft;
337
+ }
338
+ });
295
339
  }
296
340
 
297
341
  // Init triggers
298
342
 
299
343
  const initDebounced = debounce(init, 200);
300
344
 
301
- watch(() => config.value, initDebounced, { deep: true });
345
+ onMounted(() => {
346
+ // Wait for the contentSize to be available
347
+ setTimeout(() => {
348
+ init();
349
+ watch(() => config.value, initDebounced, { deep: true });
350
+ }, 1);
351
+ });
302
352
 
303
353
  // Scroll
304
354
 
305
- const itemsRef = ref<HTMLUListElement | null>(null);
306
-
307
355
  const scrollX = ref(0);
308
356
  const scrollY = ref(0);
309
357
 
@@ -1,6 +1,5 @@
1
1
  import { DateTime } from "luxon";
2
- import { FormatConfig, GanttItem, GanttItemFormatted, GanttRow, GanttRowFormatted } from "./types";
3
- import { minBy } from "lodash";
2
+ import { FormatConfig, GanttItem, GanttItemFormatted, GanttRow, GanttRowFormatted, NowLine } from "./types";
4
3
  import { Timescale } from "./timescale";
5
4
 
6
5
  export class Format {
@@ -47,6 +46,16 @@ export class Format {
47
46
  });
48
47
  });
49
48
 
49
+ const today = DateTime.local().startOf(timescale.scale.tick.step);
50
+
51
+ let nowLine = null;
52
+
53
+ if (today >= min && today <= max) {
54
+ nowLine = {
55
+ x: (today.toMillis() - min.toMillis()) * millisecondToPixel,
56
+ } as NowLine;
57
+ }
58
+
50
59
  return {
51
60
  rows: rowsFormatted,
52
61
  min,
@@ -56,6 +65,7 @@ export class Format {
56
65
  width: timescale.width,
57
66
  groups: timescale.groups,
58
67
  ticks: timescale.ticks,
68
+ nowLine: nowLine,
59
69
  };
60
70
  }
61
71
 
@@ -102,8 +112,18 @@ export class Format {
102
112
  const flatItems = rowsFormatted.flatMap((row) => row.items);
103
113
  const flatDateTimes = flatItems.flatMap((item) => [item.start, item.end]);
104
114
 
105
- const min = minBy(flatDateTimes, (dateTime) => dateTime.toMillis())?.toMillis() || 0;
106
- const max = Math.max(...flatDateTimes.map((dateTime) => dateTime.toMillis()));
115
+
116
+ const flatMillis = flatDateTimes.map((dateTime) => dateTime.toMillis());
117
+
118
+ if (this.config.includeToday) {
119
+ const today = DateTime.local().startOf("day");
120
+
121
+ flatMillis.push(today.plus({ days: 1 }).toMillis());
122
+ flatMillis.push(today.minus({ days: 1 }).toMillis());
123
+ }
124
+
125
+ const min = Math.min(...flatMillis);
126
+ const max = Math.max(...flatMillis);
107
127
 
108
128
  const minDateTime = DateTime.fromMillis(min);
109
129
  const maxDateTime = DateTime.fromMillis(max);
@@ -57,6 +57,7 @@ export class Timescale {
57
57
  // Return
58
58
 
59
59
  return {
60
+ scale: this.scale,
60
61
  groups,
61
62
  ticks,
62
63
  width: this.width,
@@ -42,6 +42,7 @@ export interface FormatConfig {
42
42
  minWidth: number;
43
43
  rowHeight: number;
44
44
  rowPadding: number;
45
+ includeToday: boolean;
45
46
  }
46
47
 
47
48
  export interface Tick {
@@ -72,4 +73,8 @@ export interface Scale {
72
73
  step: DateTimeUnit;
73
74
  format: string;
74
75
  };
75
- }
76
+ }
77
+
78
+ export interface NowLine {
79
+ x: number;
80
+ }