feat: align design with figma

This commit is contained in:
Safwan Samsudeen 2024-04-28 17:01:27 +05:30
parent 0cefc57624
commit 901f78e717
3 changed files with 144 additions and 119 deletions

View File

@ -149,7 +149,7 @@ export default class Bar {
$date_highlight.classList.add('date-highlight') $date_highlight.classList.add('date-highlight')
$date_highlight.style.height = this.height * 0.8 + 'px' $date_highlight.style.height = this.height * 0.8 + 'px'
$date_highlight.style.width = this.width + 'px' $date_highlight.style.width = this.width + 'px'
$date_highlight.style.top = this.gantt.options.header_height - 19 + 'px' $date_highlight.style.top = this.gantt.options.header_height - 24 + 'px'
$date_highlight.style.left = x + 'px' $date_highlight.style.left = x + 'px'
this.$date_highlight = $date_highlight this.$date_highlight = $date_highlight
this.gantt.$lower_header.prepend($date_highlight) this.gantt.$lower_header.prepend($date_highlight)

View File

@ -3,21 +3,27 @@
$bar-color: #fff !default; $bar-color: #fff !default;
$bar-color-important: #94c4f4 !default; $bar-color-important: #94c4f4 !default;
$bar-stroke: #fff !default; $bar-stroke: #fff !default;
$border-color: #e0e0e0 !default; $dark-stroke-color: #e0e0e0 !default;
$stroke-color: #EBEEF0 !default;
$light-bg: #f5f5f5 !default; $light-bg: #f5f5f5 !default;
$light-border-color: #ebeff2 !default; $light-border-color: #ebeff2 !default;
$light-yellow: #f6e796 !default; $light-yellow: #f6e796 !default;
$holiday-color: #f3f4f7 !default; $holiday-color: #F9FAFA !default;
$text-muted: #666 !default; $text-muted: #666 !default;
$text-grey: #98A1A9;
$text-light: #fff !default; $text-light: #fff !default;
$text-dark: #111 !default; $text-dark: #111 !default;
$progress-important: #2c94ec !default; $progress: #EBEEF0 !default;
$progress: #dedfe0 !default;
$handle-color: #dcdce4 !default; $handle-color: #dcdce4 !default;
$handle-color-important: #94c4f4 !default; $handle-color-important: #94c4f4 !default;
$light-blue: #c4c4e9 !default; $light-blue: #c4c4e9 !default;
$middle-blue: #62B2F9 !default;
$dark-blue: #2c94ec !default;
.gantt-container { .gantt-container {
line-height: 14.5px;
.grid-header { .grid-header {
background-color: #ffffff; background-color: #ffffff;
position: sticky; position: sticky;
@ -27,12 +33,20 @@ $light-blue: #c4c4e9 !default;
.lower-text, .lower-text,
.upper-text { .upper-text {
font-size: 14px;
text-anchor: middle; text-anchor: middle;
color: $text-muted; color: $text-dark;
}
.upper-header {
height: 50px;
}
.lower-header {
height: 56px;
} }
.lower-text { .lower-text {
font-size: 14px;
position: absolute; position: absolute;
width: fit-content; width: fit-content;
} }
@ -40,6 +54,8 @@ $light-blue: #c4c4e9 !default;
.upper-text { .upper-text {
position: absolute; position: absolute;
width: fit-content; width: fit-content;
font-weight: 500;
font-size: 16px;
} }
.current-upper { .current-upper {
@ -49,32 +65,51 @@ $light-blue: #c4c4e9 !default;
.side-header { .side-header {
position: fixed; position: fixed;
padding: 0 10px; padding: 0 10px;
margin-right: 10px;
background: white; background: white;
line-height: 20px;
font-weight: 400;
font-size: 13px;
} }
.today-button, .today-button {
.viewmode-select { background: #F4F5F6;
background-color: $text-light; border: none;
border: 1px solid black;
color: $text-dark; color: $text-dark;
padding: 4px 10px; padding: 4px 10px;
font-size: 14px; border-radius: 8px;
border-radius: 5px; float: right;
} }
.viewmode-select { .viewmode-select {
padding: 3px 5px; background: #F4F5F6;
margin-right: 4px; text-align: center;
outline: none !important;
padding: 4px 8px;
border-radius: 6px;
// display: block;
margin-bottom: 4px;
} }
.date-highlight { .date-highlight {
background-color: $text-muted; background-color: $progress;
border-radius: 12px; border-radius: 12px;
z-index: 1;
position: absolute; position: absolute;
opacity: 0.4;
display: none; display: none;
} }
.current-highlight {
position: absolute;
background: $dark-blue;
width: 1px;
}
.current-date-highlight {
background: $dark-blue;
color: $text-light;
padding: 4px;
border-radius: 200px;
}
} }
.gantt { .gantt {
@ -101,38 +136,19 @@ $light-blue: #c4c4e9 !default;
} }
.tick { .tick {
stroke: $border-color; stroke: $stroke-color;
stroke-width: 0.2; stroke-width: 0.2;
&.thick { &.thick {
stroke: #000; stroke: $dark-stroke-color;
stroke-width: 0.5; stroke-width: 0.7;
} }
} }
.today-highlight {
fill: $light-yellow;
opacity: 0.5;
}
.week-highlight {
fill: $light-yellow;
opacity: 0.5;
}
.holiday-highlight { .holiday-highlight {
fill: $holiday-color; fill: $holiday-color;
opacity: 0.5;
}
.month-highlight {
fill: $light-yellow;
opacity: 0.5;
}
.year-highlight {
fill: $light-yellow;
opacity: 0.5;
} }
.arrow { .arrow {
@ -148,14 +164,10 @@ $light-blue: #c4c4e9 !default;
transition: stroke-width 0.3s ease; transition: stroke-width 0.3s ease;
} }
.bar-progress { .bar-progress {
fill: $progress; fill: $progress;
} }
.bar-expected-progress { .bar-expected-progress {
fill: $light-blue; fill: $light-blue;
} }
@ -176,7 +188,7 @@ $light-blue: #c4c4e9 !default;
dominant-baseline: central; dominant-baseline: central;
// text-anchor: middle; // text-anchor: middle;
font-family: Helvetica; font-family: Helvetica;
font-size: 14px; font-size: 13px;
font-weight: 400; font-weight: 400;
&.big { &.big {
@ -191,7 +203,7 @@ $light-blue: #c4c4e9 !default;
} }
.bar-progress { .bar-progress {
fill: $progress-important; fill: $dark-blue;
} }
.bar-label { .bar-label {
@ -257,27 +269,24 @@ $light-blue: #c4c4e9 !default;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
background: rgba(0, 0, 0); background: #171B1F;
padding: 0; padding: 10px;
color: #959da5; border-radius: 5px;
border-radius: 3px;
border: 1px solid rgba(0, 0, 0);
width: max-content; width: max-content;
&.hidden { &.hidden {
opacity: 0 !important; opacity: 0 !important;
} }
.title { .title {
border-bottom: 1px solid $progress; margin-bottom: 5px;
padding: 10px;
text-align: center; text-align: center;
color: $text-light; color: $text-light;
} }
.subtitle { .subtitle {
padding: 10px; color: $text-grey;
color: #dfe2e5;
} }
.pointer { .pointer {

View File

@ -85,7 +85,7 @@ export default class Gantt {
setup_options(options) { setup_options(options) {
const default_options = { const default_options = {
header_height: 50, header_height: 65,
column_width: 30, column_width: 30,
step: 24, step: 24,
view_modes: [...Object.values(VIEW_MODE)], view_modes: [...Object.values(VIEW_MODE)],
@ -340,6 +340,7 @@ export default class Gantt {
this.make_grid(); this.make_grid();
this.make_dates(); this.make_dates();
this.make_bars(); this.make_bars();
this.make_grid_extras();
this.make_arrows(); this.make_arrows();
this.map_arrows_on_bars(); this.map_arrows_on_bars();
this.set_width(); this.set_width();
@ -363,8 +364,11 @@ export default class Gantt {
this.make_grid_background(); this.make_grid_background();
this.make_grid_rows(); this.make_grid_rows();
this.make_grid_header(); this.make_grid_header();
this.make_grid_ticks(); }
make_grid_extras() {
this.make_grid_highlights(); this.make_grid_highlights();
this.make_grid_ticks();
} }
make_grid_background() { make_grid_background() {
@ -391,14 +395,13 @@ export default class Gantt {
make_grid_rows() { make_grid_rows() {
const rows_layer = createSVG("g", { append_to: this.layers.grid }); const rows_layer = createSVG("g", { append_to: this.layers.grid });
const lines_layer = createSVG("g", { append_to: this.layers.grid });
const row_width = this.dates.length * this.options.column_width; const row_width = this.dates.length * this.options.column_width;
const row_height = this.options.bar_height + this.options.padding; const row_height = this.options.bar_height + this.options.padding;
let row_y = this.options.header_height + this.options.padding / 2; let row_y = this.options.header_height + this.options.padding / 2;
for (let task of this.tasks) { for (let _ of this.tasks) {
createSVG("rect", { createSVG("rect", {
x: 0, x: 0,
y: row_y, y: row_y,
@ -408,14 +411,7 @@ export default class Gantt {
append_to: rows_layer, append_to: rows_layer,
}); });
if (this.options.lines === 'both' || this.options.lines === 'horizontal') { if (this.options.lines === 'both' || this.options.lines === 'horizontal') {
createSVG("line", {
x1: 0,
y1: row_y + row_height,
x2: row_width,
y2: row_y + row_height,
class: "row-line",
append_to: lines_layer,
});
} }
row_y += this.options.bar_height + this.options.padding; row_y += this.options.bar_height + this.options.padding;
@ -445,10 +441,13 @@ export default class Gantt {
this.$lower_header = $lower_header this.$lower_header = $lower_header
this.$header.appendChild($lower_header) this.$header.appendChild($lower_header)
this.make_side_header()
}
make_side_header() {
let $side_header = document.createElement('div') let $side_header = document.createElement('div')
$side_header.classList.add('side-header') $side_header.classList.add('side-header')
// Create view mode change select // Create view mode change select
const $select = document.createElement("select"); const $select = document.createElement("select");
$select.classList.add('viewmode-select') $select.classList.add('viewmode-select')
@ -473,19 +472,40 @@ export default class Gantt {
$side_header.appendChild($today_button) $side_header.appendChild($today_button)
this.$header.appendChild($side_header) this.$header.appendChild($side_header)
const { left, y } = $header.getBoundingClientRect(); const { left, y } = this.$header.getBoundingClientRect();
const width = Math.min(this.$header.clientWidth, this.$container.clientWidth) const width = Math.min(this.$header.clientWidth, this.$container.clientWidth)
$side_header.style.left = left + this.$container.scrollLeft + width - $side_header.clientWidth + 'px'; $side_header.style.left = left + this.$container.scrollLeft + width - $side_header.clientWidth + 'px';
$side_header.style.top = y + 5 + 'px'; $side_header.style.top = y + 20 + 'px';
} }
make_grid_ticks() { make_grid_ticks() {
if (this.options.lines !== 'both' && this.options.lines !== 'vertical') return if (!['both', 'vertical', 'horizontal'].includes(this.options.lines)) return
let tick_x = 0; let tick_x = 0;
let tick_y = this.options.header_height + this.options.padding / 2; let tick_y = this.options.header_height + this.options.padding / 2;
let tick_height = let tick_height =
(this.options.bar_height + this.options.padding) * this.tasks.length; (this.options.bar_height + this.options.padding) * this.tasks.length;
let $lines_layer = createSVG("g", { class: 'lines_layer', append_to: this.layers.grid });
let row_y = this.options.header_height + this.options.padding / 2;
const row_width = this.dates.length * this.options.column_width;
const row_height = this.options.bar_height + this.options.padding;
if (this.options.lines !== 'vertical') {
for (let _ of this.tasks) {
createSVG("line", {
x1: 0,
y1: row_y + row_height,
x2: row_width,
y2: row_y + row_height,
class: "row-line",
append_to: $lines_layer,
});
row_y += row_height;
}
}
if (this.options.lines === 'horizontal') return;
for (let date of this.dates) { for (let date of this.dates) {
let tick_class = "tick"; let tick_class = "tick";
// thick tick for monday // thick tick for monday
@ -542,14 +562,16 @@ export default class Gantt {
//compute the horizontal x distance //compute the horizontal x distance
computeGridHighlightDimensions(view_mode) { computeGridHighlightDimensions(view_mode) {
let xDist = 0; let x = this.options.column_width / 2;
if (this.view_is(VIEW_MODE.DAY)) { if (this.view_is(VIEW_MODE.DAY)) {
return ( let today = date_utils.today()
(date_utils.diff(date_utils.today(), this.gantt_start, "hour") / return {
this.options.step) * x: x +
this.options.column_width (date_utils.diff(today, this.gantt_start, "hour") / this.options.step) *
); this.options.column_width,
date: today
}
} }
for (let date of this.dates) { for (let date of this.dates) {
@ -568,12 +590,11 @@ export default class Gantt {
break; break;
} }
if (todayDate >= startDate && todayDate <= endDate) { if (todayDate >= startDate && todayDate <= endDate) {
break; return { x, date: startDate }
} else { } else {
xDist += this.options.column_width; x += this.options.column_width;
} }
} }
return xDist;
} }
make_grid_highlights() { make_grid_highlights() {
@ -585,49 +606,43 @@ export default class Gantt {
this.view_is(VIEW_MODE.MONTH) || this.view_is(VIEW_MODE.MONTH) ||
this.view_is(VIEW_MODE.YEAR) this.view_is(VIEW_MODE.YEAR)
) { ) {
const x = this.computeGridHighlightDimensions(this.options.view_mode); // Used as we must find the _end_ of session if view is not Day
const y = 0; const { x: left, date } = this.computeGridHighlightDimensions(this.options.view_mode)
const width = this.options.column_width; const top = this.options.header_height + this.options.padding / 2;
const height = const height = (this.options.bar_height + this.options.padding) * this.tasks.length;
(this.options.bar_height + this.options.padding) * this.tasks.length + this.create_el({ top, left, height, classes: 'current-highlight', append_to: this.$container })
this.options.header_height + let $today = document.getElementById(date_utils.format(date).replaceAll(' ', '_'))
this.options.padding / 2;
let className = ""; $today.classList.add('current-date-highlight')
switch (this.options.view_mode) { $today.style.top = +$today.style.top.slice(0, -2) - 4 + 'px'
case VIEW_MODE.DAY: $today.style.left = +$today.style.left.slice(0, -2) - 4 + 'px'
className = "today-highlight";
break;
case VIEW_MODE.WEEK:
className = "week-highlight";
break;
case VIEW_MODE.MONTH:
className = "month-highlight";
break;
case VIEW_MODE.YEAR:
className = "year-highlight";
break;
}
createSVG("rect", {
x,
y,
width,
height,
class: className,
append_to: this.layers.grid,
});
} }
} }
create_el({ left, top, width, height, id, classes, append_to }) {
let $el = document.createElement("div");
$el.classList.add(classes)
$el.style.top = top + 'px'
$el.style.left = left + 'px'
if (id) $el.id = id
if (width) $el.style.width = height + 'px'
if (height) $el.style.height = height + 'px'
append_to.appendChild($el)
return $el
}
make_dates() { make_dates() {
this.upper_texts_x = {} this.upper_texts_x = {}
this.get_dates_to_draw().forEach((date, i) => { this.get_dates_to_draw().forEach((date, i) => {
let $lower_text = document.createElement('div'); let $lower_text = this.create_el({
$lower_text.classList.add('lower-text') left: date.lower_x,
top: date.lower_y,
id: date.formatted_date,
classes: 'lower-text',
append_to: this.$lower_header
})
$lower_text.innerText = date.lower_text $lower_text.innerText = date.lower_text
this.$lower_header.appendChild($lower_text) $lower_text.style.left = +$lower_text.style.left.slice(0, -2) - $lower_text.clientWidth / 2 + 'px'
$lower_text.style.left = date.lower_x - (true ? $lower_text.clientWidth / 2 : 0) + 'px'
$lower_text.style.top = date.lower_y + 'px'
if (date.upper_text) { if (date.upper_text) {
this.upper_texts_x[date.upper_text] = date.upper_x this.upper_texts_x[date.upper_text] = date.upper_x
@ -708,8 +723,8 @@ export default class Gantt {
x: last_date_info x: last_date_info
? last_date_info.base_pos_x + last_date_info.column_width ? last_date_info.base_pos_x + last_date_info.column_width
: 0, : 0,
lower_y: this.options.header_height - 15, lower_y: this.options.header_height - 20,
upper_y: this.options.header_height - 40, upper_y: this.options.header_height - 50,
}; };
const x_pos = { const x_pos = {
Hour_lower: column_width / 2, Hour_lower: column_width / 2,
@ -729,6 +744,7 @@ export default class Gantt {
}; };
return { return {
date, date,
formatted_date: date_utils.format(date).replaceAll(' ', '_'),
column_width, column_width,
base_pos_x: base_pos.x, base_pos_x: base_pos.x,
upper_text: date_text[`${this.options.view_mode}_upper`], upper_text: date_text[`${this.options.view_mode}_upper`],
@ -907,13 +923,13 @@ export default class Gantt {
if ($current) { if ($current) {
$current.classList.remove('current-upper') $current.classList.remove('current-upper')
$current.style.left = this.upper_texts_x[$current.textContent] + 'px'; $current.style.left = this.upper_texts_x[$current.textContent] + 'px';
$current.style.top = this.options.header_height - 40 + 'px'; $current.style.top = this.options.header_height - 50 + 'px';
} }
$el.classList.add('current-upper') $el.classList.add('current-upper')
let dimensions = this.$svg.getBoundingClientRect() let dimensions = this.$svg.getBoundingClientRect()
$el.style.left = dimensions.x + this.$container.scrollLeft + 10 + 'px'; $el.style.left = dimensions.x + this.$container.scrollLeft + 10 + 'px';
$el.style.top = dimensions.y + this.options.header_height - 40 + 'px'; $el.style.top = dimensions.y + this.options.header_height - 50 + 'px';
} }
Array.prototype.forEach.call(elements, function (el, i) { Array.prototype.forEach.call(elements, function (el, i) {