Commit 3cbbb37e authored by ransome1's avatar ransome1
Browse files

CSS refactoring, enhanced jail navigation, added "pri" extension

parent 7e98cd72
{
"name": "sleek",
"productName": "sleek",
"version": "1.1.9",
"version": "1.2.0-rc.1",
"description": "todo.txt manager for Linux, Windows and MacOS, free and open-source (FOSS)",
"synopsis": "todo.txt manager for Linux, Windows and MacOS, free and open-source (FOSS)",
"category": "ProjectManagement",
......
This diff is collapsed.
This diff is collapsed.
......@@ -40,7 +40,7 @@ viewInvertSorting.innerHTML = translations.invertSorting;
viewSortBy.innerHTML = translations.sortBy;
viewSortByFile.innerHTML = translations.sortByFile;
export function showDrawer(button) {
export async function showDrawer(button) {
try {
const buttons = document.querySelectorAll("nav ul li a.drawerTrigger");
......@@ -86,7 +86,7 @@ export function showDrawer(button) {
handleError(error);
});
createModalJail(drawer).then(function(response) {
createModalJail(drawer, false, true).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
......@@ -120,23 +120,6 @@ drawerClose.onclick = function() {
if(userData.matomoEvents) _paq.push(["trackEvent", "Drawer", "Click on close button"])
}
// close or open drawer on start if setting was persisted
if(userData.filterDrawer) {
const navBtnFilter = document.getElementById("navBtnFilter");
showDrawer(navBtnFilter).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
});
} else if(userData.viewDrawer) {
const navBtnView = document.getElementById("navBtnView");
showDrawer(navBtnView).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
});
}
// build the sortBy list
userData.sortBy.forEach(function(sortBy) {
const sortByContainerElement = document.createElement("li");
......
......@@ -216,14 +216,7 @@ async function generateFileList(show) {
// present the modal
if(show !== false) modalChangeFile.classList.add("is-active");
// create a jail for the modal
createModalJail(modalChangeFile).then(response => {
console.info(response);
}).catch(error => {
handleError(error);
});
// loop through all saved files
for (let i = 0; i < userData.files.length; i++) {
......@@ -269,6 +262,13 @@ async function generateFileList(show) {
}
}
// create a jail for the modal
createModalJail(modalChangeFile).then(response => {
console.info(response);
}).catch(error => {
handleError(error);
});
return Promise.resolve("Success: File changer modal built and opened");
} catch (error) {
......
......@@ -453,13 +453,6 @@ function generateFilterButtons(category, autoCompletePrefix) {
// add context menu
todoFiltersItem.oncontextmenu = function(event) {
// jail the modal
createModalJail(filterContext).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
});
filterContextInput.value = filter;
filterContextInput.setAttribute("data-item", category);
filterContextInput.focus();
......@@ -495,6 +488,15 @@ function generateFilterButtons(category, autoCompletePrefix) {
handleError(error);
});
}
// jail the modal
createModalJail(filterContext).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
});
}
// create the event listener for filter selection by user
......@@ -665,7 +667,7 @@ function generateFilterData(autoCompleteCategory, autoCompleteValue, autoComplet
// }
// build filter buttons and add them to a fragment
let buttons = await generateFilterButtons(category, autoCompletePrefix).then(response => {
const buttons = await generateFilterButtons(category, autoCompletePrefix).then(response => {
return response;
}).catch (error => {
handleError(error);
......
......@@ -4,6 +4,7 @@ import { generateGroupedObjects, items, generateTodoTxtObject } from "./todos.mj
import { isToday, isPast, isTomorrow } from "./date.mjs";
import { generateFileTabs } from "./files.mjs";
import { showGenericMessage } from "./messages.mjs";
import { showDrawer } from "./drawer.mjs";
import { showOnboarding } from "./onboarding.mjs";
import { _paq } from "./matomo.mjs";
import "../../node_modules/marked/marked.min.js";
......@@ -170,7 +171,6 @@ export function getBadgeCount() {
// one time interface setup when app is started
export function initialSetupInterface() {
try {
// setup compact view
(userData.compactView) ? body.classList.add("compact") : body.classList.remove("compact");
......@@ -185,6 +185,23 @@ export function initialSetupInterface() {
// add version number to about tab in settings modal
document.getElementById("version").innerHTML = appData.version;
// close or open drawer on start if setting was persisted
if(userData.filterDrawer) {
const navBtnFilter = document.getElementById("navBtnFilter");
showDrawer(navBtnFilter).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
});
} else if(userData.viewDrawer) {
const navBtnView = document.getElementById("navBtnView");
showDrawer(navBtnView).then(function(result) {
console.log(result);
}).catch(function(error) {
handleError(error);
});
}
return Promise.resolve("Success: Initial interface setup completed");
} catch(error) {
......@@ -194,6 +211,7 @@ export function initialSetupInterface() {
}
export function setupInterface() {
try {
// this happens in view drawer
// hide sort by container if sorting is according to file
const viewSortByRow = document.getElementById("viewSortByRow");
......
......@@ -4,7 +4,7 @@
// limits tabbing to those elements until modal is closed
// works also backwards using shift + tab
// loops when finished
export function createModalJail(modal) {
export function createModalJail(modal, arrowUpDown, arrowRightLeft) {
try {
if(typeof modal !== "object") return Promise.resolve("Info: No modal passed, can't create jail");
......@@ -19,12 +19,11 @@ export function createModalJail(modal) {
// add focus on the first focusable element
firstFocusableElement.focus();
modal.onkeydown = function(event) {
// if arrow down key is pressed
// we don't want this behaviour in modalForm
if(event.key === "ArrowDown" && excludeModalFromArrowKeys.indexOf(modal.id) === -1) {
if((arrowUpDown && event.key === "ArrowDown") || (arrowRightLeft && event.key === "ArrowRight") && excludeModalFromArrowKeys.indexOf(modal.id) === -1) {
const focusedElementIndex = Array.prototype.indexOf.call(focusableContent, document.activeElement);
// stop when the last element is reached and focus the first one
if((focusedElementIndex + 1) === focusableContent.length) {
......@@ -37,7 +36,7 @@ export function createModalJail(modal) {
// if arrow up key is pressed
// we don't want this behaviour in modalForm
if(event.key === "ArrowUp" && excludeModalFromArrowKeys.indexOf(modal.id) === -1) {
if((arrowUpDown && event.key === "ArrowUp") || (arrowRightLeft && event.key === "ArrowLeft") && excludeModalFromArrowKeys.indexOf(modal.id) === -1) {
const focusedElementIndex = Array.prototype.indexOf.call(focusableContent, document.activeElement);
// stop if the first element is reached and focus the last one
if(focusedElementIndex === 0) {
......
......@@ -204,7 +204,7 @@ export async function registerShortcuts() {
// make sure no input or drawer is opened
if(!isInputFocused() && !isDrawerOpen() && !isContextOpen()) {
if(!isInputFocused() && !isContextOpen()) {
// move focus down in table list
......
......@@ -13,7 +13,7 @@ import { generateRecurrence } from "./recurrences.mjs";
import { getActiveFile, getDoneFile, handleError, pasteItemToClipboard, generateGenericNotification, generateTodoNotification } from "./helper.mjs";
import { getConfirmation } from "./prompt.mjs";
import { show } from "./form.mjs";
import { SugarDueExtension, RecExtension, ThresholdExtension } from "./todotxtExtensions.mjs";
import { SugarDueExtension, RecExtension, ThresholdExtension, PriExtension } from "./todotxtExtensions.mjs";
const item = { previous: "" }
const items = { objects: {} }
......@@ -76,7 +76,7 @@ async function generateTodoTxtObjects(fileContent) {
try {
// create todo.txt objects
if(fileContent !== undefined) items.objects = await TodoTxt.parse(fileContent, [ new SugarDueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension() ])
if(fileContent !== undefined) items.objects = await TodoTxt.parse(fileContent, [ new SugarDueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension(), new PriExtension() ])
// empty lines will be filtered
items.objects = items.objects.filter(function(item) { return item.toString() !== "" });
......@@ -90,7 +90,7 @@ async function generateTodoTxtObjects(fileContent) {
}
function generateTodoTxtObject(string) {
try {
const todo = new TodoTxtItem(string, [ new SugarDueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension() ]);
const todo = new TodoTxtItem(string, [ new SugarDueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension(), new PriExtension() ]);
return Promise.resolve(todo);
} catch(error) {
error.functionName = editTodo.name;
......@@ -476,7 +476,7 @@ function generateTableRow(todo) {
todo[category].forEach(element => {
let todoTableBodyCellCategory = document.createElement("a");
todoTableBodyCellCategory.classList.add("tag", category)
todoTableBodyCellCategory.classList.add("button", category)
todoTableBodyCellCategory.onclick = function() {
selectFilter(element, category).then(response => {
console.log(response)
......@@ -659,7 +659,7 @@ async function createTodoContext(todoTableRow) {
// ugly but neccessary: if triggered to fast arrow right will do a first row change in jail
setTimeout(function() {
createModalJail(todoContext).then(response => {
createModalJail(todoContext, true).then(response => {
console.log(response);
}).catch(error => {
handleError(error);
......@@ -720,6 +720,14 @@ async function setTodoComplete(todo) {
todo.complete = false;
todo.completed = null;
if(todo.pri) {
// restore old priority
todo.priority = todo.pri;
//todo.pri = null;
delete todo.pri;
delete todo.priString;
}
// Mark item as complete
} else if(!todo.complete) {
todo.complete = true;
......@@ -732,10 +740,10 @@ async function setTodoComplete(todo) {
}).catch(function(error) {
handleError(error);
});
if(todo.priority) {
// and preserve prio
todo.text += " pri:" + todo.priority
todo.text += " pri:" + todo.priority;
// finally remove priority
todo.priority = null;
}
......@@ -743,7 +751,7 @@ async function setTodoComplete(todo) {
}
// delete old todo from array and add the new one at it's position
items.objects.splice(index, 1, todo);
await items.objects.splice(index, 1, todo);
//write the data to the file and advice to focus the row after reload
window.api.send("writeToFile", [items.objects.join("\n").toString() + "\n"]);
......
......@@ -43,6 +43,24 @@ SugarDueExtension.prototype.parsingFunction = function (line) {
return [null, null, null];
};
function PriExtension() {
this.name = "pri";
}
PriExtension.prototype = new TodoTxtExtension();
PriExtension.prototype.parsingFunction = function (line) {
var pri = null;
var priRegex = /pri:([A-Z])/i;
var matchPri = priRegex.exec(line);
if ( matchPri !== null ) {
pri = matchPri[1];
return [pri, line.replace(priRegex, ''), matchPri[1]];
}
return [null, null, null];
};
function ThresholdExtension() {
this.name = "t";
}
......@@ -59,4 +77,4 @@ ThresholdExtension.prototype.parsingFunction = function (line) {
return [null, null, null];
};
export { RecExtension, SugarDueExtension, ThresholdExtension };
export { RecExtension, SugarDueExtension, ThresholdExtension, PriExtension };
......@@ -76,6 +76,8 @@ function getChannel() {
function getContent(file) {
try {
if(!file) return false;
// only for MAS (Sandboxed)
// https://gist.github.com/ngehlert/74d5a26990811eed59c635e49134d669
const activeFile = getActiveFile();
......@@ -804,14 +806,14 @@ async function createWindow() {
// setup reload intervall (reload every 10 minutes)
setInterval(async () => {
if(!getActiveFile() && mainWindow.isFocused()) return false;
if(mainWindow.isFocused()) return false;
if(!getActiveFile()) return false;
const content = await getContent(getActiveFile()[1]);
mainWindow.webContents.send("buildTable", [content]);
}, 600000);
}, 60000);
return Promise.resolve("Success: Renderer window created");
......
......@@ -54,20 +54,20 @@ async function buildTable(fileContent, loadAll) {
helper.handleError(error);
})
// once we have the filtered objects, we can adjust the gui
helper.setupInterface().then(function(response) {
// build the filters in drawer and autocomplete container
await filters.generateFilterData().then(function(response) {
console.log(response)
}).catch(function(error) {
helper.handleError(error);
});
// build the filters in drawer and autocomplete container
filters.generateFilterData().then(function(response) {
// once we have the filtered objects, we can adjust the gui
helper.setupInterface().then(function(response) {
console.log(response)
}).catch(function(error) {
helper.handleError(error);
});
// Group filtered todo.txt objects and add them to items object
todos.generateGroupedObjects().then(function(response) {
console.log(response);
......@@ -118,12 +118,6 @@ window.onload = async function() {
});
}
helper.initialSetupInterface().then(function(response) {
console.info(response);
}).catch(function(error) {
helper.handleError(error);
});
messages = await import("./js/messages.mjs");
messages.checkDismissedMessages().then(function(response) {
console.info(response);
......@@ -154,6 +148,12 @@ window.onload = async function() {
helper.handleError(error);
});
helper.initialSetupInterface().then(function(response) {
console.info(response);
}).catch(function(error) {
helper.handleError(error);
});
// stop timer for app
console.info("App built in", performance.now() - a0, "ms");
......
......@@ -6,17 +6,17 @@
#modalForm {
textarea {
padding: 0.75em!important;
padding: 0.75em;
}
}
.modal.content {
.modal-card {
padding: 1em!important;
padding: 1em;
}
}
table tr td {
padding: 0.25em 1.5em 0.25em 0 !important
padding: 0.25em 1.5em 0.25em 0
}
#sortByContainer li {
padding: 0.25em 0.5em;
......@@ -28,9 +28,6 @@
}
.group {
a {
font-size: 0.8em!important;
}
.cell {
margin-bottom: 0;
}
......@@ -60,21 +57,14 @@
}
}
}
#drawerContainer {
min-width: 325px;
}
#autoCompleteContainer,
#drawerContainer .drawer {
padding: 1.5em;
.is-4 {
font-size: 1.1em;
}
a.button.priority {
font-size: 1.2em;
.tag {
font-size: 0.65em;
}
}
padding: 1em;
a.button {
font-size: 0.9em;
margin: 0 0.3em 0.3em 0!important;
margin: 0 0.3em 0.3em 0;
padding: 0.5em 0.7em;
.tag {
width: auto;
......@@ -82,9 +72,11 @@
padding: 0 .5em;
min-width: 1.5em;
min-height: 1.5em;
font-size: .9em;
}
}
.priority a.button {
padding: 0.2em 0.5em;
}
}
#autoCompleteContainer {
padding: 1em;
......@@ -95,25 +87,35 @@
}
@media screen and (max-width: 992px),
screen and (max-height: 650px) {
body {
font-size: 0.9em;
}
@include compact;
}
@mixin mobile() {
.modal {
.modal-content {
width: 95%!important;
padding: 0.5em!important;
width: 95%;
padding: 0.5em;
.card-content {
padding: 0.5em!important;
padding: 0.5em;
#modalFormInputResize {
top: 1.35em!important;
right: 1.8em!important;
top: 1.35em;
right: 1.8em;
}
}
}
}
#messages {
right: 1em;
margin: 0 0 0 1em;
}
}
@media screen and (max-width: 500px) {
body {
font-size: 0.8em;
}
@include mobile;
}
......
......@@ -5,100 +5,64 @@
background-color: $almost-black;
color: $almost-white;
code, pre {
color: $lighter-grey!important;
background-color: $almost-black!important;
}
a {
color: $has-text-link!important;
}
a:hover,
a:focus-visible {
color: $almost-white!important;
color: $lighter-grey;
background-color: $almost-black;
}
strong {
color: white!important;
color: white;
}
input,
select {
border: none!important;
background: transparent!important;
color: white!important;
}
input[type="text"],
input[type="search"],
textarea {
background: $darker-grey!important;
border: none;
color: white!important;
background: transparent;
color: white;
}
input:focus,
select:focus {
background-color: $darker-grey!important;
a:hover, a:active, a:focus {
color: $has-text-link;
}
.is-focused .inputWrapper,
.inputWrapper.is-focused {
label,
i.fa-search,
.todoTableSearchQuestionmark i {
color: $almost-white!important;
}
.button {
background-color: transparent;
}
input::placeholder {
color: $almost-white!important;
.button:focus:not(:active), .button.is-focused:not(:active), .button:active, .button.is-active, input[type=number], .button:focus, .button.is-focused, .select select, .textarea, .input, .select select:focus, .textarea:focus, .input:focus, .select select.is-focused, .is-focused.textarea, .is-focused.input, .select select:active, .textarea:active, .input:active, .select select.is-active, .is-active.textarea, .is-active.input {
background: $darker-grey;
border: none;
color: white;
}
input[type="text"]::placeholder,
input[type="search"]::placeholder,
textarea::placeholder {
color: $dark-grey!important;
textarea.is-medium::placeholder {
color: $dark-grey;
}
input[type="checkbox"]:focus,
input[type="checkbox"]:active {
outline: none;
box-shadow: none!important;
box-shadow: none;
}
input[type="range"],
input[type="range"]:focus {
background: $dark-grey!important;
background: $dark-grey;
}
input[type="range"]::-webkit-slider-thumb {
background: $almost-white!important;
}
button {
color: $almost-white!important;
background-color: transparent!important;
}
::after {
border-color: $has-text-link!important;
background: $almost-white;
}
button:focus-visible {
color: $almost-white!important;
background: $darker-grey!important;
color: $almost-white;
background: $darker-grey;
}
table {
width: 100%;
background-color: transparent!important;
color: $lighter-grey!important;