Commit 8c20ef64 authored by ransome1's avatar ransome1
Browse files

Merge branch 'develop'

parents aa5051d0 550a9e19
......@@ -14,7 +14,7 @@
sleek is an open-source todo app that makes use of the todo.txt format. sleeks GUI is modern and simple but still offers a decent set of functions which help users getting things done. sleek is available as a client for Windows, MacOS and Linux.
Users can add contexts, projects, priorities, due dates or recurrences to their todos. These todo.txt attributes can then be used in full-text search, as filters or to group and sort the todo list.
Users can add contexts, projects, priorities, due dates, recurrences or threshold dates to their todos. These todo.txt attributes can then be used in full-text search, as filters or to group and sort the todo list.
sleek manages and watches multiple todo.txt files continuously for changes, which makes it easy to integrate sleek with other todo.txt apps. Also users can switch to dark mode and choose from multiple languages.
......@@ -47,6 +47,10 @@ Run it using: `flatpak run com.github.ransome1.sleek`
<a href="https://flathub.org/apps/details/com.github.ransome1.sleek" target="blank"><img width='180' alt="Download on Flathub" src="https://flathub.org/assets/badges/flathub-badge-en.png"/></a>
### Get sleek from Homebrew
Install sleek from <a href="https://formulae.brew.sh/cask/sleek" target="blank">Homebrew</a>.
`brew install --cask sleek`
### Get sleek from Arch User Repository
Install sleek from <a href="https://aur.archlinux.org/packages/sleek/" target="blank">AUR</a>.
1. Setup <a href="https://github.com/Jguer/yay#installation" target="blank">Yay</a>
......@@ -74,7 +78,8 @@ A prioritized backlog of new features and known issues can be found <a href="htt
- projects
- due dates
- start dates
- <a href="https://github.com/ransome1/sleek/wiki/Recurring-todos">recurrences</a>
- <a href="https://github.com/ransome1/sleek/wiki/Recurring-todos-(rec:)">recurrences</a>
- <a href="https://github.com/ransome1/sleek/wiki/Deferred-todos-(t:)">thresholds</a>
* Todo-List can be grouped and sorted by priorities, due dates, contexts or projects
* The sorting order can be defined on all 4 levels
* Todos can be filtered by contexts, projects and priorities
......
{
"name": "sleek",
"productName": "sleek",
"version": "1.0.8",
"version": "1.0.9",
"description": "Todo app based on todo.txt for Linux, Windows and MacOS, free and open-source",
"synopsis": "Todo app based on todo.txt for Linux, Windows and MacOS, free and open-source",
"category": "ProjectManagement",
......
name: sleek
base: core18
version: '1.0.8'
version: '1.0.9'
summary: Todo app based on the todo.txt format for Linux, free and open-source
description: |
sleek is an open-source todo app that makes use of the todo.txt format. sleeks GUI is modern and simple but still offers a decent set of functions which help users getting things done. sleek is available as a client for Windows, MacOS and Linux.
......
......@@ -3,7 +3,18 @@
https://codepen.io/fitri/full/oWovYj/ */
"use strict";
import { reorderSortingLevel } from "../render.js";
import { setUserData, startBuilding } from "../render.js";
function reorderSortingLevel() {
let sortBy = new Array;
const children = sortByContainer.children;
for(let i=0; i<children.length; i++) {
if(!children[i].getAttribute("data-id")) continue;
sortBy.push(children[i].getAttribute("data-id"));
}
setUserData("sortBy", sortBy);
startBuilding();
}
function enableDragSort(listClass) {
const sortableLists = document.getElementsByClassName(listClass);
......
......@@ -116,6 +116,12 @@ body.dark nav ul li a.is-highlighted {
border-bottom: none;
background-color: #3B3B3B;
}
body.dark nav ul:nth-child(2) #versionNumber {
color: #CCCDCF !important;
}
body.dark nav ul:nth-child(2) #versionNumber:hover {
color: #CCCDCF !important;
}
body.dark #drawerContainer .zoom svg {
color: white !important;
}
......@@ -259,9 +265,6 @@ body.dark #drawerContainer .drawer {
body.dark #drawerContainer .drawer h4.is-4 {
color: white;
}
body.dark #drawerContainer .drawer h4.is-4 i {
color: #CCCDCF !important;
}
body.dark #drawerContainer .drawer button span.tag {
color: #5a5a5a;
}
......@@ -520,11 +523,14 @@ body::-webkit-scrollbar {
display: none;
}
a,
a {
color: #3273dc;
}
a:hover,
a:active,
a:focus {
color: #3273dc !important;
color: #5a5a5a;
}
.is-active {
......@@ -879,6 +885,7 @@ nav ul {
nav ul li a,
nav ul li.logo {
width: 5em;
position: relative;
display: block;
height: 5em;
line-height: 5em;
......@@ -905,6 +912,59 @@ nav ul:nth-child(2) {
bottom: 0;
left: 0;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
nav ul:nth-child(2) #versionNumber {
width: auto !important;
padding: 0.1em;
display: none;
line-height: 1em;
position: fixed;
bottom: 0.2em;
z-index: 80;
margin-left: 7em;
font-size: 0.8em;
color: #ccc;
background: transparent !important;
opacity: 0;
animation: fadeOut 1s forwards;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
nav ul:nth-child(2):hover #versionNumber {
display: flex;
opacity: 0;
animation: fadeIn 1s forwards;
animation-delay: 0.5s;
}
#todoTableSearchContainer {
display: none;
......@@ -958,7 +1018,7 @@ nav ul:nth-child(2) {
top: 0.8em;
left: 1.4em;
z-index: 70;
padding: 0.75em 0.75em 0.75em 0;
padding: 0.75em 0;
}
@media screen and (max-width: 992px), screen and (max-height: 650px) {
......@@ -1042,6 +1102,9 @@ nav ul li.logo {
height: 3.5em;
line-height: 3.5em;
}
nav ul:nth-child(2) #versionNumber {
margin-left: 5em;
}
#autoCompleteContainer,
#drawerContainer .drawer {
......@@ -1053,7 +1116,11 @@ nav ul li.logo {
}
#autoCompleteContainer .priority button,
#drawerContainer .drawer .priority button {
font-size: 1em;
font-size: 1.2em;
}
#autoCompleteContainer .priority button .tag,
#drawerContainer .drawer .priority button .tag {
font-size: 0.65em;
}
#autoCompleteContainer button,
#drawerContainer .drawer button {
......@@ -1151,6 +1218,9 @@ body.compact nav ul li.logo {
height: 3.5em;
line-height: 3.5em;
}
body.compact nav ul:nth-child(2) #versionNumber {
margin-left: 5em;
}
body.compact #autoCompleteContainer,
body.compact #drawerContainer .drawer {
padding: 1.5em;
......@@ -1161,7 +1231,11 @@ body.compact #drawerContainer .drawer .is-4 {
}
body.compact #autoCompleteContainer .priority button,
body.compact #drawerContainer .drawer .priority button {
font-size: 1em;
font-size: 1.2em;
}
body.compact #autoCompleteContainer .priority button .tag,
body.compact #drawerContainer .drawer .priority button .tag {
font-size: 0.65em;
}
body.compact #autoCompleteContainer button,
body.compact #drawerContainer .drawer button {
......@@ -1407,28 +1481,31 @@ body.compact #autoCompleteContainer h4 {
#drawerContainer .drawer button.is-greyed-out .tag {
display: none;
}
#drawerContainer .drawer h4.is-4 {
#drawerContainer .drawer section {
width: 100%;
padding: 0;
margin: 0 0 1.5em 0;
}
#drawerContainer .drawer section h4.is-4 {
font-size: 1.25em;
font-family: FreeSansBold;
margin-bottom: 0em;
margin: 0 0 0.75em 0;
}
#drawerContainer .drawer h4.is-4.clickable {
#drawerContainer .drawer section h4.is-4.clickable {
cursor: pointer;
display: inline;
}
#drawerContainer .drawer h4.is-4.clickable i {
#drawerContainer .drawer section h4.is-4.clickable i {
color: #3273dc;
}
#drawerContainer .drawer h4.is-4.clickable::after {
#drawerContainer .drawer section h4.is-4.clickable::after {
height: 1em;
display: block;
content: "\a";
white-space: pre;
}
#drawerContainer .drawer section {
width: 100%;
padding: 0;
margin: 0 0 1.5em 0;
#drawerContainer .drawer section .todoFilterHint {
cursor: pointer;
}
#drawerContainer .drawer table tr td:nth-child(odd) {
width: auto;
......@@ -1482,10 +1559,11 @@ body.compact #autoCompleteContainer h4 {
z-index: 60;
margin: 0 !important;
}
.modal.content .title.is-3 {
.modal.content h3 {
font-family: "FreeSansBold";
font-size: 1.7em;
font-weight: normal;
margin-top: 0.5em;
}
.modal.content p {
display: block;
......@@ -1503,6 +1581,10 @@ body.compact #autoCompleteContainer h4 {
.modal.content select {
background: white !important;
}
.modal.content code {
background: transparent;
padding: 0;
}
.modal.content .delete,
.modal.content .modal-close {
background: #3273dc !important;
......@@ -1517,9 +1599,6 @@ body.compact #autoCompleteContainer h4 {
max-height: calc(100vh - 5em);
border-radius: 0.65em;
}
.modal.content .modal-background {
z-index: 55;
}
.modal.content .modal-card-body {
background: none;
display: none;
......
This diff is collapsed.
......@@ -31,7 +31,12 @@
</ul>
<ul>
<li><a href="#" id="navBtnSettings" tabindex="-1"><i class="fas fa-cog"></i></a></li>
<li><a href="#" id="navBtnHelp" tabindex="-1"><i class="fas fa-question-circle"></i></a></li>
<li>
<a href="#" id="navBtnHelp" tabindex="-1">
<i class="fas fa-question-circle"></i>
<code id="versionNumber"></code>
</a>
</li>
</ul>
<div id="drawerContainer">
<section id="filterDrawer" class="drawer dropdown" tabindex="0">
......@@ -118,6 +123,17 @@
</span>
</td>
</tr>
<tr>
<td><span id="viewToggleDeferredTodos"></span> <a href="https://github.com/ransome1/sleek/wiki/Deferred-todos-(t:)" target="_blank"><i class="fas fa-question-circle"></i></a></td>
<td>
<span class="toggle">
<label class="switch" for="deferredTodos">
<input type="checkbox" id="deferredTodos" class="viewToggle" tabindex="0">
<span class="slider round"></span>
</label>
</span>
</td>
</tr>
<tr>
<th colspan="100%">
<h3 id="viewHeadlineFilterList" class="is-3"></h3>
......@@ -235,7 +251,7 @@
</div>
</div>
<section id="modalForm" class="modal">
<section id="modalForm" class="modal" data-item="">
<div class="modal-background"></div>
<div class="modal-content">
<div class="card">
......@@ -351,10 +367,10 @@
<div id="modalSettings" class="modal content" tabindex="0">
<div class="modal-background"></div>
<div class="modal-card">
<div class="tabs is-centered">
<div class="tabs is-centered" style="display: none;">
<ul>
<li class="settingsTab1 is-active"><a href="#" tabindex="0" id="settingsTabSettings"></a></li>
<li class="settingsTab2"><a href="#" tabindex="0" id="settingsTabAbout"></a></li>
<!--<li class="settingsTab2"><a href="#" tabindex="0" id="settingsTabAbout"></a></li>-->
</ul>
</div>
<section id="settingsTab1" class="modal-card-body" data-track-content data-content-name="Settings" data-content-piece="Settings">
......@@ -427,7 +443,7 @@
</tr>
</table>
</section>
<section id="settingsTab2" class="modal-card-body" data-track-content data-content-name="Settings" data-content-piece="About">
<!--<section id="settingsTab2" class="modal-card-body" data-track-content data-content-name="Settings" data-content-piece="About">
<h3 class="title is-3" id="settingsTabAboutHeadline"></h3>
<table>
<tr>
......@@ -490,12 +506,12 @@
</tr>
</table>
<p><code>v<span id="version"></span></code></p>
</section>
</section>-->
<button class="modal-close close is-large" aria-label="close" tabindex="0"></button>
</div>
</div>
<div id="modalHelp" class="modal content" tabindex="0" data-track-content data-content-name="Help" data-content-piece="Keyboard shortcuts">
<div id="modalHelp" class="modal content" tabindex="0">
<div class="modal-background"></div>
<div class="modal-card">
<div class="tabs is-centered">
......@@ -505,9 +521,10 @@
<li class="helpTab3"><a href="#" tabindex="0" id="helpTab3Title"></a></li>
<li class="helpTab4"><a href="#" tabindex="0" id="helpTab4Title"></a></li>
<li class="helpTab5"><a href="#" tabindex="0" id="helpTab5Title"></a></li>
<li class="helpTab6"><a href="#" tabindex="0" id="settingsTabAbout"></a></li>
</ul>
</div>
<section id="helpTab1" class="modal-card-body is-active">
<section id="helpTab1" class="modal-card-body is-active" data-track-content data-content-name="Help" data-content-piece="Keyboard shortcuts">
<h3 class="title is-3" id="helpTabKeyboardTitle"></h3>
<table class="shortcuts">
<tr>
......@@ -643,6 +660,70 @@
</div>
</div>
</section>
<section id="helpTab6" class="modal-card-body" data-track-content data-content-name="Help" data-content-piece="About">
<h3 class="title is-3" id="settingsTabAboutHeadline"></h3>
<p><code>Current version: <span id="version"></span></code></p>
<table>
<tr>
<th colspan="100%" id="settingsTabAboutContribute"></th>
</tr>
<tr>
<td><i class="fab fa-github"></i></td>
<td><a href="https://github.com/ransome1/sleek/issues" target="_blank" id="submitIssuesOnGithub"></a></td>
<td><i class="fas fa-star"></i></td>
<td><a href="https://sourceforge.net/projects/sleek/reviews" target="_blank" id="reviewSourceforge"></a></td>
<td><i class="fab fa-windows"></i></td>
<td><a href="https://www.microsoft.com/store/apps/9NWM2WXF60KR" target="_blank" id="reviewWindowsStore"></a></td>
</tr>
<tr>
<td><i class="fab fa-twitter"></i></td>
<td><a href="https://twitter.com/intent/tweet?text=Check%20out%20sleek,%20a%20todo%20app%20based%20on%20todo.txt,%20free%20and%20open-source.%20Available%20for%20Linux,%20Windows%20and%20MacOS.%20https://github.com/ransome1/sleek" target="_blank" id="shareTwitter"></a></td>
<td><i class="fab fa-facebook"></i></td>
<td><a href="https://www.facebook.com/sharer/sharer.php?u=https://github.com/ransome1/sleek" target="_blank" id="shareFacebook"></a></td>
<td><i class="fab fa-linkedin"></i></td>
<td><a href="https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/ransome1/sleek" target="_blank" id="shareLinkedin"></a></td>
</tr>
</table>
<table>
<tr>
<th colspan="100%" id="settingsTabAboutCopyrightLicense"></th>
</tr>
<tr>
<td colspan="100%" id="settingsTabAboutCopyrightLicenseBody"></td>
</tr>
</table>
<table>
<tr>
<th colspan="100%" id="settingsTabAboutPrivacy"></th>
</tr>
<tr>
<td colspan="100%" id="settingsTabAboutPrivacyBody"></td>
</tr>
</table>
<table>
<tr>
<th colspan="100%" id="settingsTabAboutExternalLibraries"></th>
</tr>
<tr>
<td><a href="https://github.com/electron/electron" target="_blank">Electron</a></td>
<td><a href="https://github.com/electron-userland/electron-builder" target="_blank">Electron builder</a></td>
<td><a href="https://github.com/i18next/i18next" target="_blank">i18next</a></td>
<td><a href="https://github.com/mymth/vanillajs-datepicker" target="_blank">vanillajs-datepicker</a></td>
</tr>
<tr>
<td><a href="https://github.com/jgthms/bulma" target="_blank">Bulma CSS</a></td>
<td><a href="https://github.com/FortAwesome/Font-Awesome" target="_blank">Font Awesome</a></td>
<td><a href="https://github.com/jmhobbs/jsTodoTxt" target="_blank">jsTodoTxt</a></td>
<td><a href="https://github.com/markedjs/marked" target="_blank">Marked</a></td>
</tr>
<tr>
<td><a href="https://github.com/matomo-org/matomo" target="_blank">Matomo</a></td>
<td><a href="https://github.com/paulmillr/chokidar" target="_blank">chokidar</a></td>
<td><a href="https://github.com/viktor-shmigol/electron-windows-badge/" target="_blank">Electron Windows Badge</a></td>
<td><a href="https://github.com/andrewplummer/Sugar" target="_blank">Sugar</a></td>
</tr>
</table>
</section>
<button class="modal-close close is-large" aria-label="close" tabindex="0"></button>
</div>
</div>
......
......@@ -50,11 +50,7 @@ const settingsTabAboutHeadline = document.getElementById("settingsTabAboutHeadli
const settingsTabAboutPrivacy = document.getElementById("settingsTabAboutPrivacy");
const settingsTabAboutPrivacyBody = document.getElementById("settingsTabAboutPrivacyBody");
const settingsTabSettings = document.getElementById("settingsTabSettings");
//const settingsTabSettingsArchive = document.getElementById("settingsTabSettingsArchive");
//const settingsTabSettingsArchiveBody = document.getElementById("settingsTabSettingsArchiveBody");
//const settingsTabSettingsArchiveButton = document.getElementById("settingsTabSettingsArchiveButton");
const settingsTabSettingsDarkmode = document.getElementById("settingsTabSettingsDarkmode");
//const settingsTabSettingsDarkmodeBody = document.getElementById("settingsTabSettingsDarkmodeBody");
const settingsTabSettingsHeadline = document.getElementById("settingsTabSettingsHeadline");
const settingsTabSettingsLanguage = document.getElementById("settingsTabSettingsLanguage");
const settingsTabSettingsLanguageBody = document.getElementById("settingsTabSettingsLanguageBody");
......@@ -117,9 +113,7 @@ settingsTabAboutExternalLibraries.innerHTML = translations.settingsTabAboutExter
settingsTabAboutHeadline.innerHTML = translations.about;
settingsTabAboutPrivacy.innerHTML = translations.settingsTabAboutPrivacy;
settingsTabAboutPrivacyBody.innerHTML = translations.settingsTabAboutPrivacyBody;
settingsTabSettings.innerHTML = translations.settings;
//settingsTabSettingsArchive.innerHTML = translations.settingsTabSettingsArchive;
//settingsTabSettingsArchiveButton.innerHTML = translations.archive;
//settingsTabSettings.innerHTML = translations.settings;
settingsTabSettingsDarkmode.innerHTML = translations.darkmode;
settingsTabSettingsHeadline.innerHTML = translations.settings;
settingsTabSettingsLanguage.innerHTML = translations.language;
......@@ -248,7 +242,7 @@ function setFriendlyLanguageNames() {
default:
return;
}
var option = document.createElement("option");
let option = document.createElement("option");
option.text = friendlyLanguageName;
option.value = language;
if(language===userData.language) option.selected = true;
......
......@@ -2,7 +2,7 @@
import { translations, userData } from "../render.js";
import { _paq } from "./matomo.mjs";
import { resizeInput } from "./form.mjs";
import { RecExtension, SugarDueExtension } from "./todotxtExtensions.mjs";
import { RecExtension, SugarDueExtension, ThresholdExtension } from "./todotxtExtensions.mjs";
import "../../node_modules/jstodotxt/jsTodoExtensions.js";
import "../../node_modules/jstodotxt/jsTodoTxt.js";
import Datepicker from "../../node_modules/vanillajs-datepicker/js/Datepicker.js";
......@@ -21,7 +21,7 @@ datePickerInput.addEventListener("changeDate", function (e) {
// we only update the object if there is a date selected. In case of a refresh it would throw an error otherwise
if(e.detail.date) {
// generate the object on what is written into input, so we don't overwrite previous inputs of user
let todo = new TodoTxtItem(document.getElementById("modalFormInput").value, [ new SugarDueExtension(), new HiddenExtension(), new RecExtension() ]);
let todo = new TodoTxtItem(document.getElementById("modalFormInput").value, [ new SugarDueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension() ]);
todo.due = new Date(e.detail.date);
todo.dueString = new Date(e.detail.date.getTime() - (e.detail.date.getTimezoneOffset() * 60000 )).toISOString().split("T")[0];
// if suggestion box was open, it needs to be closed
......@@ -53,7 +53,7 @@ const datePicker = new Datepicker(datePickerInput, {
}
});
document.querySelector(".datepicker .clear-btn").onclick = function() {
let todo = new TodoTxtItem(document.getElementById("modalFormInput").value, [ new SugarDueExtension(), new HiddenExtension(), new RecExtension() ]);
let todo = new TodoTxtItem(document.getElementById("modalFormInput").value, [ new SugarDueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension() ]);
todo.due = undefined;
todo.dueString = undefined;
document.getElementById("modalFormInput").value = todo.toString();
......
......@@ -21,7 +21,6 @@ const getPaneWidth = () => {
};
export const startDragging = (event) => {
event.preventDefault();
//const host = getResizeableElement();
const startingPaneWidth = getPaneWidth();
const xOffset = event.pageX;
const mouseDragHandler = (moveEvent) => {
......
This diff is collapsed.
......@@ -50,6 +50,7 @@ NotOp
comparison
= left:priorityComparison { return left; }
/ left:dueComparison { return left; }
/ left:thresholdComparison { return left; }
priorityComparison
= priorityKeyword _ op:compareOp _ right:priorityLiteral { return ["pri", right, op]; }
......@@ -67,8 +68,17 @@ dueComparison
/ "due:" right:dateStr { return ["duestr", right]; }
/ "due" { return ["due"]; }
thresholdComparison
= "t" _ op:compareOp _ right:dateExpr { return ["threshold"].concat(right, [op]); }
/ "t:" right:dateStr { return ["tstr", right]; }
/ "t" { return ["threshold"]; }
dateExpr
= left:dateLiteral _ op:dateOp _ count:number unit:[dbwmy] {
if (count.length == 0) {
/* empty count string means default "1" value */
count = 1;
}
if (op == "-") {
count = count * -1;
}
......@@ -99,19 +109,19 @@ dateStr
dateLiteral
= year:number4 "-" month: number2 "-" day:number2 {
let d = new Date(year, month-1, day);
return d.getTime();
let m = month > 0 ? (month <= 12 ? month-1 : 11) : 0;
let d = day > 0 ? (day <= 31 ? day : 31) : 1; /* ignores lengths of months */
return new Date(year, m, d).getTime();
}
/ year:number4 "-" month: number2 {
let d = new Date(year, month-1, 1);
return d.getTime();
let m = month > 0 ? (month <= 12 ? month-1 : 11) : 0;
return new Date(year, m, 1).getTime();
}
/ year:number4 {
let d = new Date(year, 0, 1);
return d.getTime();
return new Date(year, 0, 1).getTime();
}
/ "today" {
let d = new Date(); // now, w current time of day
let d = new Date(); // now, w current time of day
d = new Date(d.getFullYear(), d.getMonth(), d.getDate());
return d.getTime();
}
......@@ -130,10 +140,10 @@ number4
= [0-9][0-9][0-9][0-9] { return text(); }
number2
= [0-9][0-9] { return text(); }
= [0-9][0-9]? { return text(); }
number
= [0-9]+ { return text(); }
= [0-9]* { return text(); } /* used in date intervals only */
StringLiteral "string"
= '"' chars:DoubleStringCharacter* '"'? {
......@@ -167,9 +177,9 @@ SourceCharacter
= .
name
= '"' nonblank+ '"' { return text(); }
/ nonblankparen+ '"' { return '"' + text(); }
/ nonblankparen+ { return text(); }
= '"' nonblank+ '"' { return text(); }
/ nonblankparen+ '"' { return '"' + text(); }
/ nonblankparen+ { return text(); }
nonblank
= [^ \t\n\r"]
......@@ -178,4 +188,4 @@ nonblankparen
= [^ \t\n\r"()]
_ "whitespace"
= [ \t\n\r]*
= [ \t\n\r]*
......@@ -41,6 +41,29 @@ function runQuery(item, compiledQuery) {
stack.push(false); // no due date
}
break;
case "threshold":
if (item.t) {
// normalize date to have time of midnight in local zone
// we represent dates as millisec from epoch to simplify comparison
let d = item.t;
stack.push(new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime());
} else {
stack.push(undefined); // all comparisons will return false
}
break;