feat: cleaner styling, enable theming

This commit is contained in:
Safwan Samsudeen 2024-12-13 12:23:36 +05:30
parent ba660d53d2
commit 539482e6d9
9 changed files with 212 additions and 201 deletions

View File

@ -23,7 +23,7 @@ export default class Arrow {
}
const start_y =
this.gantt.options.header_height +
this.gantt.config.header_height +
this.gantt.options.bar_height +
(this.gantt.options.padding + this.gantt.options.bar_height) *
this.from_task.task._index +
@ -32,7 +32,7 @@ export default class Arrow {
const end_x =
this.to_task.$bar.getX() - this.gantt.options.padding / 2 - 7;
const end_y =
this.gantt.options.header_height +
this.gantt.config.header_height +
this.gantt.options.bar_height / 2 +
(this.gantt.options.padding + this.gantt.options.bar_height) *
this.to_task.task._index +

View File

@ -159,10 +159,9 @@ export default class Bar {
let $date_highlight = document.createElement('div');
$date_highlight.classList.add('date-highlight');
$date_highlight.classList.add(`highlight-${this.task.id}`);
$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.top =
this.gantt.options.header_height - 25 + 'px';
// $date_highlight.style.top = this.gantt.config.header_height - 25 + 'px';
$date_highlight.style.left = x + 'px';
this.$date_highlight = $date_highlight;
this.gantt.$lower_header.prepend($date_highlight);
@ -596,7 +595,7 @@ export default class Bar {
compute_y() {
this.y =
this.gantt.options.header_height +
this.gantt.config.header_height +
this.gantt.options.padding +
this.task._index * (this.height + this.gantt.options.padding);
}

View File

@ -1,99 +0,0 @@
:root {
--bar-color-dark: #616161;
--bar-stroke-dark: #c6ccd2;
--border-color-dark: #616161;
--light-bg-dark: #3e3e3e;
--light-border-color-dark: #3e3e3e;
--text-muted-dark: #eee;
--text-light-dark: #ececec;
--text-color-dark: #f7f7f7;
--blue-dark: #8a8aff;
}
.dark>.gantt-container .gantt {
& .grid-row {
fill: #252525;
}
/* & .grid-row:nth-child(even) {
fill: var(--light-bg-dark);
} */
& .row-line {
stroke: var(--light-border-color-dark);
}
& .tick {
stroke: var(--border-color-dark);
}
& .holiday-highlight {
fill: var(--light-bg-dark);
}
& .arrow {
stroke: var(--text-muted-dark);
}
& .bar {
fill: var(--bar-color-dark);
stroke: none;
}
& .bar-progress {
fill: var(--blue-dark);
}
& .bar-invalid {
fill: transparent;
stroke: var(--bar-stroke-dark);
&~.bar-label {
fill: var(--text-light-dark);
}
}
& .bar-label.big {
fill: var(--text-light-dark);
}
& .bar-wrapper {
&:hover {
.bar {
fill: lighten(var(--bar-color-dark, 5));
}
& .bar-progress {
fill: lighten(var(--blue-dark, 5));
}
}
&.active {
.bar {
fill: lighten(var(--bar-color-dark, 5));
}
& .bar-progress {
fill: lighten(var(--blue-dark, 5));
}
}
}
}
.dark>.gantt-container {
& .grid-header {
background-color: #252525;
}
& .popup-wrapper {
background-color: #333;
& .title {
border-color: lighten(var(--blue-dark, 5));
}
& .pointer {
border-top-color: #333;
}
}
}

View File

@ -103,8 +103,7 @@ const DEFAULT_OPTIONS = {
column_width: null,
date_format: 'YYYY-MM-DD',
snap_at: null,
infinite_padding: false,
header_height: 65,
infinite_padding: true,
holidays: { '#fff7ed': 'weekend' },
ignore: [],
language: 'en',

View File

@ -7,7 +7,7 @@ import Popup from './popup';
import { DEFAULT_OPTIONS, DEFAULT_VIEW_MODES } from './defaults';
import './gantt.css';
import './styles/gantt.css';
export default class Gantt {
constructor(wrapper, tasks, options) {
@ -75,6 +75,18 @@ export default class Gantt {
this.original_options = options;
this.options = { ...DEFAULT_OPTIONS, ...options };
const CSS_VARIABLES = {
'grid-height': 'container_height',
'bar-height': 'bar_height',
};
for (let name in CSS_VARIABLES) {
this.$container.style.setProperty(
'--gv-' + name,
this.options[CSS_VARIABLES[name]] + 'px',
);
}
this.config = {
ignored_dates: [],
ignored_positions: [],
@ -224,6 +236,11 @@ export default class Gantt {
this.config.unit = scale;
this.config.column_width =
this.options.column_width || mode.column_width || 30;
this.$container.style.setProperty(
'--gv-column-width',
this.config.column_width + 'px',
);
this.config.header_height = this.config.column_width * 2.5;
}
setup_dates() {
@ -357,10 +374,11 @@ export default class Gantt {
make_grid_background() {
const grid_width = this.dates.length * this.config.column_width;
const grid_height =
this.options.header_height +
this.config.header_height +
this.options.padding +
(this.options.bar_height + this.options.padding) *
this.tasks.length;
createSVG('rect', {
x: 0,
y: 0,
@ -382,7 +400,7 @@ export default class Gantt {
const row_width = this.dates.length * this.config.column_width;
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.config.header_height + this.options.padding / 2;
for (let _ of this.tasks) {
createSVG('rect', {
x: 0,
@ -405,7 +423,7 @@ export default class Gantt {
make_grid_header() {
let $header = document.createElement('div');
$header.style.height = this.options.header_height + 10 + 'px';
$header.style.height = this.config.header_height + 'px';
$header.style.width =
this.dates.length * this.config.column_width + 'px';
$header.classList.add('grid-header');
@ -471,7 +489,7 @@ export default class Gantt {
make_grid_ticks() {
if (this.options.lines === 'none') return;
let tick_x = 0;
let tick_y = this.options.header_height + this.options.padding / 2;
let tick_y = this.config.header_height + this.options.padding / 2;
let tick_height =
(this.options.bar_height + this.options.padding) *
this.tasks.length;
@ -481,7 +499,7 @@ export default class Gantt {
append_to: this.layers.grid,
});
let row_y = this.options.header_height + this.options.padding / 2;
let row_y = this.config.header_height + this.options.padding / 2;
const row_width = this.dates.length * this.config.column_width;
const row_height = this.options.bar_height + this.options.padding;
@ -603,9 +621,7 @@ export default class Gantt {
}
let el = createSVG('rect', {
x: Math.round(x),
y:
this.options.header_height +
this.options.padding / 2,
y: this.config.header_height + this.options.padding / 2,
width:
this.config.column_width /
date_utils.convert_scales(
@ -649,26 +665,22 @@ export default class Gantt {
);
this.$current_highlight = this.create_el({
top: this.options.header_height - 20,
top: this.config.header_height - 20,
left,
height,
classes: 'current-highlight',
append_to: this.$extras,
});
let $today = this.$container.querySelector(
'.date_' + date.replaceAll(' ', '_'),
);
if ($today) {
$today.classList.add('current-date-highlight');
$today.style.top = +$today.style.top.slice(0, -2) - 4 + 'px';
}
let $today = this.$container
.querySelector('.date_' + date.replaceAll(' ', '_'))
.classList.add('current-date-highlight');
}
make_grid_highlights() {
this.highlightHolidays();
const top = this.options.header_height + this.options.padding / 2;
const top = this.config.header_height + this.options.padding / 2;
const height =
(this.options.bar_height + this.options.padding) *
this.tasks.length;
@ -676,7 +688,7 @@ export default class Gantt {
<path d="M-1,1 l2,-2
M0,4 l4,-4
M3,5 l2,-2"
style="stroke:black; stroke-width:0.5" />
style="stroke:grey; stroke-width:0.3" />
</pattern>`;
for (
@ -776,9 +788,9 @@ export default class Gantt {
const base_pos = {
x: last_date_info
? last_date_info.base_pos_x + last_date_info.column_width
: 20,
lower_y: this.options.header_height - 20,
upper_y: this.options.header_height - 50,
: 0,
lower_y: this.config.column_width * 1.5,
upper_y: 15,
};
let upper_text = this.config.view_mode.upper_text;
@ -821,7 +833,7 @@ export default class Gantt {
1) /
2,
upper_y: base_pos.upper_y,
lower_x: base_pos.x + column_width / 2 - 20,
lower_x: base_pos.x,
lower_y: base_pos.lower_y,
};
}
@ -867,16 +879,13 @@ export default class Gantt {
}
set_dimensions() {
const { width: cur_width, height } = this.$svg.getBoundingClientRect();
const { width: cur_width } = this.$svg.getBoundingClientRect();
const actual_width = this.$svg.querySelector('.grid .grid-row')
? this.$svg.querySelector('.grid .grid-row').getAttribute('width')
: 0;
if (cur_width < actual_width) {
this.$svg.setAttribute('width', actual_width);
}
this.$container.style.height =
{ auto: height }[this.options.container_height] ||
this.options.container_height + 'px';
}
set_scroll_position(date) {

View File

@ -50,7 +50,7 @@ export default class Popup {
this.parent.classList.remove('hidden');
this.pointer.style.left = this.parent.clientWidth / 2 + 'px';
this.pointer.style.top = '-15px';
this.pointer.style.top = '-10px';
// show
this.parent.style.opacity = 1;

99
src/styles/dark.css Normal file
View File

@ -0,0 +1,99 @@
:root {
--g-bar-stroke-dark: #c6ccd2;
--g-border-color-dark: #616161;
--g-bar-color-dark: #616161;
--g-light-bg-dark: #3e3e3e;
--g-light-border-color-dark: #3e3e3e;
--g-text-muted-dark: #eee;
--g-text-light-dark: #ececec;
--g-text-color-dark: #f7f7f7;
--g-blue-dark: #8a8aff;
}
.dark > .gantt-container .gantt {
& .grid-row {
fill: #252525;
}
& .grid-row:nth-child(even) {
fill: var(--g-light-bg-dark);
}
& .row-line {
stroke: var(--g-light-border-color-dark);
}
& .tick {
stroke: var(--g-border-color-dark);
}
& .holiday-highlight {
fill: var(--g-light-bg-dark);
}
& .arrow {
stroke: var(--g-text-muted-dark);
}
& .bar {
fill: var(--g-bar-color-dark);
stroke: none;
}
& .bar-progress {
fill: var(--g-blue-dark);
}
& .bar-invalid {
fill: transparent;
stroke: var(--g-bar-stroke-dark);
& ~ .bar-label {
fill: var(--g-text-light-dark);
}
}
& .bar-label.big {
fill: var(--g-text-light-dark);
}
& .bar-wrapper {
&:hover {
.bar {
fill: lighten(var(--g-bar-color-dark, 5));
}
& .bar-progress {
fill: lighten(var(--g-blue-dark, 5));
}
}
&.active {
.bar {
fill: lighten(var(--g-bar-color-dark, 5));
}
& .bar-progress {
fill: lighten(var(--g-blue-dark, 5));
}
}
}
}
.dark > .gantt-container {
& .grid-header {
background-color: #252525;
}
& .popup-wrapper {
background-color: #333;
& .title {
border-color: lighten(var(--g-blue-dark, 5));
}
& .pointer {
border-top-color: #333;
}
}
}

View File

@ -1,33 +1,11 @@
@import './dark.css';
:root {
--bar-color: #fff;
--bar-color-important: #94c4f4;
--bar-stroke: #fff;
--dark-stroke-color: #e0e0e0;
--stroke-color: #ebeef0;
--light-bg: #f5f5f5;
--light-border-color: #ebeff2;
--light-yellow: #f6e796;
--holiday-color: #f9fafa;
--text-muted: #7c7c7c;
--text-grey: #98a1a9;
--text-light: #fff;
--text-dark: #171717;
--progress: #ebeef0;
--handle-color: #dcdce4;
--handle-color-important: #94c4f4;
--light-blue: #c4c4e9;
--middle-blue: #62b2f9;
--dark-blue: #2c94ec;
}
@import './light.css';
.gantt-container {
line-height: 14.5px;
position: relative;
overflow: auto;
font-size: 12px;
height: 300px;
height: var(--gv-grid-height);
& .popup-wrapper {
position: absolute;
@ -46,24 +24,23 @@
margin-bottom: 5px;
text-align: -webkit-center;
text-align: center;
color: var(--text-light);
color: var(--g-text-light);
}
& .subtitle {
color: var(--text-grey);
color: var(--g-text-secondary);
}
& .pointer {
position: absolute;
height: 5px;
margin: 0 0 0 -5px;
border: 5px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.8);
}
}
& .grid-header {
background-color: #ffffff;
background-color: var(--g-header-background);
position: sticky;
top: 0;
left: 0;
@ -76,19 +53,22 @@
}
& .upper-header {
height: 40px;
height: calc(var(--gv-column-width) * 1.5);
}
& .lower-header {
height: 30px;
height: var(--gv-column-width);
}
& .lower-text {
font-size: 14px;
font-size: 12px;
position: absolute;
width: fit-content;
transform: translateX(-50%);
color: var(--text-muted);
width: calc(var(--gv-column-width) * 0.8);
height: calc(var(--gv-column-width) * 0.8);
margin: 0 calc(var(--gv-column-width) * 0.1);
align-content: center;
text-align: center;
color: var(--g-text-muted);
}
& .upper-text {
@ -96,12 +76,12 @@
width: fit-content;
font-weight: 500;
font-size: 16px;
color: var(--text-dark);
color: var(--g-text-dark);
}
& .current-upper {
position: sticky;
left: 2px !important;
left: 0 !important;
padding: 0 10px;
height: 20px;
background: white;
@ -121,14 +101,14 @@
}
& .side-header * {
background: #f4f5f6;
background: var(--g-actions-background);
text-align: -webkit-center;
text-align: center;
height: 30px;
border-radius: 0;
border: 1px dotted grey;
border-right: none;
color: var(--text-dark);
color: var(--g-text-dark);
padding: 4px 10px;
position: sticky;
float: right;
@ -147,24 +127,25 @@
}
& .date-highlight {
background-color: var(--progress);
background-color: var(--g-progress-color);
border-radius: 12px;
height: calc(var(--gv-bar-height) * 0.8);
top: calc(var(--gv-column-width) * 1.5);
position: absolute;
display: none;
}
& .current-highlight {
position: absolute;
background: var(--dark-blue);
background: var(--g-blue-dark);
width: 1px;
z-index: 999;
}
& .current-date-highlight {
background: var(--dark-blue);
color: var(--text-light);
padding: 4px 8px;
border-radius: 5px;
background: var(--g-blue-dark);
color: var(--g-text-light);
border-radius: 100px;
}
& .holiday-label {
@ -173,7 +154,7 @@
left: 0;
opacity: 0;
z-index: 1000;
background: #dcdce4;
background: --g-holiday-label-color;
border-radius: 5px;
padding: 2px 5px;
@ -193,96 +174,96 @@
}
& .grid-row {
fill: #ffffff;
fill: var(--g-row-color);
}
& .row-line {
stroke: var(--light-border-color);
stroke: var(--g-border-color);
}
& .tick {
stroke: var(--stroke-color);
stroke: var(--g-tick-color);
stroke-width: 0.4;
&.thick {
stroke: var(--dark-stroke-color);
stroke: var(--g-tick-color-thick);
stroke-width: 0.7;
}
}
& .arrow {
fill: none;
stroke: #9fa9b1;
stroke: var(--arrow-color);
stroke-width: 1;
}
& .bar-wrapper .bar {
fill: var(--bar-color);
stroke: var(--bar-stroke);
fill: var(--g-bar-color);
stroke: var(--g-bar-border);
stroke-width: 0;
transition: stroke-width 0.3s ease;
}
& .bar-progress {
fill: var(--progress);
fill: var(--g-progress-color);
}
& .bar-expected-progress {
fill: var(--light-blue);
fill: var(--g-blue-light);
}
& .bar-invalid {
fill: transparent;
stroke: var(--bar-stroke);
stroke: var(--g-bar-border);
stroke-width: 1;
stroke-dasharray: 5;
& ~ .bar-label {
fill: var(--text-light);
fill: var(--g-text-light);
}
}
& .bar-label {
fill: var(--text-dark);
fill: var(--g-text-dark);
dominant-baseline: central;
font-family: Helvetica;
font-size: 13px;
font-weight: 400;
&.big {
fill: var(--text-dark);
fill: var(--g-text-dark);
text-anchor: start;
}
}
& .bar-wrapper.important {
& .bar {
fill: var(--bar-color-important);
fill: var(--g-bar-color-important);
}
& .bar-progress {
fill: var(--dark-blue);
fill: var(--g-blue-dark);
}
& .bar-label {
fill: var(--text-light);
fill: var(--g-text-light);
&.big {
fill: var(--text-dark);
fill: var(--g-text-dark);
}
}
& .handle {
fill: var(--handle-color-important);
fill: var(--g-handle-color-important);
}
& .handle.progress {
fill: var(--text-light);
fill: var(--g-text-light);
}
}
& .handle {
fill: var(--handle-color);
fill: var(--g-handle-color);
cursor: ew-resize;
opacity: 0;
visibility: hidden;
@ -290,7 +271,7 @@
}
& .handle.progress {
fill: var(--text-muted);
fill: var(--g-text-muted);
}
& .bar-wrapper {

23
src/styles/light.css Normal file
View File

@ -0,0 +1,23 @@
:root {
--g-arrow-color: #9fa9b1;
--g-bar-color: #fff;
--g-bar-color-important: #94c4f4;
--g-bar-border: #fff;
--g-tick-color-thick: #e0e0e0;
--g-tick-color: #ebeef0;
--g-light-bg: #f5f5f5;
--g-actions-background: #f4f5f6;
--g-border-color: #ebeff2;
--g-text-muted: #7c7c7c;
--g-text-light: #fff;
--g-text-secondary: #98a1a9;
--g-text-dark: #171717;
--g-progress-color: #ebeef0;
--g-handle-color: #dcdce4;
--g-handle-color-important: #94c4f4;
--g-holiday-label-color: #dcdce4;
--g-blue-light: #c4c4e9;
--g-blue-dark: #2c94ec;
--g-header-background: #ffffff;
--g-row-color: #fff;
}