Merge pull request #394 from safwansamsudeen/master
Tooling and Bug Fixes
This commit is contained in:
commit
22ff6e202e
30
.github/workflows/publish.yml
vendored
30
.github/workflows/publish.yml
vendored
@ -1,19 +1,19 @@
|
|||||||
name: Publish on NPM
|
name: Publish on NPM
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- uses: actions/setup-node@v1
|
- uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14
|
node-version: 14
|
||||||
- run: yarn install
|
- run: yarn install
|
||||||
- run: yarn prettier-check
|
- run: yarn prettier-check
|
||||||
- run: yarn test
|
- run: yarn test
|
||||||
- uses: JS-DevTools/npm-publish@v1
|
- uses: JS-DevTools/npm-publish@v1
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.NPM_TOKEN }}
|
token: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,6 +25,7 @@ build/Release
|
|||||||
# Dependency directory
|
# Dependency directory
|
||||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||||
node_modules
|
node_modules
|
||||||
|
.yarn
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"singleQuote": true
|
"singleQuote": true
|
||||||
}
|
}
|
||||||
|
|||||||
1
.yarnrc.yml
Normal file
1
.yarnrc.yml
Normal file
@ -0,0 +1 @@
|
|||||||
|
nodeLinker: node-modules
|
||||||
50
README.md
50
README.md
@ -51,19 +51,19 @@ var gantt = new Gantt("#gantt", tasks);
|
|||||||
You can also pass various options to the Gantt constructor:
|
You can also pass various options to the Gantt constructor:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var gantt = new Gantt("#gantt", tasks, {
|
var gantt = new Gantt('#gantt', tasks, {
|
||||||
header_height: 50,
|
header_height: 50,
|
||||||
column_width: 30,
|
column_width: 30,
|
||||||
step: 24,
|
step: 24,
|
||||||
view_modes: ["Quarter Day", "Half Day", "Day", "Week", "Month"],
|
view_modes: ['Quarter Day', 'Half Day', 'Day', 'Week', 'Month'],
|
||||||
bar_height: 20,
|
bar_height: 20,
|
||||||
bar_corner_radius: 3,
|
bar_corner_radius: 3,
|
||||||
arrow_curve: 5,
|
arrow_curve: 5,
|
||||||
padding: 18,
|
padding: 18,
|
||||||
view_mode: "Day",
|
view_mode: 'Day',
|
||||||
date_format: "YYYY-MM-DD",
|
date_format: 'YYYY-MM-DD',
|
||||||
language: "en", // or 'es', 'it', 'ru', 'ptBr', 'fr', 'tr', 'zh', 'de', 'hu'
|
language: 'en', // or 'es', 'it', 'ru', 'ptBr', 'fr', 'tr', 'zh', 'de', 'hu'
|
||||||
custom_popup_html: null,
|
custom_popup_html: null,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -91,25 +91,25 @@ Assuming the last commit (or a couple of commits) were enhancements or fixes,
|
|||||||
|
|
||||||
1. Run `yarn build`
|
1. Run `yarn build`
|
||||||
|
|
||||||
This will generate files in the `dist/` folder. These files need to be committed.
|
This will generate files in the `dist/` folder. These files need to be committed.
|
||||||
|
|
||||||
1. Run `yarn publish`
|
1. Run `yarn publish`
|
||||||
1. Type the new version at the prompt
|
1. Type the new version at the prompt
|
||||||
|
|
||||||
Depending on the type of change, you can either bump the patch version or the minor version.
|
Depending on the type of change, you can either bump the patch version or the minor version.
|
||||||
For e.g.,
|
For e.g.,
|
||||||
|
|
||||||
```
|
```
|
||||||
0.5.0 -> 0.6.0 (minor version bump)
|
0.5.0 -> 0.6.0 (minor version bump)
|
||||||
0.5.0 -> 0.5.1 (patch version bump)
|
0.5.0 -> 0.5.1 (patch version bump)
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Now, there will be a commit named after the version you just entered. Include the generated files in `dist/` folder as part of this commit by running the command:
|
1. Now, there will be a commit named after the version you just entered. Include the generated files in `dist/` folder as part of this commit by running the command:
|
||||||
```
|
```
|
||||||
git add dist
|
git add dist
|
||||||
git commit --amend
|
git commit --amend
|
||||||
git push origin master
|
git push origin master
|
||||||
```
|
```
|
||||||
|
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
|
|||||||
295
dist/frappe-gantt.css
vendored
295
dist/frappe-gantt.css
vendored
@ -1,295 +0,0 @@
|
|||||||
.dark > .gantt-container .gantt .grid-header {
|
|
||||||
fill: #252525;
|
|
||||||
stroke: #616161;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .grid-row {
|
|
||||||
fill: #252525;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .grid-row:nth-child(even) {
|
|
||||||
fill: #3e3e3e;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .row-line {
|
|
||||||
stroke: #3e3e3e;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .tick {
|
|
||||||
stroke: #616161;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .today-highlight {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .arrow {
|
|
||||||
stroke: #eee;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar {
|
|
||||||
fill: #616161;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar-progress {
|
|
||||||
fill: #8a8aff;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar-invalid {
|
|
||||||
fill: transparent;
|
|
||||||
stroke: #c6ccd2;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar-invalid ~ .bar-label {
|
|
||||||
fill: #ececec;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar-label.big {
|
|
||||||
fill: #ececec;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar-wrapper:hover .bar {
|
|
||||||
fill: #6e6e6e;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar-wrapper:hover .bar-progress {
|
|
||||||
fill: #a4a4ff;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar-wrapper.active .bar {
|
|
||||||
fill: #6e6e6e;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .bar-wrapper.active .bar-progress {
|
|
||||||
fill: #a4a4ff;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .upper-text {
|
|
||||||
fill: #a2a2a2;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .gantt .lower-text {
|
|
||||||
fill: #f7f7f7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark > .gantt-container .popup-wrapper {
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .popup-wrapper .title {
|
|
||||||
border-color: #a4a4ff;
|
|
||||||
}
|
|
||||||
.dark > .gantt-container .popup-wrapper .pointer {
|
|
||||||
border-top-color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gantt-container {
|
|
||||||
line-height: 14.5px;
|
|
||||||
}
|
|
||||||
.gantt-container .grid-header {
|
|
||||||
background-color: #ffffff;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
.gantt-container .lower-text,
|
|
||||||
.gantt-container .upper-text {
|
|
||||||
text-anchor: middle;
|
|
||||||
color: #111;
|
|
||||||
}
|
|
||||||
.gantt-container .upper-header {
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
.gantt-container .lower-header {
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
.gantt-container .lower-text {
|
|
||||||
font-size: 14px;
|
|
||||||
position: absolute;
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
.gantt-container .upper-text {
|
|
||||||
position: absolute;
|
|
||||||
width: fit-content;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.gantt-container .current-upper {
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
.gantt-container .side-header {
|
|
||||||
position: fixed;
|
|
||||||
padding: 0 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
background: white;
|
|
||||||
line-height: 20px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
.gantt-container .today-button,
|
|
||||||
.gantt-container .viewmode-select {
|
|
||||||
background: #F4F5F6;
|
|
||||||
text-align: -webkit-center;
|
|
||||||
text-align: center;
|
|
||||||
height: 25px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: none;
|
|
||||||
color: #111;
|
|
||||||
padding: 4px 10px;
|
|
||||||
border-radius: 8px;
|
|
||||||
height: 25px;
|
|
||||||
}
|
|
||||||
.gantt-container .viewmode-select {
|
|
||||||
outline: none !important;
|
|
||||||
padding: 4px 8px;
|
|
||||||
margin-right: 4px;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
text-indent: 1px;
|
|
||||||
text-overflow: "";
|
|
||||||
}
|
|
||||||
.gantt-container .date-highlight {
|
|
||||||
background-color: #EBEEF0;
|
|
||||||
border-radius: 12px;
|
|
||||||
position: absolute;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.gantt-container .current-highlight {
|
|
||||||
position: absolute;
|
|
||||||
background: #2c94ec;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
.gantt-container .current-date-highlight {
|
|
||||||
background: #2c94ec;
|
|
||||||
color: #fff;
|
|
||||||
padding: 4px 8px;
|
|
||||||
border-radius: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gantt {
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.gantt .grid-background {
|
|
||||||
fill: none;
|
|
||||||
}
|
|
||||||
.gantt .grid-row {
|
|
||||||
fill: #ffffff;
|
|
||||||
}
|
|
||||||
.gantt .row-line {
|
|
||||||
stroke: #ebeff2;
|
|
||||||
}
|
|
||||||
.gantt .tick {
|
|
||||||
stroke: #EBEEF0;
|
|
||||||
stroke-width: 0.4;
|
|
||||||
}
|
|
||||||
.gantt .tick.thick {
|
|
||||||
stroke: #e0e0e0;
|
|
||||||
stroke-width: 0.7;
|
|
||||||
}
|
|
||||||
.gantt .holiday-highlight {
|
|
||||||
fill: #F9FAFA;
|
|
||||||
}
|
|
||||||
.gantt .arrow {
|
|
||||||
fill: none;
|
|
||||||
stroke: #9FA9B1;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper .bar {
|
|
||||||
fill: #fff;
|
|
||||||
stroke: #fff;
|
|
||||||
stroke-width: 0;
|
|
||||||
transition: stroke-width 0.3s ease;
|
|
||||||
}
|
|
||||||
.gantt .bar-progress {
|
|
||||||
fill: #EBEEF0;
|
|
||||||
}
|
|
||||||
.gantt .bar-expected-progress {
|
|
||||||
fill: #c4c4e9;
|
|
||||||
}
|
|
||||||
.gantt .bar-invalid {
|
|
||||||
fill: transparent;
|
|
||||||
stroke: #fff;
|
|
||||||
stroke-width: 1;
|
|
||||||
stroke-dasharray: 5;
|
|
||||||
}
|
|
||||||
.gantt .bar-invalid ~ .bar-label {
|
|
||||||
fill: #fff;
|
|
||||||
}
|
|
||||||
.gantt .bar-label {
|
|
||||||
fill: #111;
|
|
||||||
dominant-baseline: central;
|
|
||||||
font-family: Helvetica;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
.gantt .bar-label.big {
|
|
||||||
fill: #111;
|
|
||||||
text-anchor: start;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper.important .bar {
|
|
||||||
fill: #94c4f4;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper.important .bar-progress {
|
|
||||||
fill: #2c94ec;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper.important .bar-label {
|
|
||||||
fill: #fff;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper.important .handle {
|
|
||||||
fill: #94c4f4;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper.important .handle.progress {
|
|
||||||
fill: #fff;
|
|
||||||
}
|
|
||||||
.gantt .handle {
|
|
||||||
fill: #dcdce4;
|
|
||||||
cursor: ew-resize;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
.gantt .handle.progress {
|
|
||||||
fill: #666;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper {
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper.active .handle {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper .bar {
|
|
||||||
-webkit-filter: drop-shadow(3px 3px 2px rgba(0, 0, 0, 0.7));
|
|
||||||
filter: drop-shadow(0 0 2px rgba(17, 43, 66, 0.16));
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper:hover .bar {
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
}
|
|
||||||
.gantt .bar-wrapper:hover .date-highlight {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.gantt .hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gantt-container {
|
|
||||||
position: relative;
|
|
||||||
overflow: auto;
|
|
||||||
font-size: 12px;
|
|
||||||
height: 500px;
|
|
||||||
}
|
|
||||||
.gantt-container .popup-wrapper {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
background: #171B1F;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
width: max-content;
|
|
||||||
}
|
|
||||||
.gantt-container .popup-wrapper.hidden {
|
|
||||||
opacity: 0 !important;
|
|
||||||
}
|
|
||||||
.gantt-container .popup-wrapper .title {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
text-align: -webkit-center;
|
|
||||||
text-align: center;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.gantt-container .popup-wrapper .subtitle {
|
|
||||||
color: #98A1A9;
|
|
||||||
}
|
|
||||||
.gantt-container .popup-wrapper .pointer {
|
|
||||||
position: absolute;
|
|
||||||
height: 5px;
|
|
||||||
margin: 0 0 0 -5px;
|
|
||||||
border: 5px solid transparent;
|
|
||||||
border-bottom-color: rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
3516
dist/frappe-gantt.js
vendored
3516
dist/frappe-gantt.js
vendored
File diff suppressed because it is too large
Load Diff
1
dist/frappe-gantt.js.map
vendored
1
dist/frappe-gantt.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/frappe-gantt.min.css
vendored
1
dist/frappe-gantt.min.css
vendored
@ -1 +0,0 @@
|
|||||||
.dark>.gantt-container .gantt .grid-header{fill:#252525;stroke:#616161}.dark>.gantt-container .gantt .grid-row{fill:#252525}.dark>.gantt-container .gantt .grid-row:nth-child(even){fill:#3e3e3e}.dark>.gantt-container .gantt .row-line{stroke:#3e3e3e}.dark>.gantt-container .gantt .tick{stroke:#616161}.dark>.gantt-container .gantt .today-highlight{opacity:.2}.dark>.gantt-container .gantt .arrow{stroke:#eee}.dark>.gantt-container .gantt .bar{fill:#616161;stroke:none}.dark>.gantt-container .gantt .bar-progress{fill:#8a8aff}.dark>.gantt-container .gantt .bar-invalid{fill:rgba(0,0,0,0);stroke:#c6ccd2}.dark>.gantt-container .gantt .bar-invalid~.bar-label{fill:#ececec}.dark>.gantt-container .gantt .bar-label.big{fill:#ececec}.dark>.gantt-container .gantt .bar-wrapper:hover .bar{fill:#6e6e6e}.dark>.gantt-container .gantt .bar-wrapper:hover .bar-progress{fill:#a4a4ff}.dark>.gantt-container .gantt .bar-wrapper.active .bar{fill:#6e6e6e}.dark>.gantt-container .gantt .bar-wrapper.active .bar-progress{fill:#a4a4ff}.dark>.gantt-container .gantt .upper-text{fill:#a2a2a2}.dark>.gantt-container .gantt .lower-text{fill:#f7f7f7}.dark>.gantt-container .popup-wrapper{background-color:#333}.dark>.gantt-container .popup-wrapper .title{border-color:#a4a4ff}.dark>.gantt-container .popup-wrapper .pointer{border-top-color:#333}.gantt-container{line-height:14.5px}.gantt-container .grid-header{background-color:#fff;position:sticky;top:0;left:0;z-index:10}.gantt-container .lower-text,.gantt-container .upper-text{text-anchor:middle;color:#111}.gantt-container .upper-header{height:40px}.gantt-container .lower-header{height:30px}.gantt-container .lower-text{font-size:14px;position:absolute;width:fit-content}.gantt-container .upper-text{position:absolute;width:fit-content;font-weight:500;font-size:16px}.gantt-container .current-upper{position:fixed}.gantt-container .side-header{position:fixed;padding:0 10px;margin-right:10px;background:#fff;line-height:20px;font-weight:400}.gantt-container .today-button,.gantt-container .viewmode-select{background:#f4f5f6;text-align:-webkit-center;text-align:center;height:25px;border-radius:8px;border:none;color:#111;padding:4px 10px;border-radius:8px;height:25px}.gantt-container .viewmode-select{outline:none !important;padding:4px 8px;margin-right:4px;-webkit-appearance:none;-moz-appearance:none;text-indent:1px;text-overflow:""}.gantt-container .date-highlight{background-color:#ebeef0;border-radius:12px;position:absolute;display:none}.gantt-container .current-highlight{position:absolute;background:#2c94ec;width:1px}.gantt-container .current-date-highlight{background:#2c94ec;color:#fff;padding:4px 8px;border-radius:200px}.gantt{user-select:none;-webkit-user-select:none;position:absolute}.gantt .grid-background{fill:none}.gantt .grid-row{fill:#fff}.gantt .row-line{stroke:#ebeff2}.gantt .tick{stroke:#ebeef0;stroke-width:.4}.gantt .tick.thick{stroke:#e0e0e0;stroke-width:.7}.gantt .holiday-highlight{fill:#f9fafa}.gantt .arrow{fill:none;stroke:#9fa9b1;stroke-width:1}.gantt .bar-wrapper .bar{fill:#fff;stroke:#fff;stroke-width:0;transition:stroke-width .3s ease}.gantt .bar-progress{fill:#ebeef0}.gantt .bar-expected-progress{fill:#c4c4e9}.gantt .bar-invalid{fill:rgba(0,0,0,0);stroke:#fff;stroke-width:1;stroke-dasharray:5}.gantt .bar-invalid~.bar-label{fill:#fff}.gantt .bar-label{fill:#111;dominant-baseline:central;font-family:Helvetica;font-size:13px;font-weight:400}.gantt .bar-label.big{fill:#111;text-anchor:start}.gantt .bar-wrapper.important .bar{fill:#94c4f4}.gantt .bar-wrapper.important .bar-progress{fill:#2c94ec}.gantt .bar-wrapper.important .bar-label{fill:#fff}.gantt .bar-wrapper.important .handle{fill:#94c4f4}.gantt .bar-wrapper.important .handle.progress{fill:#fff}.gantt .handle{fill:#dcdce4;cursor:ew-resize;opacity:0;visibility:hidden;transition:opacity .3s ease}.gantt .handle.progress{fill:#666}.gantt .bar-wrapper{cursor:pointer;outline:none}.gantt .bar-wrapper.active .handle{visibility:visible;opacity:1}.gantt .bar-wrapper .bar{-webkit-filter:drop-shadow(3px 3px 2px rgba(0, 0, 0, 0.7));filter:drop-shadow(0 0 2px rgba(17, 43, 66, 0.16));border-radius:3px}.gantt .bar-wrapper:hover .bar{transition:transform .3s ease}.gantt .bar-wrapper:hover .date-highlight{display:block}.gantt .hide{display:none}.gantt-container{position:relative;overflow:auto;font-size:12px;height:500px}.gantt-container .popup-wrapper{position:absolute;top:0;left:0;background:#171b1f;padding:10px;border-radius:5px;width:max-content}.gantt-container .popup-wrapper.hidden{opacity:0 !important}.gantt-container .popup-wrapper .title{margin-bottom:5px;text-align:-webkit-center;text-align:center;color:#fff}.gantt-container .popup-wrapper .subtitle{color:#98a1a9}.gantt-container .popup-wrapper .pointer{position:absolute;height:5px;margin:0 0 0 -5px;border:5px solid rgba(0,0,0,0);border-bottom-color:rgba(0,0,0,.8)}
|
|
||||||
2
dist/frappe-gantt.min.js
vendored
2
dist/frappe-gantt.min.js
vendored
File diff suppressed because one or more lines are too long
1
dist/frappe-gantt.min.js.map
vendored
1
dist/frappe-gantt.min.js.map
vendored
File diff suppressed because one or more lines are too long
23
dist/frappe-gantt.umd.cjs
vendored
Normal file
23
dist/frappe-gantt.umd.cjs
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/style.css
vendored
Normal file
1
dist/style.css
vendored
Normal file
File diff suppressed because one or more lines are too long
262
index.html
262
index.html
@ -1,130 +1,140 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>Simple Gantt</title>
|
<title>Simple Gantt</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
background: #ccc;
|
background: #ccc;
|
||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
/* custom class */
|
/* custom class */
|
||||||
.gantt .bar-milestone .bar {
|
.gantt .bar-milestone .bar {
|
||||||
fill: tomato;
|
fill: tomato;
|
||||||
}
|
}
|
||||||
.heading {
|
.heading {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.gantt-target.dark {
|
.gantt-target.dark {
|
||||||
background-color: #252525;
|
background-color: #252525;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="dist/frappe-gantt.css" />
|
<link rel="stylesheet" href="dist/style.css" />
|
||||||
<script src="dist/frappe-gantt.js"></script>
|
<script src="dist/frappe-gantt.umd.cjs"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="heading">Interactive Gantt Chart entirely made in SVG!</h2>
|
<h2 class="heading">
|
||||||
<div class="gantt-target"></div>
|
Interactive Gantt Chart entirely made in SVG!
|
||||||
</div>
|
</h2>
|
||||||
<script>
|
<div class="gantt-target"></div>
|
||||||
let tasks = [
|
</div>
|
||||||
{
|
<script type="module">
|
||||||
start: '2024-04-01',
|
// import Gantt from "./dist/frappe-gantt.js";
|
||||||
end: '2024-04-01',
|
|
||||||
name: 'Redesign website',
|
|
||||||
id: "Task 0",
|
|
||||||
progress: 30
|
|
||||||
},
|
|
||||||
{
|
|
||||||
start: '2024-03-26',
|
|
||||||
// Utilizes duration
|
|
||||||
duration: '6d',
|
|
||||||
name: 'Write new content',
|
|
||||||
id: "Task 1",
|
|
||||||
progress: 5,
|
|
||||||
important: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
start: '2024-04-04',
|
|
||||||
end: '2024-04-08',
|
|
||||||
name: 'Apply new styles',
|
|
||||||
id: "Task 2",
|
|
||||||
progress: 80,
|
|
||||||
dependencies: 'Task 1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
start: '2024-04-08',
|
|
||||||
end: '2024-04-09',
|
|
||||||
name: 'Review',
|
|
||||||
id: "Task 3",
|
|
||||||
progress: 5,
|
|
||||||
dependencies: 'Task 2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
start: '2024-04-08',
|
|
||||||
end: '2024-04-10',
|
|
||||||
name: 'Deploy',
|
|
||||||
id: "Task 4",
|
|
||||||
progress: 0,
|
|
||||||
// dependencies: 'Task 2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
start: '2024-04-21',
|
|
||||||
end: '2024-04-29',
|
|
||||||
name: 'Go Live!',
|
|
||||||
id: "Task 5",
|
|
||||||
progress: 0,
|
|
||||||
dependencies: 'Task 2',
|
|
||||||
custom_class: 'bar-milestone'
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// start: '2014-01-05',
|
|
||||||
// end: '2019-10-12',
|
|
||||||
// name: 'Long term task',
|
|
||||||
// id: "Task 6",
|
|
||||||
// progress: 0
|
|
||||||
// }
|
|
||||||
];
|
|
||||||
|
|
||||||
// Uncomment to test fixed header
|
let tasks = [
|
||||||
tasks = [...tasks, ...Array.from({length: tasks.length * 3}, (_, i) => ({...tasks[i % 3], id: i}))]
|
{
|
||||||
|
start: '2024-04-01',
|
||||||
let gantt_chart = new Gantt(".gantt-target", tasks, {
|
end: '2024-04-01',
|
||||||
on_click: (task) => {
|
name: 'Redesign website',
|
||||||
console.log("Click", task);
|
id: 'Task 0',
|
||||||
},
|
progress: 30,
|
||||||
// on_double_click: (task) => {
|
},
|
||||||
// console.log("Double Click", task);
|
{
|
||||||
// },
|
start: '2024-03-26',
|
||||||
// on_date_change: (task, start, end) => {
|
// Utilizes duration
|
||||||
// console.log("Date change", task, start, end);
|
duration: '6d',
|
||||||
// },
|
name: 'Write new content',
|
||||||
// on_progress_change: (task, progress) => {
|
id: 'Task 1',
|
||||||
// console.log("Progress Change", task, progress);
|
progress: 5,
|
||||||
// },
|
important: true,
|
||||||
// on_view_change: (mode) => {
|
},
|
||||||
// console.log("View Change", mode);
|
{
|
||||||
// },
|
start: '2024-04-04',
|
||||||
// on_hover: (task, x, y) => {
|
end: '2024-04-08',
|
||||||
// console.log("Hover", x, y);
|
name: 'Apply new styles',
|
||||||
// },
|
id: 'Task 2',
|
||||||
view_mode: "Day",
|
progress: 80,
|
||||||
view_mode_padding: { DAY: "3d" },
|
dependencies: 'Task 1',
|
||||||
popup: false,
|
},
|
||||||
// scroll_to: 'today',
|
{
|
||||||
// view_mode_select: true,
|
start: '2024-04-08',
|
||||||
// today_button: false,
|
end: '2024-04-09',
|
||||||
// readonly: true,
|
name: 'Review',
|
||||||
// lines: 'vertical',
|
id: 'Task 3',
|
||||||
// lower_text: (date) => date.getDay(),
|
progress: 5,
|
||||||
// upper_text: (date, view_mode, def) => def,
|
dependencies: 'Task 2',
|
||||||
});
|
},
|
||||||
console.log(gantt_chart);
|
{
|
||||||
</script>
|
start: '2024-04-08',
|
||||||
</body>
|
end: '2024-04-10',
|
||||||
|
name: 'Deploy',
|
||||||
|
id: 'Task 4',
|
||||||
|
progress: 0,
|
||||||
|
// dependencies: 'Task 2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
start: '2024-04-21',
|
||||||
|
end: '2024-04-29',
|
||||||
|
name: 'Go Live!',
|
||||||
|
id: 'Task 5',
|
||||||
|
progress: 0,
|
||||||
|
dependencies: 'Task 2',
|
||||||
|
custom_class: 'bar-milestone',
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// start: '2014-01-05',
|
||||||
|
// end: '2019-10-12',
|
||||||
|
// name: 'Long term task',
|
||||||
|
// id: "Task 6",
|
||||||
|
// progress: 0
|
||||||
|
// }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Uncomment to test fixed header
|
||||||
|
// tasks = [
|
||||||
|
// ...tasks,
|
||||||
|
// ...Array.from({ length: tasks.length * 3 }, (_, i) => ({
|
||||||
|
// ...tasks[i % 3],
|
||||||
|
// id: i,
|
||||||
|
// })),
|
||||||
|
// ];
|
||||||
|
|
||||||
|
let gantt_chart = new Gantt('.gantt-target', tasks, {
|
||||||
|
on_click: (task) => {
|
||||||
|
console.log('Click', task);
|
||||||
|
},
|
||||||
|
// on_double_click: (task) => {
|
||||||
|
// console.log("Double Click", task);
|
||||||
|
// },
|
||||||
|
// on_date_change: (task, start, end) => {
|
||||||
|
// console.log("Date change", task, start, end);
|
||||||
|
// },
|
||||||
|
// on_progress_change: (task, progress) => {
|
||||||
|
// console.log("Progress Change", task, progress);
|
||||||
|
// },
|
||||||
|
// on_view_change: (mode) => {
|
||||||
|
// console.log("View Change", mode);
|
||||||
|
// },
|
||||||
|
// on_hover: (task, x, y) => {
|
||||||
|
// console.log("Hover", x, y);
|
||||||
|
// },
|
||||||
|
view_mode: 'Day',
|
||||||
|
view_mode_padding: { DAY: '3d' },
|
||||||
|
// popup: false,
|
||||||
|
// scroll_to: 'today',
|
||||||
|
// view_mode_select: true,
|
||||||
|
// dates_readonly: true,
|
||||||
|
// today_button: false,
|
||||||
|
// readonly: true,
|
||||||
|
// lines: 'vertical',
|
||||||
|
// lower_text: (date) => date.getDay(),
|
||||||
|
// upper_text: (date, view_mode, def) => def,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2016 Frappe Technologies Pvt. Ltd.
|
Copyright (c) 2024 Frappe Technologies Pvt. Ltd.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
|||||||
6265
package-lock.json
generated
Normal file
6265
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
108
package.json
108
package.json
@ -1,52 +1,60 @@
|
|||||||
{
|
{
|
||||||
"name": "frappe-gantt",
|
"name": "frappe-gantt",
|
||||||
"version": "0.6.1",
|
"version": "0.8",
|
||||||
"description": "A simple, modern, interactive gantt library for the web",
|
"description": "A simple, modern, interactive gantt library for the web",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"type": "module",
|
||||||
"start": "yarn run dev",
|
"scripts": {
|
||||||
"build": "rollup -c",
|
"start": "yarn run dev",
|
||||||
"dev": "rollup -c -w",
|
"dev": "vite",
|
||||||
"test": "jest",
|
"build-dev": "vite build --watch",
|
||||||
"test:watch": "jest --watch",
|
"build": "vite build",
|
||||||
"prettier": "prettier --write \"{src/*,tests/*,rollup.config}.js\"",
|
"test": "jest",
|
||||||
"prettier-check": "prettier --check \"{src/*,tests/*,rollup.config}.js\""
|
"lint": "eslint src/**/*.js",
|
||||||
},
|
"test:watch": "jest --watch",
|
||||||
"repository": {
|
"prettier": "prettier --write \"{src/*,tests/*,rollup.config}.js\"",
|
||||||
"type": "git",
|
"prettier-check": "prettier --check \"{src/*,tests/*,rollup.config}.js\""
|
||||||
"url": "https://github.com/frappe/gantt.git"
|
},
|
||||||
},
|
"repository": {
|
||||||
"files": [
|
"type": "git",
|
||||||
"src",
|
"url": "https://github.com/frappe/gantt.git"
|
||||||
"dist",
|
},
|
||||||
"README.md"
|
"files": [
|
||||||
],
|
"src",
|
||||||
"keywords": [
|
"dist",
|
||||||
"gantt",
|
"README.md"
|
||||||
"svg",
|
],
|
||||||
"simple gantt",
|
"exports": {
|
||||||
"project timeline",
|
".": {
|
||||||
"interactive gantt",
|
"import": "./dist/frappe-gantt.es.js",
|
||||||
"project management"
|
"require": "./dist/frappe-gantt.umd.js"
|
||||||
],
|
}
|
||||||
"author": "Faris Ansari",
|
},
|
||||||
"license": "MIT",
|
"keywords": [
|
||||||
"bugs": {
|
"gantt",
|
||||||
"url": "https://github.com/frappe/gantt/issues"
|
"svg",
|
||||||
},
|
"simple gantt",
|
||||||
"homepage": "https://github.com/frappe/gantt",
|
"project timeline",
|
||||||
"devDependencies": {
|
"interactive gantt",
|
||||||
"babel-preset-env": "^1.6.1",
|
"project management"
|
||||||
"eslint": "^4.17.0",
|
],
|
||||||
"eslint-config-prettier": "^2.9.0",
|
"author": "Faris Ansari",
|
||||||
"eslint-plugin-prettier": "^2.6.0",
|
"license": "MIT",
|
||||||
"jest": "^22.2.1",
|
"bugs": {
|
||||||
"prettier": "3.2.5",
|
"url": "https://github.com/frappe/gantt/issues"
|
||||||
"rollup": "^2.70.2",
|
},
|
||||||
"rollup-plugin-sass": "^1.2.12",
|
"homepage": "https://github.com/frappe/gantt",
|
||||||
"rollup-plugin-terser": "^7.0.2"
|
"devDependencies": {
|
||||||
},
|
"eslint": "^4.17.0",
|
||||||
"eslintIgnore": [
|
"eslint-config-prettier": "^2.9.0",
|
||||||
"dist"
|
"eslint-plugin-prettier": "^2.6.0",
|
||||||
]
|
"jest": "^22.2.1",
|
||||||
|
"postcss-nesting": "^12.1.2",
|
||||||
|
"prettier": "3.2.5",
|
||||||
|
"vite": "^5.2.10"
|
||||||
|
},
|
||||||
|
"eslintIgnore": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"packageManager": "yarn@3.2.3"
|
||||||
}
|
}
|
||||||
|
|||||||
4
postcss.config.cjs
Normal file
4
postcss.config.cjs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
module.exports = {
|
||||||
|
plugins: [require('postcss-nesting')],
|
||||||
|
};
|
||||||
@ -1,37 +0,0 @@
|
|||||||
import sass from "rollup-plugin-sass";
|
|
||||||
import { terser } from "rollup-plugin-terser";
|
|
||||||
|
|
||||||
const dev = {
|
|
||||||
input: "src/index.js",
|
|
||||||
output: {
|
|
||||||
name: "Gantt",
|
|
||||||
file: "dist/frappe-gantt.js",
|
|
||||||
sourcemap: true,
|
|
||||||
format: "iife",
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
sass({
|
|
||||||
output: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const prod = {
|
|
||||||
input: "src/index.js",
|
|
||||||
output: {
|
|
||||||
name: "Gantt",
|
|
||||||
file: "dist/frappe-gantt.min.js",
|
|
||||||
sourcemap: true,
|
|
||||||
format: "iife",
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
sass({
|
|
||||||
output: true,
|
|
||||||
options: {
|
|
||||||
outputStyle: "compressed",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
terser(),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export default [dev, prod];
|
|
||||||
127
src/arrow.js
127
src/arrow.js
@ -1,52 +1,53 @@
|
|||||||
import { createSVG } from "./svg_utils";
|
import { createSVG } from './svg_utils';
|
||||||
|
|
||||||
export default class Arrow {
|
export default class Arrow {
|
||||||
constructor(gantt, from_task, to_task) {
|
constructor(gantt, from_task, to_task) {
|
||||||
this.gantt = gantt;
|
this.gantt = gantt;
|
||||||
this.from_task = from_task;
|
this.from_task = from_task;
|
||||||
this.to_task = to_task;
|
this.to_task = to_task;
|
||||||
|
|
||||||
this.calculate_path();
|
this.calculate_path();
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
|
||||||
|
|
||||||
calculate_path() {
|
|
||||||
let start_x =
|
|
||||||
this.from_task.$bar.getX() + this.from_task.$bar.getWidth() / 2;
|
|
||||||
|
|
||||||
const condition = () =>
|
|
||||||
this.to_task.$bar.getX() < start_x + this.gantt.options.padding &&
|
|
||||||
start_x > this.from_task.$bar.getX() + this.gantt.options.padding;
|
|
||||||
|
|
||||||
while (condition()) {
|
|
||||||
start_x -= 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const start_y =
|
calculate_path() {
|
||||||
this.gantt.options.header_height +
|
let start_x =
|
||||||
this.gantt.options.bar_height +
|
this.from_task.$bar.getX() + this.from_task.$bar.getWidth() / 2;
|
||||||
(this.gantt.options.padding + this.gantt.options.bar_height) *
|
|
||||||
this.from_task.task._index +
|
|
||||||
this.gantt.options.padding;
|
|
||||||
|
|
||||||
const end_x = this.to_task.$bar.getX() - this.gantt.options.padding / 2 - 7;
|
const condition = () =>
|
||||||
const end_y =
|
this.to_task.$bar.getX() < start_x + this.gantt.options.padding &&
|
||||||
this.gantt.options.header_height +
|
start_x > this.from_task.$bar.getX() + this.gantt.options.padding;
|
||||||
this.gantt.options.bar_height / 2 +
|
|
||||||
(this.gantt.options.padding + this.gantt.options.bar_height) *
|
|
||||||
this.to_task.task._index +
|
|
||||||
this.gantt.options.padding;
|
|
||||||
|
|
||||||
const from_is_below_to =
|
while (condition()) {
|
||||||
this.from_task.task._index > this.to_task.task._index;
|
start_x -= 10;
|
||||||
const curve = this.gantt.options.arrow_curve;
|
}
|
||||||
const clockwise = from_is_below_to ? 1 : 0;
|
|
||||||
const curve_y = from_is_below_to ? -curve : curve;
|
|
||||||
const offset = from_is_below_to
|
|
||||||
? end_y + this.gantt.options.arrow_curve
|
|
||||||
: end_y - this.gantt.options.arrow_curve;
|
|
||||||
|
|
||||||
this.path = `
|
const start_y =
|
||||||
|
this.gantt.options.header_height +
|
||||||
|
this.gantt.options.bar_height +
|
||||||
|
(this.gantt.options.padding + this.gantt.options.bar_height) *
|
||||||
|
this.from_task.task._index +
|
||||||
|
this.gantt.options.padding;
|
||||||
|
|
||||||
|
const end_x =
|
||||||
|
this.to_task.$bar.getX() - this.gantt.options.padding / 2 - 7;
|
||||||
|
const end_y =
|
||||||
|
this.gantt.options.header_height +
|
||||||
|
this.gantt.options.bar_height / 2 +
|
||||||
|
(this.gantt.options.padding + this.gantt.options.bar_height) *
|
||||||
|
this.to_task.task._index +
|
||||||
|
this.gantt.options.padding;
|
||||||
|
|
||||||
|
const from_is_below_to =
|
||||||
|
this.from_task.task._index > this.to_task.task._index;
|
||||||
|
const curve = this.gantt.options.arrow_curve;
|
||||||
|
const clockwise = from_is_below_to ? 1 : 0;
|
||||||
|
const curve_y = from_is_below_to ? -curve : curve;
|
||||||
|
const offset = from_is_below_to
|
||||||
|
? end_y + this.gantt.options.arrow_curve
|
||||||
|
: end_y - this.gantt.options.arrow_curve;
|
||||||
|
|
||||||
|
this.path = `
|
||||||
M ${start_x} ${start_y}
|
M ${start_x} ${start_y}
|
||||||
V ${offset}
|
V ${offset}
|
||||||
a ${curve} ${curve} 0 0 ${clockwise} ${curve} ${curve_y}
|
a ${curve} ${curve} 0 0 ${clockwise} ${curve} ${curve_y}
|
||||||
@ -55,16 +56,18 @@ export default class Arrow {
|
|||||||
l 5 5
|
l 5 5
|
||||||
l -5 5`;
|
l -5 5`;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.to_task.$bar.getX() <
|
this.to_task.$bar.getX() <
|
||||||
this.from_task.$bar.getX() + this.gantt.options.padding
|
this.from_task.$bar.getX() + this.gantt.options.padding
|
||||||
) {
|
) {
|
||||||
const down_1 = this.gantt.options.padding / 2 - curve;
|
const down_1 = this.gantt.options.padding / 2 - curve;
|
||||||
const down_2 =
|
const down_2 =
|
||||||
this.to_task.$bar.getY() + this.to_task.$bar.getHeight() / 2 - curve_y;
|
this.to_task.$bar.getY() +
|
||||||
const left = this.to_task.$bar.getX() - this.gantt.options.padding;
|
this.to_task.$bar.getHeight() / 2 -
|
||||||
|
curve_y;
|
||||||
|
const left = this.to_task.$bar.getX() - this.gantt.options.padding;
|
||||||
|
|
||||||
this.path = `
|
this.path = `
|
||||||
M ${start_x} ${start_y}
|
M ${start_x} ${start_y}
|
||||||
v ${down_1}
|
v ${down_1}
|
||||||
a ${curve} ${curve} 0 0 1 -${curve} ${curve}
|
a ${curve} ${curve} 0 0 1 -${curve} ${curve}
|
||||||
@ -76,19 +79,19 @@ export default class Arrow {
|
|||||||
m -5 -5
|
m -5 -5
|
||||||
l 5 5
|
l 5 5
|
||||||
l -5 5`;
|
l -5 5`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
this.element = createSVG("path", {
|
this.element = createSVG('path', {
|
||||||
d: this.path,
|
d: this.path,
|
||||||
"data-from": this.from_task.task.id,
|
'data-from': this.from_task.task.id,
|
||||||
"data-to": this.to_task.task.id,
|
'data-to': this.to_task.task.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
this.calculate_path();
|
this.calculate_path();
|
||||||
this.element.setAttribute("d", this.path);
|
this.element.setAttribute('d', this.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1231
src/bar.js
1231
src/bar.js
File diff suppressed because it is too large
Load Diff
99
src/dark.css
Normal file
99
src/dark.css
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,97 +0,0 @@
|
|||||||
$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-header {
|
|
||||||
fill: #252525;
|
|
||||||
stroke: $border-color-dark;
|
|
||||||
}
|
|
||||||
.grid-row {
|
|
||||||
fill: #252525;
|
|
||||||
}
|
|
||||||
.grid-row:nth-child(even) {
|
|
||||||
fill: $light-bg-dark;
|
|
||||||
}
|
|
||||||
.row-line {
|
|
||||||
stroke: $light-border-color-dark;
|
|
||||||
}
|
|
||||||
.tick {
|
|
||||||
stroke: $border-color-dark;
|
|
||||||
}
|
|
||||||
.today-highlight {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
stroke: $text-muted-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar {
|
|
||||||
fill: $bar-color-dark;
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
.bar-progress {
|
|
||||||
fill: $blue-dark;
|
|
||||||
}
|
|
||||||
.bar-invalid {
|
|
||||||
fill: transparent;
|
|
||||||
stroke: $bar-stroke-dark;
|
|
||||||
|
|
||||||
& ~ .bar-label {
|
|
||||||
fill: $text-light-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-label.big {
|
|
||||||
fill: $text-light-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-wrapper {
|
|
||||||
&:hover {
|
|
||||||
.bar {
|
|
||||||
fill: lighten($bar-color-dark, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-progress {
|
|
||||||
fill: lighten($blue-dark, 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
.bar {
|
|
||||||
fill: lighten($bar-color-dark, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-progress {
|
|
||||||
fill: lighten($blue-dark, 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.upper-text {
|
|
||||||
fill: #a2a2a2;
|
|
||||||
}
|
|
||||||
.lower-text {
|
|
||||||
fill: $text-color-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark > .gantt-container {
|
|
||||||
.popup-wrapper {
|
|
||||||
background-color: #333;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
border-color: lighten($blue-dark, 5);
|
|
||||||
}
|
|
||||||
.pointer {
|
|
||||||
border-top-color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,266 +1,266 @@
|
|||||||
const YEAR = "year";
|
const YEAR = 'year';
|
||||||
const MONTH = "month";
|
const MONTH = 'month';
|
||||||
const DAY = "day";
|
const DAY = 'day';
|
||||||
const HOUR = "hour";
|
const HOUR = 'hour';
|
||||||
const MINUTE = "minute";
|
const MINUTE = 'minute';
|
||||||
const SECOND = "second";
|
const SECOND = 'second';
|
||||||
const MILLISECOND = "millisecond";
|
const MILLISECOND = 'millisecond';
|
||||||
|
|
||||||
const SHORTENED = {
|
const SHORTENED = {
|
||||||
January: "Jan",
|
January: 'Jan',
|
||||||
February: "Feb",
|
February: 'Feb',
|
||||||
March: "Mar",
|
March: 'Mar',
|
||||||
April: "Apr",
|
April: 'Apr',
|
||||||
May: "May",
|
May: 'May',
|
||||||
June: "Jun",
|
June: 'Jun',
|
||||||
July: "Jul",
|
July: 'Jul',
|
||||||
August: "Aug",
|
August: 'Aug',
|
||||||
September: "Sep",
|
September: 'Sep',
|
||||||
October: "Oct",
|
October: 'Oct',
|
||||||
November: "Nov",
|
November: 'Nov',
|
||||||
December: "Dec"
|
December: 'Dec',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
parse_duration(duration) {
|
parse_duration(duration) {
|
||||||
const regex = /([0-9])+(y|m|d|h|min|s|ms)/gm;
|
const regex = /([0-9]+)(y|m|d|h|min|s|ms)/gm;
|
||||||
const matches = regex.exec(duration);
|
const matches = regex.exec(duration);
|
||||||
|
console.log(matches);
|
||||||
if (matches !== null) {
|
if (matches !== null) {
|
||||||
if (matches[2] === "y") {
|
if (matches[2] === 'y') {
|
||||||
return { duration: parseInt(matches[1]), scale: `year` };
|
return { duration: parseInt(matches[1]), scale: `year` };
|
||||||
} else if (matches[2] === "m") {
|
} else if (matches[2] === 'm') {
|
||||||
return { duration: parseInt(matches[1]), scale: `month` };
|
return { duration: parseInt(matches[1]), scale: `month` };
|
||||||
} else if (matches[2] === "d") {
|
} else if (matches[2] === 'd') {
|
||||||
return { duration: parseInt(matches[1]), scale: `day` };
|
return { duration: parseInt(matches[1]), scale: `day` };
|
||||||
} else if (matches[2] === "h") {
|
} else if (matches[2] === 'h') {
|
||||||
return { duration: parseInt(matches[1]), scale: `hour` };
|
return { duration: parseInt(matches[1]), scale: `hour` };
|
||||||
} else if (matches[2] === "min") {
|
} else if (matches[2] === 'min') {
|
||||||
return { duration: parseInt(matches[1]), scale: `minute` };
|
return { duration: parseInt(matches[1]), scale: `minute` };
|
||||||
} else if (matches[2] === "s") {
|
} else if (matches[2] === 's') {
|
||||||
return { duration: parseInt(matches[1]), scale: `second` };
|
return { duration: parseInt(matches[1]), scale: `second` };
|
||||||
} else if (matches[2] === "ms") {
|
} else if (matches[2] === 'ms') {
|
||||||
return { duration: parseInt(matches[1]), scale: `millisecond` };
|
return { duration: parseInt(matches[1]), scale: `millisecond` };
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
parse(date, date_separator = "-", time_separator = /[.:]/) {
|
|
||||||
if (date instanceof Date) {
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
if (typeof date === "string") {
|
|
||||||
let date_parts, time_parts;
|
|
||||||
const parts = date.split(" ");
|
|
||||||
date_parts = parts[0]
|
|
||||||
.split(date_separator)
|
|
||||||
.map((val) => parseInt(val, 10));
|
|
||||||
time_parts = parts[1] && parts[1].split(time_separator);
|
|
||||||
|
|
||||||
// month is 0 indexed
|
|
||||||
date_parts[1] = date_parts[1] ? date_parts[1] - 1 : 0;
|
|
||||||
|
|
||||||
let vals = date_parts;
|
|
||||||
|
|
||||||
if (time_parts && time_parts.length) {
|
|
||||||
if (time_parts.length === 4) {
|
|
||||||
time_parts[3] = "0." + time_parts[3];
|
|
||||||
time_parts[3] = parseFloat(time_parts[3]) * 1000;
|
|
||||||
}
|
}
|
||||||
vals = vals.concat(time_parts);
|
},
|
||||||
}
|
parse(date, date_separator = '-', time_separator = /[.:]/) {
|
||||||
return new Date(...vals);
|
if (date instanceof Date) {
|
||||||
}
|
return date;
|
||||||
},
|
|
||||||
|
|
||||||
to_string(date, with_time = false) {
|
|
||||||
if (!(date instanceof Date)) {
|
|
||||||
throw new TypeError("Invalid argument type");
|
|
||||||
}
|
|
||||||
const vals = this.get_date_values(date).map((val, i) => {
|
|
||||||
if (i === 1) {
|
|
||||||
// add 1 for month
|
|
||||||
val = val + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i === 6) {
|
|
||||||
return padStart(val + "", 3, "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
return padStart(val + "", 2, "0");
|
|
||||||
});
|
|
||||||
const date_string = `${vals[0]}-${vals[1]}-${vals[2]}`;
|
|
||||||
const time_string = `${vals[3]}:${vals[4]}:${vals[5]}.${vals[6]}`;
|
|
||||||
|
|
||||||
return date_string + (with_time ? " " + time_string : "");
|
|
||||||
},
|
|
||||||
|
|
||||||
format(date, format_string = "YYYY-MM-DD HH:mm:ss.SSS", lang = "en") {
|
|
||||||
const dateTimeFormat = new Intl.DateTimeFormat(lang, {
|
|
||||||
month: "long",
|
|
||||||
});
|
|
||||||
const month_name = dateTimeFormat.format(date);
|
|
||||||
const month_name_capitalized =
|
|
||||||
month_name.charAt(0).toUpperCase() + month_name.slice(1);
|
|
||||||
|
|
||||||
const values = this.get_date_values(date).map((d) => padStart(d, 2, 0));
|
|
||||||
const format_map = {
|
|
||||||
YYYY: values[0],
|
|
||||||
MM: padStart(+values[1] + 1, 2, 0),
|
|
||||||
DD: values[2],
|
|
||||||
HH: values[3],
|
|
||||||
mm: values[4],
|
|
||||||
ss: values[5],
|
|
||||||
SSS: values[6],
|
|
||||||
D: values[2],
|
|
||||||
MMMM: month_name_capitalized,
|
|
||||||
MMM: SHORTENED[month_name_capitalized],
|
|
||||||
};
|
|
||||||
|
|
||||||
let str = format_string;
|
|
||||||
const formatted_values = [];
|
|
||||||
|
|
||||||
Object.keys(format_map)
|
|
||||||
.sort((a, b) => b.length - a.length) // big string first
|
|
||||||
.forEach((key) => {
|
|
||||||
if (str.includes(key)) {
|
|
||||||
str = str.replaceAll(key, `$${formatted_values.length}`);
|
|
||||||
formatted_values.push(format_map[key]);
|
|
||||||
}
|
}
|
||||||
});
|
if (typeof date === 'string') {
|
||||||
|
let date_parts, time_parts;
|
||||||
|
const parts = date.split(' ');
|
||||||
|
date_parts = parts[0]
|
||||||
|
.split(date_separator)
|
||||||
|
.map((val) => parseInt(val, 10));
|
||||||
|
time_parts = parts[1] && parts[1].split(time_separator);
|
||||||
|
|
||||||
formatted_values.forEach((value, i) => {
|
// month is 0 indexed
|
||||||
str = str.replaceAll(`$${i}`, value);
|
date_parts[1] = date_parts[1] ? date_parts[1] - 1 : 0;
|
||||||
});
|
|
||||||
|
|
||||||
return str;
|
let vals = date_parts;
|
||||||
},
|
|
||||||
|
|
||||||
diff(date_a, date_b, scale = DAY) {
|
if (time_parts && time_parts.length) {
|
||||||
let milliseconds, seconds, hours, minutes, days, months, years;
|
if (time_parts.length === 4) {
|
||||||
|
time_parts[3] = '0.' + time_parts[3];
|
||||||
|
time_parts[3] = parseFloat(time_parts[3]) * 1000;
|
||||||
|
}
|
||||||
|
vals = vals.concat(time_parts);
|
||||||
|
}
|
||||||
|
return new Date(...vals);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
milliseconds = date_a - date_b;
|
to_string(date, with_time = false) {
|
||||||
seconds = milliseconds / 1000;
|
if (!(date instanceof Date)) {
|
||||||
minutes = seconds / 60;
|
throw new TypeError('Invalid argument type');
|
||||||
hours = minutes / 60;
|
}
|
||||||
days = hours / 24;
|
const vals = this.get_date_values(date).map((val, i) => {
|
||||||
months = days / 30;
|
if (i === 1) {
|
||||||
years = months / 12;
|
// add 1 for month
|
||||||
|
val = val + 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!scale.endsWith("s")) {
|
if (i === 6) {
|
||||||
scale += "s";
|
return padStart(val + '', 3, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.floor(
|
return padStart(val + '', 2, '0');
|
||||||
{
|
});
|
||||||
milliseconds,
|
const date_string = `${vals[0]}-${vals[1]}-${vals[2]}`;
|
||||||
seconds,
|
const time_string = `${vals[3]}:${vals[4]}:${vals[5]}.${vals[6]}`;
|
||||||
minutes,
|
|
||||||
hours,
|
|
||||||
days,
|
|
||||||
months,
|
|
||||||
years,
|
|
||||||
}[scale],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
today() {
|
return date_string + (with_time ? ' ' + time_string : '');
|
||||||
const vals = this.get_date_values(new Date()).slice(0, 3);
|
},
|
||||||
return new Date(...vals);
|
|
||||||
},
|
|
||||||
|
|
||||||
now() {
|
format(date, format_string = 'YYYY-MM-DD HH:mm:ss.SSS', lang = 'en') {
|
||||||
return new Date();
|
const dateTimeFormat = new Intl.DateTimeFormat(lang, {
|
||||||
},
|
month: 'long',
|
||||||
|
});
|
||||||
|
const month_name = dateTimeFormat.format(date);
|
||||||
|
const month_name_capitalized =
|
||||||
|
month_name.charAt(0).toUpperCase() + month_name.slice(1);
|
||||||
|
|
||||||
add(date, qty, scale) {
|
const values = this.get_date_values(date).map((d) => padStart(d, 2, 0));
|
||||||
qty = parseInt(qty, 10);
|
const format_map = {
|
||||||
const vals = [
|
YYYY: values[0],
|
||||||
date.getFullYear() + (scale === YEAR ? qty : 0),
|
MM: padStart(+values[1] + 1, 2, 0),
|
||||||
date.getMonth() + (scale === MONTH ? qty : 0),
|
DD: values[2],
|
||||||
date.getDate() + (scale === DAY ? qty : 0),
|
HH: values[3],
|
||||||
date.getHours() + (scale === HOUR ? qty : 0),
|
mm: values[4],
|
||||||
date.getMinutes() + (scale === MINUTE ? qty : 0),
|
ss: values[5],
|
||||||
date.getSeconds() + (scale === SECOND ? qty : 0),
|
SSS: values[6],
|
||||||
date.getMilliseconds() + (scale === MILLISECOND ? qty : 0),
|
D: values[2],
|
||||||
];
|
MMMM: month_name_capitalized,
|
||||||
return new Date(...vals);
|
MMM: SHORTENED[month_name_capitalized],
|
||||||
},
|
};
|
||||||
|
|
||||||
start_of(date, scale) {
|
let str = format_string;
|
||||||
const scores = {
|
const formatted_values = [];
|
||||||
[YEAR]: 6,
|
|
||||||
[MONTH]: 5,
|
|
||||||
[DAY]: 4,
|
|
||||||
[HOUR]: 3,
|
|
||||||
[MINUTE]: 2,
|
|
||||||
[SECOND]: 1,
|
|
||||||
[MILLISECOND]: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
function should_reset(_scale) {
|
Object.keys(format_map)
|
||||||
const max_score = scores[scale];
|
.sort((a, b) => b.length - a.length) // big string first
|
||||||
return scores[_scale] <= max_score;
|
.forEach((key) => {
|
||||||
}
|
if (str.includes(key)) {
|
||||||
|
str = str.replaceAll(key, `$${formatted_values.length}`);
|
||||||
|
formatted_values.push(format_map[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const vals = [
|
formatted_values.forEach((value, i) => {
|
||||||
date.getFullYear(),
|
str = str.replaceAll(`$${i}`, value);
|
||||||
should_reset(YEAR) ? 0 : date.getMonth(),
|
});
|
||||||
should_reset(MONTH) ? 1 : date.getDate(),
|
|
||||||
should_reset(DAY) ? 0 : date.getHours(),
|
|
||||||
should_reset(HOUR) ? 0 : date.getMinutes(),
|
|
||||||
should_reset(MINUTE) ? 0 : date.getSeconds(),
|
|
||||||
should_reset(SECOND) ? 0 : date.getMilliseconds(),
|
|
||||||
];
|
|
||||||
|
|
||||||
return new Date(...vals);
|
return str;
|
||||||
},
|
},
|
||||||
|
|
||||||
clone(date) {
|
diff(date_a, date_b, scale = DAY) {
|
||||||
return new Date(...this.get_date_values(date));
|
let milliseconds, seconds, hours, minutes, days, months, years;
|
||||||
},
|
|
||||||
|
|
||||||
get_date_values(date) {
|
milliseconds = date_a - date_b;
|
||||||
return [
|
seconds = milliseconds / 1000;
|
||||||
date.getFullYear(),
|
minutes = seconds / 60;
|
||||||
date.getMonth(),
|
hours = minutes / 60;
|
||||||
date.getDate(),
|
days = hours / 24;
|
||||||
date.getHours(),
|
months = days / 30;
|
||||||
date.getMinutes(),
|
years = months / 12;
|
||||||
date.getSeconds(),
|
|
||||||
date.getMilliseconds(),
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
get_days_in_month(date) {
|
if (!scale.endsWith('s')) {
|
||||||
const no_of_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
scale += 's';
|
||||||
|
}
|
||||||
|
|
||||||
const month = date.getMonth();
|
return Math.floor(
|
||||||
|
{
|
||||||
|
milliseconds,
|
||||||
|
seconds,
|
||||||
|
minutes,
|
||||||
|
hours,
|
||||||
|
days,
|
||||||
|
months,
|
||||||
|
years,
|
||||||
|
}[scale],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
if (month !== 1) {
|
today() {
|
||||||
return no_of_days[month];
|
const vals = this.get_date_values(new Date()).slice(0, 3);
|
||||||
}
|
return new Date(...vals);
|
||||||
|
},
|
||||||
|
|
||||||
// Feb
|
now() {
|
||||||
const year = date.getFullYear();
|
return new Date();
|
||||||
if ((year % 4 === 0 && year % 100 != 0) || year % 400 === 0) {
|
},
|
||||||
return 29;
|
|
||||||
}
|
add(date, qty, scale) {
|
||||||
return 28;
|
qty = parseInt(qty, 10);
|
||||||
},
|
const vals = [
|
||||||
|
date.getFullYear() + (scale === YEAR ? qty : 0),
|
||||||
|
date.getMonth() + (scale === MONTH ? qty : 0),
|
||||||
|
date.getDate() + (scale === DAY ? qty : 0),
|
||||||
|
date.getHours() + (scale === HOUR ? qty : 0),
|
||||||
|
date.getMinutes() + (scale === MINUTE ? qty : 0),
|
||||||
|
date.getSeconds() + (scale === SECOND ? qty : 0),
|
||||||
|
date.getMilliseconds() + (scale === MILLISECOND ? qty : 0),
|
||||||
|
];
|
||||||
|
return new Date(...vals);
|
||||||
|
},
|
||||||
|
|
||||||
|
start_of(date, scale) {
|
||||||
|
const scores = {
|
||||||
|
[YEAR]: 6,
|
||||||
|
[MONTH]: 5,
|
||||||
|
[DAY]: 4,
|
||||||
|
[HOUR]: 3,
|
||||||
|
[MINUTE]: 2,
|
||||||
|
[SECOND]: 1,
|
||||||
|
[MILLISECOND]: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
function should_reset(_scale) {
|
||||||
|
const max_score = scores[scale];
|
||||||
|
return scores[_scale] <= max_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vals = [
|
||||||
|
date.getFullYear(),
|
||||||
|
should_reset(YEAR) ? 0 : date.getMonth(),
|
||||||
|
should_reset(MONTH) ? 1 : date.getDate(),
|
||||||
|
should_reset(DAY) ? 0 : date.getHours(),
|
||||||
|
should_reset(HOUR) ? 0 : date.getMinutes(),
|
||||||
|
should_reset(MINUTE) ? 0 : date.getSeconds(),
|
||||||
|
should_reset(SECOND) ? 0 : date.getMilliseconds(),
|
||||||
|
];
|
||||||
|
|
||||||
|
return new Date(...vals);
|
||||||
|
},
|
||||||
|
|
||||||
|
clone(date) {
|
||||||
|
return new Date(...this.get_date_values(date));
|
||||||
|
},
|
||||||
|
|
||||||
|
get_date_values(date) {
|
||||||
|
return [
|
||||||
|
date.getFullYear(),
|
||||||
|
date.getMonth(),
|
||||||
|
date.getDate(),
|
||||||
|
date.getHours(),
|
||||||
|
date.getMinutes(),
|
||||||
|
date.getSeconds(),
|
||||||
|
date.getMilliseconds(),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
get_days_in_month(date) {
|
||||||
|
const no_of_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||||
|
|
||||||
|
const month = date.getMonth();
|
||||||
|
|
||||||
|
if (month !== 1) {
|
||||||
|
return no_of_days[month];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feb
|
||||||
|
const year = date.getFullYear();
|
||||||
|
if ((year % 4 === 0 && year % 100 != 0) || year % 400 === 0) {
|
||||||
|
return 29;
|
||||||
|
}
|
||||||
|
return 28;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
|
||||||
function padStart(str, targetLength, padString) {
|
function padStart(str, targetLength, padString) {
|
||||||
str = str + "";
|
str = str + '';
|
||||||
targetLength = targetLength >> 0;
|
targetLength = targetLength >> 0;
|
||||||
padString = String(typeof padString !== "undefined" ? padString : " ");
|
padString = String(typeof padString !== 'undefined' ? padString : ' ');
|
||||||
if (str.length > targetLength) {
|
if (str.length > targetLength) {
|
||||||
return String(str);
|
return String(str);
|
||||||
} else {
|
} else {
|
||||||
targetLength = targetLength - str.length;
|
targetLength = targetLength - str.length;
|
||||||
if (targetLength > padString.length) {
|
if (targetLength > padString.length) {
|
||||||
padString += padString.repeat(targetLength / padString.length);
|
padString += padString.repeat(targetLength / padString.length);
|
||||||
|
}
|
||||||
|
return padString.slice(0, targetLength) + String(str);
|
||||||
}
|
}
|
||||||
return padString.slice(0, targetLength) + String(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
306
src/gantt.css
Normal file
306
src/gantt.css
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
@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: #666;
|
||||||
|
--text-grey: #98a1a9;
|
||||||
|
--text-light: #fff;
|
||||||
|
--text-dark: #111;
|
||||||
|
--progress: #ebeef0;
|
||||||
|
--handle-color: #dcdce4;
|
||||||
|
--handle-color-important: #94c4f4;
|
||||||
|
--light-blue: #c4c4e9;
|
||||||
|
--middle-blue: #62b2f9;
|
||||||
|
--dark-blue: #2c94ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.gantt-container {
|
||||||
|
line-height: 14.5px;
|
||||||
|
position: relative;
|
||||||
|
overflow: auto;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 500px;
|
||||||
|
|
||||||
|
& .popup-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background: #171b1f;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: max-content;
|
||||||
|
|
||||||
|
&.hidden {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .title {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
text-align: -webkit-center;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .subtitle {
|
||||||
|
color: var(--text-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .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;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .lower-text,
|
||||||
|
& .upper-text {
|
||||||
|
text-anchor: middle;
|
||||||
|
color: var(--text-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .upper-header {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .lower-header {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .lower-text {
|
||||||
|
font-size: 14px;
|
||||||
|
position: absolute;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .upper-text {
|
||||||
|
position: absolute;
|
||||||
|
width: fit-content;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .current-upper {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .side-header {
|
||||||
|
position: fixed;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
background: white;
|
||||||
|
line-height: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .today-button,
|
||||||
|
& .viewmode-select {
|
||||||
|
background: #f4f5f6;
|
||||||
|
text-align: -webkit-center;
|
||||||
|
text-align: center;
|
||||||
|
height: 25px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-dark);
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .viewmode-select {
|
||||||
|
outline: none !important;
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin-right: 4px;
|
||||||
|
|
||||||
|
/* -webkit-appearance: none; */
|
||||||
|
/* -moz-appearance: none; */
|
||||||
|
text-indent: 1px;
|
||||||
|
text-overflow: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
& .date-highlight {
|
||||||
|
background-color: var(--progress);
|
||||||
|
border-radius: 12px;
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .current-highlight {
|
||||||
|
position: absolute;
|
||||||
|
background: var(--dark-blue);
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .current-date-highlight {
|
||||||
|
background: var(--dark-blue);
|
||||||
|
color: var(--text-light);
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.gantt {
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
& .grid-background {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .grid-row {
|
||||||
|
fill: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .row-line {
|
||||||
|
stroke: var(--light-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .tick {
|
||||||
|
stroke: var(--stroke-color);
|
||||||
|
stroke-width: 0.4;
|
||||||
|
|
||||||
|
&.thick {
|
||||||
|
stroke: var(--dark-stroke-color);
|
||||||
|
stroke-width: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .holiday-highlight {
|
||||||
|
fill: var(--holiday-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .arrow {
|
||||||
|
fill: none;
|
||||||
|
stroke: #9fa9b1;
|
||||||
|
stroke-width: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-wrapper .bar {
|
||||||
|
fill: var(--bar-color);
|
||||||
|
stroke: var(--bar-stroke);
|
||||||
|
stroke-width: 0;
|
||||||
|
transition: stroke-width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-progress {
|
||||||
|
fill: var(--progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-expected-progress {
|
||||||
|
fill: var(--light-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-invalid {
|
||||||
|
fill: transparent;
|
||||||
|
stroke: var(--bar-stroke);
|
||||||
|
stroke-width: 1;
|
||||||
|
stroke-dasharray: 5;
|
||||||
|
|
||||||
|
&~.bar-label {
|
||||||
|
fill: var(--text-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-label {
|
||||||
|
fill: var(--text-dark);
|
||||||
|
dominant-baseline: central;
|
||||||
|
font-family: Helvetica;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
&.big {
|
||||||
|
fill: var(--text-dark);
|
||||||
|
text-anchor: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-wrapper.important {
|
||||||
|
& .bar {
|
||||||
|
fill: var(--bar-color-important);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-progress {
|
||||||
|
fill: var(--dark-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-label {
|
||||||
|
fill: var(--text-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .handle {
|
||||||
|
fill: var(--handle-color-important);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .handle.progress {
|
||||||
|
fill: var(--text-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .handle {
|
||||||
|
fill: var(--handle-color);
|
||||||
|
cursor: ew-resize;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .handle.progress {
|
||||||
|
fill: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar-wrapper {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
& .handle {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar {
|
||||||
|
-webkit-filter: drop-shadow(3px 3px 2px rgba(0, 0, 0, 0.7));
|
||||||
|
filter: drop-shadow(0 0 2px rgba(17, 43, 66, 0.16));
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .bar.safari {
|
||||||
|
outline: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.bar {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-highlight {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
316
src/gantt.scss
316
src/gantt.scss
@ -1,316 +0,0 @@
|
|||||||
@import "./dark.scss";
|
|
||||||
|
|
||||||
$bar-color: #fff !default;
|
|
||||||
$bar-color-important: #94c4f4 !default;
|
|
||||||
$bar-stroke: #fff !default;
|
|
||||||
$dark-stroke-color: #e0e0e0 !default;
|
|
||||||
$stroke-color: #EBEEF0 !default;
|
|
||||||
$light-bg: #f5f5f5 !default;
|
|
||||||
$light-border-color: #ebeff2 !default;
|
|
||||||
$light-yellow: #f6e796 !default;
|
|
||||||
$holiday-color: #F9FAFA !default;
|
|
||||||
$text-muted: #666 !default;
|
|
||||||
$text-grey: #98A1A9;
|
|
||||||
$text-light: #fff !default;
|
|
||||||
$text-dark: #111 !default;
|
|
||||||
$progress: #EBEEF0 !default;
|
|
||||||
$handle-color: #dcdce4 !default;
|
|
||||||
$handle-color-important: #94c4f4 !default;
|
|
||||||
$light-blue: #c4c4e9 !default;
|
|
||||||
$middle-blue: #62B2F9 !default;
|
|
||||||
$dark-blue: #2c94ec !default;
|
|
||||||
|
|
||||||
|
|
||||||
.gantt-container {
|
|
||||||
line-height: 14.5px;
|
|
||||||
|
|
||||||
.grid-header {
|
|
||||||
background-color: #ffffff;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lower-text,
|
|
||||||
.upper-text {
|
|
||||||
text-anchor: middle;
|
|
||||||
color: $text-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upper-header {
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lower-header {
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lower-text {
|
|
||||||
font-size: 14px;
|
|
||||||
position: absolute;
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upper-text {
|
|
||||||
position: absolute;
|
|
||||||
width: fit-content;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-upper {
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-header {
|
|
||||||
position: fixed;
|
|
||||||
padding: 0 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
background: white;
|
|
||||||
line-height: 20px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.today-button,
|
|
||||||
.viewmode-select {
|
|
||||||
background: #F4F5F6;
|
|
||||||
text-align: -webkit-center;
|
|
||||||
text-align: center;
|
|
||||||
height: 25px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: none;
|
|
||||||
color: $text-dark;
|
|
||||||
padding: 4px 10px;
|
|
||||||
border-radius: 8px;
|
|
||||||
height: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewmode-select {
|
|
||||||
outline: none !important;
|
|
||||||
padding: 4px 8px;
|
|
||||||
margin-right: 4px;
|
|
||||||
|
|
||||||
// Hide select icon
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
text-indent: 1px;
|
|
||||||
text-overflow: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-highlight {
|
|
||||||
background-color: $progress;
|
|
||||||
border-radius: 12px;
|
|
||||||
position: absolute;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-highlight {
|
|
||||||
position: absolute;
|
|
||||||
background: $dark-blue;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-date-highlight {
|
|
||||||
background: $dark-blue;
|
|
||||||
color: $text-light;
|
|
||||||
padding: 4px 8px;
|
|
||||||
border-radius: 200px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.gantt {
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
.grid-background {
|
|
||||||
fill: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.grid-row {
|
|
||||||
fill: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
// .grid-row:nth-child(even) {
|
|
||||||
// fill: $light-bg;
|
|
||||||
// }
|
|
||||||
|
|
||||||
.row-line {
|
|
||||||
stroke: $light-border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tick {
|
|
||||||
stroke: $stroke-color;
|
|
||||||
stroke-width: 0.4;
|
|
||||||
|
|
||||||
&.thick {
|
|
||||||
stroke: $dark-stroke-color;
|
|
||||||
stroke-width: 0.7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.holiday-highlight {
|
|
||||||
fill: $holiday-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
fill: none;
|
|
||||||
stroke: #9FA9B1;
|
|
||||||
stroke-width: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-wrapper .bar {
|
|
||||||
fill: $bar-color;
|
|
||||||
stroke: $bar-stroke;
|
|
||||||
stroke-width: 0;
|
|
||||||
transition: stroke-width 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-progress {
|
|
||||||
fill: $progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-expected-progress {
|
|
||||||
fill: $light-blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-invalid {
|
|
||||||
fill: transparent;
|
|
||||||
stroke: $bar-stroke;
|
|
||||||
stroke-width: 1;
|
|
||||||
stroke-dasharray: 5;
|
|
||||||
|
|
||||||
&~.bar-label {
|
|
||||||
fill: $text-light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-label {
|
|
||||||
fill: $text-dark;
|
|
||||||
dominant-baseline: central;
|
|
||||||
// text-anchor: middle;
|
|
||||||
font-family: Helvetica;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
&.big {
|
|
||||||
fill: $text-dark;
|
|
||||||
text-anchor: start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-wrapper.important {
|
|
||||||
.bar {
|
|
||||||
fill: $bar-color-important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-progress {
|
|
||||||
fill: $dark-blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-label {
|
|
||||||
fill: $text-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle {
|
|
||||||
fill: $handle-color-important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle.progress {
|
|
||||||
fill: $text-light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.handle {
|
|
||||||
fill: $handle-color;
|
|
||||||
cursor: ew-resize;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handle.progress {
|
|
||||||
fill: $text-muted;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-wrapper {
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
& .handle {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar {
|
|
||||||
-webkit-filter: drop-shadow(3px 3px 2px rgba(0, 0, 0, .7));
|
|
||||||
filter: drop-shadow(0 0 2px rgba(17, 43, 66, .16));
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.bar {
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-highlight {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.gantt-container {
|
|
||||||
position: relative;
|
|
||||||
overflow: auto;
|
|
||||||
font-size: 12px;
|
|
||||||
height: 500px;
|
|
||||||
|
|
||||||
.popup-wrapper {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
background: #171B1F;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
width: max-content;
|
|
||||||
|
|
||||||
&.hidden {
|
|
||||||
opacity: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.title {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
text-align: -webkit-center;
|
|
||||||
text-align: center;
|
|
||||||
color: $text-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
color: $text-grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pointer {
|
|
||||||
position: absolute;
|
|
||||||
height: 5px;
|
|
||||||
margin: 0 0 0 -5px;
|
|
||||||
border: 5px solid transparent;
|
|
||||||
border-bottom-color: rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2389
src/index.js
2389
src/index.js
File diff suppressed because it is too large
Load Diff
97
src/popup.js
97
src/popup.js
@ -1,61 +1,62 @@
|
|||||||
export default class Popup {
|
export default class Popup {
|
||||||
constructor(parent, custom_html) {
|
constructor(parent, custom_html) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.custom_html = custom_html;
|
this.custom_html = custom_html;
|
||||||
this.make();
|
this.make();
|
||||||
}
|
}
|
||||||
|
|
||||||
make() {
|
make() {
|
||||||
this.parent.innerHTML = `
|
this.parent.innerHTML = `
|
||||||
<div class="title"></div>
|
<div class="title"></div>
|
||||||
<div class="subtitle"></div>
|
<div class="subtitle"></div>
|
||||||
<div class="pointer"></div>
|
<div class="pointer"></div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
this.hide();
|
this.hide();
|
||||||
|
|
||||||
this.title = this.parent.querySelector(".title");
|
this.title = this.parent.querySelector('.title');
|
||||||
this.subtitle = this.parent.querySelector(".subtitle");
|
this.subtitle = this.parent.querySelector('.subtitle');
|
||||||
this.pointer = this.parent.querySelector(".pointer");
|
this.pointer = this.parent.querySelector('.pointer');
|
||||||
}
|
|
||||||
|
|
||||||
show(options) {
|
|
||||||
if (!options.target_element) {
|
|
||||||
throw new Error("target_element is required to show popup");
|
|
||||||
}
|
|
||||||
const target_element = options.target_element;
|
|
||||||
|
|
||||||
if (this.custom_html) {
|
|
||||||
let html = this.custom_html(options.task);
|
|
||||||
html += '<div class="pointer"></div>';
|
|
||||||
this.parent.innerHTML = html;
|
|
||||||
this.pointer = this.parent.querySelector(".pointer");
|
|
||||||
} else {
|
|
||||||
// set data
|
|
||||||
this.title.innerHTML = options.title;
|
|
||||||
this.subtitle.innerHTML = options.subtitle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set position
|
show(options) {
|
||||||
let position_meta;
|
if (!options.target_element) {
|
||||||
if (target_element instanceof HTMLElement) {
|
throw new Error('target_element is required to show popup');
|
||||||
position_meta = target_element.getBoundingClientRect();
|
}
|
||||||
} else if (target_element instanceof SVGElement) {
|
const target_element = options.target_element;
|
||||||
position_meta = options.target_element.getBBox();
|
|
||||||
|
if (this.custom_html) {
|
||||||
|
let html = this.custom_html(options.task);
|
||||||
|
html += '<div class="pointer"></div>';
|
||||||
|
this.parent.innerHTML = html;
|
||||||
|
this.pointer = this.parent.querySelector('.pointer');
|
||||||
|
} else {
|
||||||
|
// set data
|
||||||
|
this.title.innerHTML = options.title;
|
||||||
|
this.subtitle.innerHTML = options.subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set position
|
||||||
|
let position_meta;
|
||||||
|
if (target_element instanceof HTMLElement) {
|
||||||
|
position_meta = target_element.getBoundingClientRect();
|
||||||
|
} else if (target_element instanceof SVGElement) {
|
||||||
|
position_meta = options.target_element.getBBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parent.style.left = options.x - this.parent.clientWidth / 2 + 'px';
|
||||||
|
this.parent.style.top =
|
||||||
|
position_meta.y + position_meta.height + 10 + 'px';
|
||||||
|
|
||||||
|
this.pointer.style.left = this.parent.clientWidth / 2 + 'px';
|
||||||
|
this.pointer.style.top = '-15px';
|
||||||
|
|
||||||
|
// show
|
||||||
|
this.parent.style.opacity = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parent.style.left = options.x - this.parent.clientWidth / 2 + "px";
|
hide() {
|
||||||
this.parent.style.top = position_meta.y + position_meta.height + 10 + "px";
|
this.parent.style.opacity = 0;
|
||||||
|
this.parent.style.left = 0;
|
||||||
this.pointer.style.left = this.parent.clientWidth / 2 + "px";
|
}
|
||||||
this.pointer.style.top = "-15px";
|
|
||||||
|
|
||||||
// show
|
|
||||||
this.parent.style.opacity = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
this.parent.style.opacity = 0;
|
|
||||||
this.parent.style.left = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
188
src/svg_utils.js
188
src/svg_utils.js
@ -1,135 +1,135 @@
|
|||||||
export function $(expr, con) {
|
export function $(expr, con) {
|
||||||
return typeof expr === "string"
|
return typeof expr === 'string'
|
||||||
? (con || document).querySelector(expr)
|
? (con || document).querySelector(expr)
|
||||||
: expr || null;
|
: expr || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSVG(tag, attrs) {
|
export function createSVG(tag, attrs) {
|
||||||
const elem = document.createElementNS("http://www.w3.org/2000/svg", tag);
|
const elem = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
||||||
for (let attr in attrs) {
|
for (let attr in attrs) {
|
||||||
if (attr === "append_to") {
|
if (attr === 'append_to') {
|
||||||
const parent = attrs.append_to;
|
const parent = attrs.append_to;
|
||||||
parent.appendChild(elem);
|
parent.appendChild(elem);
|
||||||
} else if (attr === "innerHTML") {
|
} else if (attr === 'innerHTML') {
|
||||||
elem.innerHTML = attrs.innerHTML;
|
elem.innerHTML = attrs.innerHTML;
|
||||||
} else if (attr === 'clipPath') {
|
} else if (attr === 'clipPath') {
|
||||||
elem.setAttribute('clip-path', 'url(#' + attrs[attr] + ')');
|
elem.setAttribute('clip-path', 'url(#' + attrs[attr] + ')');
|
||||||
} else {
|
} else {
|
||||||
elem.setAttribute(attr, attrs[attr]);
|
elem.setAttribute(attr, attrs[attr]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return elem;
|
||||||
return elem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function animateSVG(svgElement, attr, from, to) {
|
export function animateSVG(svgElement, attr, from, to) {
|
||||||
const animatedSvgElement = getAnimationElement(svgElement, attr, from, to);
|
const animatedSvgElement = getAnimationElement(svgElement, attr, from, to);
|
||||||
|
|
||||||
if (animatedSvgElement === svgElement) {
|
if (animatedSvgElement === svgElement) {
|
||||||
// triggered 2nd time programmatically
|
// triggered 2nd time programmatically
|
||||||
// trigger artificial click event
|
// trigger artificial click event
|
||||||
const event = document.createEvent("HTMLEvents");
|
const event = document.createEvent('HTMLEvents');
|
||||||
event.initEvent("click", true, true);
|
event.initEvent('click', true, true);
|
||||||
event.eventName = "click";
|
event.eventName = 'click';
|
||||||
animatedSvgElement.dispatchEvent(event);
|
animatedSvgElement.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAnimationElement(
|
function getAnimationElement(
|
||||||
svgElement,
|
svgElement,
|
||||||
attr,
|
attr,
|
||||||
from,
|
|
||||||
to,
|
|
||||||
dur = "0.4s",
|
|
||||||
begin = "0.1s",
|
|
||||||
) {
|
|
||||||
const animEl = svgElement.querySelector("animate");
|
|
||||||
if (animEl) {
|
|
||||||
$.attr(animEl, {
|
|
||||||
attributeName: attr,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
dur,
|
|
||||||
begin: "click + " + begin, // artificial click
|
|
||||||
});
|
|
||||||
return svgElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
const animateElement = createSVG("animate", {
|
|
||||||
attributeName: attr,
|
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
dur,
|
dur = '0.4s',
|
||||||
begin,
|
begin = '0.1s',
|
||||||
calcMode: "spline",
|
) {
|
||||||
values: from + ";" + to,
|
const animEl = svgElement.querySelector('animate');
|
||||||
keyTimes: "0; 1",
|
if (animEl) {
|
||||||
keySplines: cubic_bezier("ease-out"),
|
$.attr(animEl, {
|
||||||
});
|
attributeName: attr,
|
||||||
svgElement.appendChild(animateElement);
|
from,
|
||||||
|
to,
|
||||||
|
dur,
|
||||||
|
begin: 'click + ' + begin, // artificial click
|
||||||
|
});
|
||||||
|
return svgElement;
|
||||||
|
}
|
||||||
|
|
||||||
return svgElement;
|
const animateElement = createSVG('animate', {
|
||||||
|
attributeName: attr,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
dur,
|
||||||
|
begin,
|
||||||
|
calcMode: 'spline',
|
||||||
|
values: from + ';' + to,
|
||||||
|
keyTimes: '0; 1',
|
||||||
|
keySplines: cubic_bezier('ease-out'),
|
||||||
|
});
|
||||||
|
svgElement.appendChild(animateElement);
|
||||||
|
|
||||||
|
return svgElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cubic_bezier(name) {
|
function cubic_bezier(name) {
|
||||||
return {
|
return {
|
||||||
ease: ".25 .1 .25 1",
|
ease: '.25 .1 .25 1',
|
||||||
linear: "0 0 1 1",
|
linear: '0 0 1 1',
|
||||||
"ease-in": ".42 0 1 1",
|
'ease-in': '.42 0 1 1',
|
||||||
"ease-out": "0 0 .58 1",
|
'ease-out': '0 0 .58 1',
|
||||||
"ease-in-out": ".42 0 .58 1",
|
'ease-in-out': '.42 0 .58 1',
|
||||||
}[name];
|
}[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
$.on = (element, event, selector, callback) => {
|
$.on = (element, event, selector, callback) => {
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
callback = selector;
|
callback = selector;
|
||||||
$.bind(element, event, callback);
|
$.bind(element, event, callback);
|
||||||
} else {
|
} else {
|
||||||
$.delegate(element, event, selector, callback);
|
$.delegate(element, event, selector, callback);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$.off = (element, event, handler) => {
|
$.off = (element, event, handler) => {
|
||||||
element.removeEventListener(event, handler);
|
element.removeEventListener(event, handler);
|
||||||
};
|
};
|
||||||
|
|
||||||
$.bind = (element, event, callback) => {
|
$.bind = (element, event, callback) => {
|
||||||
event.split(/\s+/).forEach(function (event) {
|
event.split(/\s+/).forEach(function (event) {
|
||||||
element.addEventListener(event, callback);
|
element.addEventListener(event, callback);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$.delegate = (element, event, selector, callback) => {
|
$.delegate = (element, event, selector, callback) => {
|
||||||
element.addEventListener(event, function (e) {
|
element.addEventListener(event, function (e) {
|
||||||
const delegatedTarget = e.target.closest(selector);
|
const delegatedTarget = e.target.closest(selector);
|
||||||
if (delegatedTarget) {
|
if (delegatedTarget) {
|
||||||
e.delegatedTarget = delegatedTarget;
|
e.delegatedTarget = delegatedTarget;
|
||||||
callback.call(this, e, delegatedTarget);
|
callback.call(this, e, delegatedTarget);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$.closest = (selector, element) => {
|
$.closest = (selector, element) => {
|
||||||
if (!element) return null;
|
if (!element) return null;
|
||||||
|
|
||||||
if (element.matches(selector)) {
|
if (element.matches(selector)) {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $.closest(selector, element.parentNode);
|
return $.closest(selector, element.parentNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
$.attr = (element, attr, value) => {
|
$.attr = (element, attr, value) => {
|
||||||
if (!value && typeof attr === "string") {
|
if (!value && typeof attr === 'string') {
|
||||||
return element.getAttribute(attr);
|
return element.getAttribute(attr);
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof attr === "object") {
|
|
||||||
for (let key in attr) {
|
|
||||||
$.attr(element, key, attr[key]);
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
element.setAttribute(attr, value);
|
if (typeof attr === 'object') {
|
||||||
|
for (let key in attr) {
|
||||||
|
$.attr(element, key, attr[key]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.setAttribute(attr, value);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,124 +1,124 @@
|
|||||||
import date_utils from "../src/date_utils";
|
import date_utils from '../src/date_utils';
|
||||||
|
|
||||||
test("Parse: parses string date", () => {
|
test('Parse: parses string date', () => {
|
||||||
const date = date_utils.parse("2017-09-09");
|
const date = date_utils.parse('2017-09-09');
|
||||||
|
|
||||||
expect(date.getDate()).toBe(9);
|
expect(date.getDate()).toBe(9);
|
||||||
expect(date.getMonth()).toBe(8);
|
expect(date.getMonth()).toBe(8);
|
||||||
expect(date.getFullYear()).toBe(2017);
|
expect(date.getFullYear()).toBe(2017);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Parse: parses string datetime", () => {
|
test('Parse: parses string datetime', () => {
|
||||||
const date = date_utils.parse("2017-08-27 16:08:34");
|
const date = date_utils.parse('2017-08-27 16:08:34');
|
||||||
|
|
||||||
expect(date.getFullYear()).toBe(2017);
|
expect(date.getFullYear()).toBe(2017);
|
||||||
expect(date.getMonth()).toBe(7);
|
expect(date.getMonth()).toBe(7);
|
||||||
expect(date.getDate()).toBe(27);
|
expect(date.getDate()).toBe(27);
|
||||||
expect(date.getHours()).toBe(16);
|
expect(date.getHours()).toBe(16);
|
||||||
expect(date.getMinutes()).toBe(8);
|
expect(date.getMinutes()).toBe(8);
|
||||||
expect(date.getSeconds()).toBe(34);
|
expect(date.getSeconds()).toBe(34);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Parse: parses string datetime", () => {
|
test('Parse: parses string datetime', () => {
|
||||||
const date = date_utils.parse("2016-02-29 16:08:34.3");
|
const date = date_utils.parse('2016-02-29 16:08:34.3');
|
||||||
|
|
||||||
expect(date.getFullYear()).toBe(2016);
|
expect(date.getFullYear()).toBe(2016);
|
||||||
expect(date.getMonth()).toBe(1);
|
expect(date.getMonth()).toBe(1);
|
||||||
expect(date.getDate()).toBe(29);
|
expect(date.getDate()).toBe(29);
|
||||||
expect(date.getHours()).toBe(16);
|
expect(date.getHours()).toBe(16);
|
||||||
expect(date.getMinutes()).toBe(8);
|
expect(date.getMinutes()).toBe(8);
|
||||||
expect(date.getSeconds()).toBe(34);
|
expect(date.getSeconds()).toBe(34);
|
||||||
expect(date.getMilliseconds()).toBe(300);
|
expect(date.getMilliseconds()).toBe(300);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Parse: parses string datetime", () => {
|
test('Parse: parses string datetime', () => {
|
||||||
const date = date_utils.parse("2015-07-01 00:00:59.200");
|
const date = date_utils.parse('2015-07-01 00:00:59.200');
|
||||||
|
|
||||||
expect(date.getFullYear()).toBe(2015);
|
expect(date.getFullYear()).toBe(2015);
|
||||||
expect(date.getMonth()).toBe(6);
|
expect(date.getMonth()).toBe(6);
|
||||||
expect(date.getDate()).toBe(1);
|
expect(date.getDate()).toBe(1);
|
||||||
expect(date.getHours()).toBe(0);
|
expect(date.getHours()).toBe(0);
|
||||||
expect(date.getMinutes()).toBe(0);
|
expect(date.getMinutes()).toBe(0);
|
||||||
expect(date.getSeconds()).toBe(59);
|
expect(date.getSeconds()).toBe(59);
|
||||||
expect(date.getMilliseconds()).toBe(200);
|
expect(date.getMilliseconds()).toBe(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Format: converts date object to string", () => {
|
test('Format: converts date object to string', () => {
|
||||||
const date = new Date("2017-09-18");
|
const date = new Date('2017-09-18');
|
||||||
expect(date_utils.to_string(date)).toBe("2017-09-18");
|
expect(date_utils.to_string(date)).toBe('2017-09-18');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Format: converts date object to string", () => {
|
test('Format: converts date object to string', () => {
|
||||||
const date = new Date("2016-02-29 16:08:34.3");
|
const date = new Date('2016-02-29 16:08:34.3');
|
||||||
expect(date_utils.to_string(date, true)).toBe("2016-02-29 16:08:34.300");
|
expect(date_utils.to_string(date, true)).toBe('2016-02-29 16:08:34.300');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Format: converts date object to string", () => {
|
test('Format: converts date object to string', () => {
|
||||||
const date = new Date("2016-02-29 16:08:34.3");
|
const date = new Date('2016-02-29 16:08:34.3');
|
||||||
expect(date_utils.to_string(date, true)).toBe("2016-02-29 16:08:34.300");
|
expect(date_utils.to_string(date, true)).toBe('2016-02-29 16:08:34.300');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Parse: returns Date Object as is", () => {
|
test('Parse: returns Date Object as is', () => {
|
||||||
const d = new Date();
|
const d = new Date();
|
||||||
const date = date_utils.parse(d);
|
const date = date_utils.parse(d);
|
||||||
|
|
||||||
expect(d).toBe(date);
|
expect(d).toBe(date);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Diff: returns diff between 2 date objects", () => {
|
test('Diff: returns diff between 2 date objects', () => {
|
||||||
const a = date_utils.parse("2017-09-08");
|
const a = date_utils.parse('2017-09-08');
|
||||||
const b = date_utils.parse("2017-06-07");
|
const b = date_utils.parse('2017-06-07');
|
||||||
|
|
||||||
expect(date_utils.diff(a, b, "day")).toBe(93);
|
expect(date_utils.diff(a, b, 'day')).toBe(93);
|
||||||
expect(date_utils.diff(a, b, "month")).toBe(3);
|
expect(date_utils.diff(a, b, 'month')).toBe(3);
|
||||||
expect(date_utils.diff(a, b, "year")).toBe(0);
|
expect(date_utils.diff(a, b, 'year')).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("StartOf", () => {
|
test('StartOf', () => {
|
||||||
const date = date_utils.parse("2017-08-12 15:07:34.012");
|
const date = date_utils.parse('2017-08-12 15:07:34.012');
|
||||||
|
|
||||||
const start_of_millisecond = date_utils.start_of(date, "millisecond");
|
const start_of_millisecond = date_utils.start_of(date, 'millisecond');
|
||||||
expect(date_utils.to_string(start_of_millisecond, true)).toBe(
|
expect(date_utils.to_string(start_of_millisecond, true)).toBe(
|
||||||
"2017-08-12 15:07:34.012",
|
'2017-08-12 15:07:34.012',
|
||||||
);
|
);
|
||||||
|
|
||||||
const start_of_second = date_utils.start_of(date, "second");
|
const start_of_second = date_utils.start_of(date, 'second');
|
||||||
expect(date_utils.to_string(start_of_second, true)).toBe(
|
expect(date_utils.to_string(start_of_second, true)).toBe(
|
||||||
"2017-08-12 15:07:34.000",
|
'2017-08-12 15:07:34.000',
|
||||||
);
|
);
|
||||||
|
|
||||||
const start_of_minute = date_utils.start_of(date, "minute");
|
const start_of_minute = date_utils.start_of(date, 'minute');
|
||||||
expect(date_utils.to_string(start_of_minute, true)).toBe(
|
expect(date_utils.to_string(start_of_minute, true)).toBe(
|
||||||
"2017-08-12 15:07:00.000",
|
'2017-08-12 15:07:00.000',
|
||||||
);
|
);
|
||||||
|
|
||||||
const start_of_hour = date_utils.start_of(date, "hour");
|
const start_of_hour = date_utils.start_of(date, 'hour');
|
||||||
expect(date_utils.to_string(start_of_hour, true)).toBe(
|
expect(date_utils.to_string(start_of_hour, true)).toBe(
|
||||||
"2017-08-12 15:00:00.000",
|
'2017-08-12 15:00:00.000',
|
||||||
);
|
);
|
||||||
|
|
||||||
const start_of_day = date_utils.start_of(date, "day");
|
const start_of_day = date_utils.start_of(date, 'day');
|
||||||
expect(date_utils.to_string(start_of_day, true)).toBe(
|
expect(date_utils.to_string(start_of_day, true)).toBe(
|
||||||
"2017-08-12 00:00:00.000",
|
'2017-08-12 00:00:00.000',
|
||||||
);
|
);
|
||||||
|
|
||||||
const start_of_month = date_utils.start_of(date, "month");
|
const start_of_month = date_utils.start_of(date, 'month');
|
||||||
expect(date_utils.to_string(start_of_month, true)).toBe(
|
expect(date_utils.to_string(start_of_month, true)).toBe(
|
||||||
"2017-08-01 00:00:00.000",
|
'2017-08-01 00:00:00.000',
|
||||||
);
|
);
|
||||||
|
|
||||||
const start_of_year = date_utils.start_of(date, "year");
|
const start_of_year = date_utils.start_of(date, 'year');
|
||||||
expect(date_utils.to_string(start_of_year, true)).toBe(
|
expect(date_utils.to_string(start_of_year, true)).toBe(
|
||||||
"2017-01-01 00:00:00.000",
|
'2017-01-01 00:00:00.000',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("format", () => {
|
test('format', () => {
|
||||||
const date = date_utils.parse("2017-08-12 15:07:23");
|
const date = date_utils.parse('2017-08-12 15:07:23');
|
||||||
expect(date_utils.format(date, "YYYY-MM-DD")).toBe("2017-08-12");
|
expect(date_utils.format(date, 'YYYY-MM-DD')).toBe('2017-08-12');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("format", () => {
|
test('format', () => {
|
||||||
const date = date_utils.parse("2016-02-29 16:08:34.3");
|
const date = date_utils.parse('2016-02-29 16:08:34.3');
|
||||||
expect(date_utils.format(date)).toBe("2016-02-29 16:08:34.300");
|
expect(date_utils.format(date)).toBe('2016-02-29 16:08:34.300');
|
||||||
});
|
});
|
||||||
|
|||||||
22
vite.config.js
Normal file
22
vite.config.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { resolve } from 'path';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: resolve(__dirname, 'src/index.js'),
|
||||||
|
name: 'Gantt',
|
||||||
|
fileName: 'frappe-gantt',
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
external: ['vue'],
|
||||||
|
output: {
|
||||||
|
globals: {
|
||||||
|
vue: 'Vue'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: { interop: 'auto' },
|
||||||
|
server: { watch: { include: ['dist/*', 'src/*'] } }
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user