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

Merge branch 'develop'

parents cadc2bf9 2dd23de7
{
"name": "sleek",
"productName": "sleek",
"version": "1.0.6-1",
"version": "1.0.6-2",
"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.6'
version: '1.0.6-2'
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.
......
......@@ -498,14 +498,19 @@ button, button:focus, button:active, button:active, button:after, button::before
}
.button.is-greyed-out {
filter: opacity(75%) grayscale(100%);
cursor: not-allowed;
}
.is-greyed-out {
filter: opacity(75%) grayscale(100%);
}
.is-greyed-out .tag {
display: none;
}
table {
width: 100%;
border-collapse: separate;
margin-bottom: 2em;
}
table tr th {
padding: 0.1em 0 !important;
......@@ -824,6 +829,9 @@ nav ul:nth-child(2) {
padding: 0;
margin: 0 0 1.5em 0;
}
#drawerContainer .drawer table {
margin-bottom: 2em;
}
#drawerContainer .drawer table tr td:nth-child(odd) {
width: auto;
vertical-align: middle;
......@@ -939,6 +947,7 @@ nav ul:nth-child(2) {
display: flex;
}
#todoTable .cell {
line-height: 1.7em;
padding: 0.75em 0;
margin-right: 1em;
height: auto;
......@@ -956,9 +965,6 @@ nav ul:nth-child(2) {
#todoTable .cell span.tag.contexts {
background: #c5ede3;
}
#todoTable .cell.archive {
line-height: 1.6em;
}
#todoTable .cell.checkbox a {
flex: 0 0 1em;
font-size: 1.25em;
......@@ -966,7 +972,6 @@ nav ul:nth-child(2) {
#todoTable .cell.text {
width: auto;
flex: 1;
line-height: 1.7em;
color: #4a4a4a;
margin-right: 0;
}
......@@ -1026,7 +1031,7 @@ nav ul:nth-child(2) {
#todoTable .cell.itemDueDate .fa-sort-down {
position: absolute;
right: 0.2em;
bottom: 2.2em;
bottom: 2.1em;
display: none;
}
#todoTable .cell.itemDueDate .tags {
......@@ -1189,6 +1194,7 @@ nav ul:nth-child(2) {
}
#todoContext a {
color: #3273dc;
padding: 0.75em 1em;
}
#todoContext.is-active {
......@@ -1293,6 +1299,7 @@ nav ul:nth-child(2) {
}
.priority .button {
font-size: 1.2em;
font-family: FreeSansBold;
background: #ccc;
color: #666666;
......@@ -1602,18 +1609,26 @@ nav ul:nth-child(2) {
line-height: 3.5em;
}
.drawer {
#autoCompleteContainer,
.drawer {
padding: 1.5em;
}
.drawer .is-4 {
#autoCompleteContainer .is-4,
.drawer .is-4 {
font-size: 1.1em;
}
.drawer .button {
#autoCompleteContainer .priority .button,
.drawer .priority .button {
font-size: 1em;
}
#autoCompleteContainer .button,
.drawer .button {
font-size: 0.9em;
margin: 0 0.25em 0.25em 0 !important;
margin: 0 0.3em 0.3em 0 !important;
padding: 0.25em 0.6em;
}
.drawer .button .tag {
#autoCompleteContainer .button .tag,
.drawer .button .tag {
padding: 0 0.5em;
width: auto;
height: auto;
......@@ -1621,6 +1636,13 @@ nav ul:nth-child(2) {
min-height: 1.5em;
font-size: 0.9em;
}
#autoCompleteContainer {
padding: 1em;
}
#autoCompleteContainer h4 {
margin-top: 0;
}
}
body.compact #todoTableSearchContainer {
padding: 1em;
......@@ -1658,17 +1680,25 @@ body.compact nav ul li {
height: 3.5em;
line-height: 3.5em;
}
body.compact #autoCompleteContainer,
body.compact .drawer {
padding: 1.5em;
}
body.compact #autoCompleteContainer .is-4,
body.compact .drawer .is-4 {
font-size: 1.1em;
}
body.compact #autoCompleteContainer .priority .button,
body.compact .drawer .priority .button {
font-size: 1em;
}
body.compact #autoCompleteContainer .button,
body.compact .drawer .button {
font-size: 0.9em;
margin: 0 0.25em 0.25em 0 !important;
margin: 0 0.3em 0.3em 0 !important;
padding: 0.25em 0.6em;
}
body.compact #autoCompleteContainer .button .tag,
body.compact .drawer .button .tag {
padding: 0 0.5em;
width: auto;
......@@ -1677,6 +1707,12 @@ body.compact .drawer .button .tag {
min-height: 1.5em;
font-size: 0.9em;
}
body.compact #autoCompleteContainer {
padding: 1em;
}
body.compact #autoCompleteContainer h4 {
margin-top: 0;
}
.datepicker {
display: none;
......
This diff is collapsed.
......@@ -248,7 +248,7 @@
<div class="content">
<div class="control has-icons-right">
<input id="modalFormInput" class="input is-medium" type="text" tabindex="0">
<div id="autoCompleteContainer" class="drawer card"></div>
<div id="autoCompleteContainer" class="card"></div>
<a href="#" id="modalFormInputResize" class="icon is-right" tabindex="-1" data-input-type="input">
<i class="fas fa-expand-alt"></i>
</a>
......
......@@ -11,13 +11,13 @@ const navBtnView = document.getElementById("navBtnView");
const drawers = document.querySelectorAll("nav ul li.drawerTrigger");
if(userData.filterDrawer) {
showDrawer(document.getElementById("navBtnFilter"), document.getElementById("navBtnFilter").getAttribute("data-drawer")).then(function(result) {
show(document.getElementById("navBtnFilter"), document.getElementById("navBtnFilter").getAttribute("data-drawer")).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
});
} else if(userData.viewDrawer) {
showDrawer(document.getElementById("navBtnView"), document.getElementById("navBtnView").getAttribute("data-drawer")).then(function(result) {
show(document.getElementById("navBtnView"), document.getElementById("navBtnView").getAttribute("data-drawer")).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
......@@ -25,7 +25,7 @@ if(userData.filterDrawer) {
}
document.getElementById("drawerClose").onclick = function() {
showDrawer(null, null, true).then(function(result) {
show(null, null, true).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
......@@ -35,7 +35,7 @@ document.getElementById("drawerClose").onclick = function() {
}
document.getElementById("filterDrawer").addEventListener ("keydown", function () {
if(event.key === "Escape") {
showDrawer(false, navBtnFilter.id, this.id).then(function(result) {
show(false, navBtnFilter.id, this.id).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
......@@ -44,7 +44,7 @@ document.getElementById("filterDrawer").addEventListener ("keydown", function ()
});
document.getElementById("viewDrawer").addEventListener ("keydown", function () {
if(event.key === "Escape") {
showDrawer(false, document.getElementById("navBtnView").id, this.id).then(function(result) {
show(false, document.getElementById("navBtnView").id, this.id).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
......@@ -53,7 +53,7 @@ document.getElementById("viewDrawer").addEventListener ("keydown", function () {
});
getHandleElement.addEventListener("mousedown", startDragging);
navBtnFilter.onclick = function() {
showDrawer(this, this.getAttribute("data-drawer")).then(function(result) {
show(this, this.getAttribute("data-drawer")).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
......@@ -62,7 +62,7 @@ navBtnFilter.onclick = function() {
if(userData.matomoEvents) _paq.push(["trackEvent", "Menu", "Click on filter"]);
}
navBtnView.onclick = function() {
showDrawer(this, this.getAttribute("data-drawer")).then(function(result) {
show(this, this.getAttribute("data-drawer")).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
......@@ -71,13 +71,13 @@ navBtnView.onclick = function() {
if(userData.matomoEvents) _paq.push(["trackEvent", "Menu", "Click on view"]);
}
export function showDrawer(button, drawer, close) {
export function show(button, drawer, close) {
try {
// close drawers and the container and persist it
if(close) {
drawerContainer.classList.remove("is-active");
drawers.forEach((item) => {
item.classList.remove("is-highlighted");
drawerContainer.classList.remove("is-active");
document.getElementById(item.getAttribute("data-drawer")).classList.remove("is-active");
setUserData(item.getAttribute("data-drawer"), false);
});
......@@ -104,7 +104,7 @@ export function showDrawer(button, drawer, close) {
return Promise.resolve("Success: Drawer opened");
}
} catch(error) {
error.functionName = showDrawer.name;
error.functionName = show.name;
return Promise.reject(error);
}
}
......@@ -13,6 +13,7 @@ const filterContextSave = document.getElementById("filterContextSave");
const filterContextDelete = document.getElementById("filterContextDelete");
let categories,
filterCounter = 0,
filtersCounted,
filtersCountedReduced,
selectedFilters,
......@@ -132,6 +133,8 @@ function filterItems(items) {
}
function generateFilterData(autoCompleteCategory, autoCompleteValue, autoCompletePrefix, caretPosition) {
try {
// reset filter counter
filterCounter = 0;
// select the container (filter drawer or autocomplete) in which filters will be shown
if(autoCompleteCategory) {
container = autoCompleteContainer;
......@@ -286,6 +289,7 @@ function selectFilter(filter, category) {
}
function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix, caretPosition) {
try {
let hideFilterCategories = userData.hideFilterCategories;
selectedFilters = new Array;
if(userData.selectedFilters && userData.selectedFilters.length>0) selectedFilters = JSON.parse(userData.selectedFilters);
// creates a div for the specific filter section
......@@ -302,25 +306,27 @@ function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix,
if(autoCompletePrefix===undefined && userData.showEmptyFilters) {
// create a sub headline element
let todoFilterHeadline = document.createElement("h4");
todoFilterHeadline.setAttribute("class", "is-4 title clickable");
todoFilterHeadline.innerHTML = "<i class=\"far fa-eye-slash\" tabindex=\"-1\"></i>&nbsp;" + headline;
todoFilterHeadline.setAttribute("class", "is-4 clickable");
// setup greyed out state
if(hideFilterCategories.includes(category)) {
todoFilterHeadline.innerHTML = "<i class=\"far fa-eye\" tabindex=\"-1\"></i>&nbsp;" + headline;
todoFilterHeadline.classList.add("is-greyed-out");
} else {
todoFilterHeadline.innerHTML = "<i class=\"far fa-eye-slash\" tabindex=\"-1\"></i>&nbsp;" + headline;
todoFilterHeadline.classList.remove("is-greyed-out");
}
// add click event
todoFilterHeadline.onclick = function() {
document.getElementById("todoTableWrapper").scrollTo(0,0);
let hideFilterCategories = userData.hideFilterCategories;
if(hideFilterCategories.includes(category)) {
hideFilterCategories.splice(hideFilterCategories.indexOf(category),1)
this.parentElement.classList.remove("is-greyed-out");
this.innerHTML = "<i class=\"far fa-eye-slash\" tabindex=\"-1\"></i>&nbsp;" + headline;
} else {
hideFilterCategories.push(category);
this.parentElement.classList.add("is-greyed-out");
this.innerHTML = "<i class=\"far fa-eye\" tabindex=\"-1\"></i>&nbsp;" + headline;
hideFilterCategories = [...new Set(hideFilterCategories.join(",").split(","))];
}
setUserData("hideFilterCategories", hideFilterCategories)
startBuilding();
}
// add click event
// add the headline before category container
todoFiltersContainer.appendChild(todoFilterHeadline);
} else {
......@@ -332,7 +338,7 @@ function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix,
}
todoFilterHeadline.setAttribute("tabindex", -1);
// create a sub headline element
todoFilterHeadline.setAttribute("class", "is-4 title");
todoFilterHeadline.setAttribute("class", "is-4");
// no need for tab index if the headline is in suggestion box
//if(autoCompletePrefix==undefined)
todoFilterHeadline.innerHTML = headline;
......@@ -407,6 +413,7 @@ function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix,
if(userData.matomoEvents) _paq.push(["trackEvent", "Filter-Drawer", "Click on filter tag", category]);
});
} else {
todoFiltersItem.disabled = true;
todoFiltersItem.classList.add("is-greyed-out");
todoFiltersItem.innerHTML += " <span class=\"tag is-rounded\">0</span>";
}
......@@ -430,6 +437,7 @@ function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix,
if(userData.matomoEvents) _paq.push(["trackEvent", "Suggestion-box", "Click on filter tag", category]);
});
}
filterCounter++;
todoFiltersContainer.appendChild(todoFiltersItem);
}
return Promise.resolve(todoFiltersContainer);
......@@ -439,4 +447,4 @@ function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix,
}
}
export { filterItems, generateFilterData, selectFilter, categories };
export { filterItems, generateFilterData, selectFilter, categories, filterCounter };
......@@ -50,7 +50,7 @@ const todoTableBodyCellCheckboxTemplate = document.createElement("div");
const todoTableBodyCellTextTemplate = document.createElement("a");
const tableContainerCategoriesTemplate = document.createElement("span");
const todoTableBodyCellPriorityTemplate = document.createElement("div");
const todoTableBodyCellSpacerTemplate = document.createElement("div");
//const todoTableBodyCellSpacerTemplate = document.createElement("div");
const todoTableBodyCellDueDateTemplate = document.createElement("span");
const todoTableBodyCellRecurrenceTemplate = document.createElement("span");
const todoTableBodyCellArchiveTemplate = document.createElement("span");
......@@ -243,7 +243,7 @@ function generateTableRow(todo) {
let todoTableBodyCellText = todoTableBodyCellTextTemplate.cloneNode(true);
let tableContainerCategories = tableContainerCategoriesTemplate.cloneNode(true);
let todoTableBodyCellPriority = todoTableBodyCellPriorityTemplate.cloneNode(true);
let todoTableBodyCellSpacer = todoTableBodyCellSpacerTemplate.cloneNode(true);
//let todoTableBodyCellSpacer = todoTableBodyCellSpacerTemplate.cloneNode(true);
let todoTableBodyCellDueDate = todoTableBodyCellDueDateTemplate.cloneNode(true);
let todoTableBodyCellRecurrence = todoTableBodyCellRecurrenceTemplate.cloneNode(true);
let todoTableBodyCellArchive = todoTableBodyCellArchiveTemplate.cloneNode(true);
......@@ -261,10 +261,10 @@ function generateTableRow(todo) {
if(todo.priority && userData.sortBy==="priority") {
todoTableBodyCellPriority.setAttribute("class", "cell priority " + todo.priority);
todoTableBodyRow.appendChild(todoTableBodyCellPriority);
} else if(!todo.priority && userData.sortBy==="priority") {
} /*else if(!todo.priority && userData.sortBy==="priority") {
todoTableBodyCellSpacer.setAttribute("class", "cell spacer");
todoTableBodyRow.appendChild(todoTableBodyCellSpacer);
}
}*/
// add the checkbox
if(todo.complete==true) {
todoTableBodyCellCheckbox.setAttribute("title", translations.inProgress);
......
......@@ -128,7 +128,7 @@ function configureMainView() {
// jump to previously added item
if(document.getElementById("previousItem")) jumpToItem(document.getElementById("previousItem"))
// show add todo buttons
navBtnAddTodo.classList.remove("is-hidden");
//navBtnAddTodo.classList.remove("is-hidden");
//btnAddTodo.forEach(item => item.classList.remove("is-hidden"));
// remove onboarding
showOnboarding(false).then(function(response) {
......@@ -138,7 +138,20 @@ function configureMainView() {
});
// check if archive button should be enabled
setButtonState("btnArchiveTodos");
// file is defined, but content is empty
// configure navigation
if(filters.filterCounter===0) {
// hide filter nav button
navBtnFilter.classList.add("is-hidden");
// close filter drawer
drawer.show(navBtnFilter, document.getElementById(navBtnFilter.getAttribute("data-drawer")), true).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
});
} else {
navBtnFilter.classList.remove("is-hidden");
}
// configure table view
if(userData.file && todos.items.objects.length===0) {
addTodoContainer.classList.add("is-active");
todoTableSearchContainer.classList.remove("is-active");
......@@ -149,7 +162,6 @@ function configureMainView() {
addTodoContainer.classList.remove("is-active");
todoTableSearchContainer.classList.add("is-active");
noResultContainer.classList.add("is-active");
navBtnFilter.classList.add("is-hidden");
return Promise.resolve("Info: No results");
// TODO explain
} else if(userData.file && todos.items.filtered.length>0) {
......@@ -474,7 +486,7 @@ function registerKeyboardShortcuts() {
}
// show filter drawer
if(event.key==="b" && !modalForm.classList.contains("is-active") && (document.activeElement.id!="todoTableSearch" && document.activeElement.id!="filterContextInput" && document.activeElement.id!="modalFormInput")) {
drawer.showDrawer(document.getElementById("navBtnFilter"), document.getElementById("navBtnFilter").getAttribute("data-drawer")).then(function(result) {
drawer.show(document.getElementById("navBtnFilter"), document.getElementById("navBtnFilter").getAttribute("data-drawer")).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
......@@ -789,6 +801,7 @@ window.onload = async function () {
translations = await getTranslations();
todos = await import("./js/todos.mjs");
filters = await import("./js/filters.mjs");
drawer = await import("./js/drawer.mjs");
if(userData.file) {
window.api.send("startFileWatcher", userData.file);
// for users who upgrade from very old versions
......@@ -828,7 +841,6 @@ window.onload = async function () {
});
form = await import("./js/form.mjs");
content = await import("./js/content.mjs");
drawer = await import("./js/drawer.mjs");
view = await import("./js/view.mjs");
import("./js/navigation.mjs");
import("./js/files.mjs");
......@@ -871,7 +883,7 @@ window.api.receive("triggerFunction", (name, args) => {
getConfirmation(todos.archiveTodos, translations.archivingPrompt);
break;
case "showDrawer":
drawer.showDrawer(...args).then(function(response) {
drawer.show(...args).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
......
......@@ -45,13 +45,17 @@ button, button:focus, button:active, button:active, button:after, button::before
color: white;
}
.button.is-greyed-out {
filter: opacity(75%) grayscale(100%);
cursor: not-allowed;
}
.is-greyed-out {
filter: opacity(75%) grayscale(100%);
.tag {
display: none;
}
}
table {
width: 100%;
border-collapse:separate;
margin-bottom: 2em;
tr {
th {
padding: .1em 0 !important;
......@@ -351,6 +355,9 @@ nav {
padding: 0;
margin: 0 0 1.5em 0;
}
table {
margin-bottom: 2em;
}
table tr td:nth-child(odd) {
width: auto;
vertical-align: middle;
......@@ -463,6 +470,7 @@ nav {
display: flex;
}
.cell {
line-height: 1.7em;
padding: .75em 0;
margin-right: 1em;
height: auto;
......@@ -471,7 +479,7 @@ nav {
background: none;
}
span.tag {
margin: 0 .25em 0 0;
margin: 0 0.25em 0 0;
}
span.tag.projects {
background: $sleek-projects-button;
......@@ -480,9 +488,6 @@ nav {
background: $sleek-contexts-button;
}
}
.cell.archive {
line-height: 1.6em;
}
.cell.checkbox a {
flex: 0 0 1em;
font-size: 1.25em;
......@@ -490,7 +495,6 @@ nav {
.cell.text {
width: auto;
flex: 1;
line-height: 1.7em;
color: $dark-grey;
margin-right: 0;
.categories {
......@@ -549,7 +553,7 @@ nav {
.fa-sort-down {
position: absolute;
right: 0.2em;
bottom: 2.2em;
bottom: 2.1em;
display: none;
}
.tags {
......@@ -709,6 +713,7 @@ nav {
z-index: 60;
a {
color: $has-text-link;
padding: 0.75em 1em;
}
}
#todoContext.is-active {
......@@ -810,6 +815,7 @@ nav {
}
.priority {
.button {
font-size: 1.2em;
font-family: FreeSansBold;
background: $mid-grey;
color: darken($mid-grey, 40%);
......@@ -1120,14 +1126,20 @@ nav {
line-height: 3.5em;
}
}
#autoCompleteContainer,
.drawer {
padding: 1.5em;
.is-4 {
font-size: 1.1em;
}
.priority {
.button {
font-size: 1em;
}
}
.button {
font-size: 0.9em;
margin: 0 0.25em 0.25em 0!important;
margin: 0 0.3em 0.3em 0!important;
padding: 0.25em 0.6em;
.tag {
padding: 0 .5em;
......@@ -1139,6 +1151,12 @@ nav {
}
}
}
#autoCompleteContainer {
padding: 1em;
h4 {
margin-top: 0;
}
}
}
@media screen and (max-width: 992px),
screen and (max-height: 650px) {
......
......@@ -37,17 +37,16 @@ describe("Navigation", function () {
it("Theme is switched to dark and back to light", async () => {
let themeLink = await app.client.$("#themeLink");
let href = await themeLink.getAttribute("href");
const btnTheme = await app.client.$("#btnTheme");
setTimeout(async () => {
btnTheme.click();
if(!href.includes("dark.css")) throw new Error("Could not switch to dark theme");
btnTheme.click();
themeLink = await app.client.$("#themeLink");
href = await themeLink.getAttribute("href");
if(href.includes("dark.css")) throw new Error("Could not switch to light theme");
}, 1000);
await btnTheme.waitForClickable({ timeout: 10000 });
btnTheme.click();
let body = await app.client.$("body");
let bodyClassList = await body.getAttribute("class");
if(bodyClassList.search("dark")===-1) throw new Error("Could not switch to dark theme");
btnTheme.click();
body = await app.client.$("body");
bodyClassList = await body.getAttribute("class");
if(bodyClassList.search("dark")!==-1) throw new Error("Could not switch to light theme");
})