Commit 6000e80f authored by ransome1's avatar ransome1
Browse files

Improvements on file tabbing function, updated readme, updates translations

parent 3c223e28
......@@ -123,3 +123,4 @@ A prioritized backlog of new features and known issues can be found <a href="htt
- Matomo: https://github.com/matomo-org/matomo
- chokidar: https://github.com/paulmillr/chokidar
- Sugar: https://github.com/andrewplummer/Sugar
- PEG.js: https://github.com/pegjs/pegjs
{
"name": "sleek",
"productName": "sleek",
"version": "1.1.0-rc.2",
"version": "1.1.0-rc.3",
"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",
......
......@@ -322,7 +322,8 @@ body.dark #fileTabBar ul li {
body.dark #fileTabBar ul li i {
color: #2d2d2d;
}
body.dark #fileTabBar ul li:hover i {
body.dark #fileTabBar ul li:hover i,
body.dark #fileTabBar ul li.is-highlighted:hover i {
color: #3273dc;
}
body.dark #fileTabBar ul li.is-highlighted {
......@@ -918,19 +919,29 @@ code, pre {
padding-left: 2.5em;
}
#fileTabBar ul li {
width: auto;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 15em;
min-width: 8.5em;
float: left;
color: #5a5a5a;
background: transparent;
padding: 0.35em 1em 0.35em 2.35em;
padding: 0.35em 2.35em;
margin-top: 2px;
cursor: pointer;
text-align: center;
}
#fileTabBar ul li i {
position: absolute;
top: 0.65em;
right: 0.5em;
color: #ebebeb;
padding-left: 0.5em;
}
#fileTabBar ul li:hover i {
#fileTabBar ul li:hover i,
#fileTabBar ul li.is-highlighted:hover i {
color: #3273dc;
}
#fileTabBar ul li.is-highlighted {
......@@ -2472,6 +2483,16 @@ body {
nav ul,
header,
#drawerClose,
#viewDrawer,
#todoContext,
#filterContext,
#modalChangeFile,
#modalPrompt,
#messages,
#modalForm,
#modalHelp,
#modalSettings,
#btnFiltersResetFilters {
display: none !important;
}
......
This diff is collapsed.
......@@ -744,6 +744,12 @@
<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>
<tr>
<td><a href="https://github.com/pegjs/pegjs" target="_blank">PEG.js</a></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</section>
<button class="modal-close close is-large" aria-label="close" tabindex="0"></button>
......
"use strict";
import { resetFilters, resetModal, handleError, userData, setUserData, translations, getConfirmation } from "../render.js";
import { resetFilters, resetModal, handleError, userData, setUserData, translations } from "../render.js";
import { _paq } from "./matomo.mjs";
import { createModalJail } from "../configs/modal.config.mjs";
......@@ -8,27 +8,29 @@ const modalChangeFile = document.getElementById("modalChangeFile");
const modalChangeFileTable = document.getElementById("modalChangeFileTable");
const fileTabBarList = document.querySelector("#fileTabBar ul");
function removeFileFromList(filePath, files) {
function removeFileFromList(isActive, index) {
try {
// remove file from files array
files = files.filter(function(file) {
return file[1] != filePath;
});
// persist new files array
setUserData("files", files);
// reset everything and load again
if(isActive && index-1 === -1) {
userData.files[index+1][0] = 1;
} else if(isActive && index-1 >= 0) {
userData.files[index-1][0] = 1;
}
userData.files.splice(index, 1);
setUserData("files", userData.files);
resetFilters().then(function(response) {
console.info(response);
index = userData.files.findIndex(file => file[0] === 1);
window.api.send("startFileWatcher", userData.files[index][1]);
}).catch(function(error) {
handleError(error);
});
return Promise.resolve("Success: File removed from list: " + filePath);
return Promise.resolve("Success: File removed from list");
} catch (error) {
return Promise.reject(error);
}
}
function selectFileFromList(file) {
function selectFileFromList(index) {
try {
resetFilters().then(function(response) {
console.info(response);
......@@ -36,78 +38,60 @@ function selectFileFromList(file) {
handleError(error);
});
resetModal().then(response => {
window.api.send("startFileWatcher", file);
window.api.send("startFileWatcher", userData.files[index][1]);
console.info(response);
}).catch(error => {
handleError(error);
});
return Promise.resolve("Success: File selected from list: " + file);
return Promise.resolve("Success: File selected");
} catch (error) {
return Promise.reject(error);
}
}
function generateFileTabs() {
let files = userData.files;
if(files.length>1 && userData.fileTabs) {
fileTabBar.classList.add("is-active");
} else {
fileTabBar.classList.remove("is-active");
return false;
}
fileTabBarList.innerHTML = null;
for (let file in files) {
const isActive = files[file][0];
const filePath = files[file][1];
const fileName = files[file][1].split("/").pop();
let listItem = document.createElement("li");
listItem.innerHTML = fileName;
listItem.innerHTML += "<i class=\"fas fa-minus-circle\"></i>";
if(isActive===1) {
listItem.classList.add("is-highlighted");
function generateFileList() {
try {
if(userData.files.length>1 && userData.fileTabs) {
fileTabBar.classList.add("is-active");
} else {
// only add remove button to not selected ones to reduce complexity
listItem.querySelector("i").onclick = function() {
getConfirmation(removeFileFromList, translations.fileRemovalPrompt, filePath, files);
}
fileTabBar.classList.remove("is-active");
}
listItem.onclick = function(event) {
// if click was on minus circle function is aborted
if(event.target.classList.contains("fas")) return false;
// just send the new file to filewatcher
selectFileFromList(filePath).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
});
// trigger matomo event
if(userData.matomoEvents) _paq.push(["trackEvent", "File-Tab", "Click on tab"]);
}
fileTabBarList.appendChild(listItem);
}
}
function showFiles() {
try {
let files = userData.files;
modalChangeFile.classList.add("is-active");
modalChangeFile.focus();
fileTabBarList.innerHTML = null;
modalChangeFileTable.innerHTML = null;
modalChangeFileTable.classList.add("files");
for (let file in files) {
// skip if file doesn't exist
for (let i = 0; i < userData.files.length; i++) {
let isActive = userData.files[i][0];
let fileName = userData.files[i][1].split("/").pop();
let listItem = document.createElement("li");
listItem.innerHTML = fileName;
listItem.innerHTML += "<i class=\"fas fa-minus-circle\"></i>";
if(isActive===1) listItem.classList.add("is-highlighted");
listItem.querySelector("i").onclick = function() {
removeFileFromList(isActive, i);
}
if(!isActive) {
listItem.onclick = function(event) {
if(event.target.classList.contains("fas")) return false;
selectFileFromList(i).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
});
// trigger matomo event
if(userData.matomoEvents) _paq.push(["trackEvent", "File-Tab", "Click on tab"]);
}
}
fileTabBarList.appendChild(listItem);
let row = modalChangeFileTable.insertRow(-1);
let cell1 = row.insertCell(0);
let cell2 = row.insertCell(1);
let cell3 = row.insertCell(2);
row.setAttribute("data-path", files[file][1]);
if(files[file][0]===1) {
if(userData.files[i][0]===1) {
cell1.innerHTML = "<button disabled>" + translations.selected + "</button>";
} else {
cell1.innerHTML = "<button tabindex=\"0\">" + translations.select + "</button>";
cell1.onclick = function() {
// just send the new file to filewatcher
selectFileFromList(this.parentElement.getAttribute("data-path")).then(function(response) {
selectFileFromList(i).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
......@@ -115,21 +99,21 @@ function showFiles() {
// trigger matomo event
if(userData.matomoEvents) _paq.push(["trackEvent", "File", "Click on select button"]);
}
cell3.innerHTML = "<a href=\"#\" tabindex=\"0\"><i class=\"fas fa-minus-circle\"></i></a>";
cell3.title = translations.delete;
cell3.onclick = async function() {
await getConfirmation(removeFileFromList, translations.fileRemovalPrompt, this.parentElement.getAttribute("data-path"), files);
showFiles().then(response => {
console.info(response);
}).catch(error => {
handleError(error);
});
}
}
cell2.innerHTML = files[file][1];
cell2.innerHTML = userData.files[i][1];
cell3.innerHTML = "<a href=\"#\" tabindex=\"0\"><i class=\"fas fa-minus-circle\"></i></a>";
cell3.title = translations.delete;
cell3.onclick = function() {
removeFileFromList(isActive, i);
generateFileList().then(response => {
modalChangeFile.classList.add("is-active");
modalChangeFile.focus();
console.info(response);
}).catch(error => {
handleError(error);
});
}
}
// create the modal jail, so tabbing won't leave modal
createModalJail(modalChangeFile);
return Promise.resolve("Success: File changer modal built and opened");
} catch (error) {
return Promise.reject(error);
......@@ -138,8 +122,11 @@ function showFiles() {
btnOpenTodoFile.onclick = function() {
if(typeof userData.files === "object" && userData.files.length>0) {
showFiles().then(response => {
generateFileList().then(response => {
console.info(response);
modalChangeFile.classList.add("is-active");
modalChangeFile.focus();
createModalJail(modalChangeFile);
}).catch(error => {
handleError(error);
});
......@@ -150,4 +137,4 @@ btnOpenTodoFile.onclick = function() {
if(userData.matomoEvents) _paq.push(["trackEvent", "Menu", "Click on Files"]);
}
export { generateFileTabs };
export { generateFileList, removeFileFromList };
......@@ -155,5 +155,5 @@
"deferredTodos": "Verzögertes Datum",
"noFiltersFound": "Keine Filter gefunden",
"fileRemovalPrompt": "Die Datei wird lediglich aus dieser Liste entfernt, dabei aber nicht von der Festplatte gelöscht.",
"fileTabs": "Dateireiter"
"fileTabs": "Reiter"
}
......@@ -154,5 +154,5 @@
"deferredTodos": "Threshold date in the future",
"noFiltersFound": "No filters found",
"fileRemovalPrompt": "This will only remove the file from your file list, it will not be deleted from your drive.",
"fileTabs": "File tabs"
"fileTabs": "Tabs"
}
......@@ -153,5 +153,5 @@
"deferredTodos": "Fecha límite en el futuro",
"noFiltersFound": "No se encontraron filtros",
"fileRemovalPrompt": "Esto solo eliminará el archivo de su lista de archivos, no se eliminará de su unidad.",
"fileTabs": "Pestañas de archivo"
"fileTabs": "Pestañas"
}
......@@ -154,5 +154,5 @@
"deferredTodos": "Date seuil dans le futur",
"noFiltersFound": "Aucun filtre trouvé",
"fileRemovalPrompt": "Cela supprimera uniquement le fichier de votre liste de fichiers, il ne sera pas supprimé de votre lecteur.",
"fileTabs": "Onglets de fichier"
"fileTabs": "Onglets"
}
......@@ -153,5 +153,5 @@
"deferredTodos": "Data limite nel futuro",
"noFiltersFound": "Nessun filtro trovato",
"fileRemovalPrompt": "Questo rimuoverà solo il file dall'elenco dei file, non verrà eliminato dall'unità.",
"fileTabs": "Schede di file"
"fileTabs": "Schede"
}
......@@ -154,5 +154,5 @@
"deferredTodos": "将来のしきい値",
"noFiltersFound": "フィルタが見つかりません",
"fileRemovalPrompt": "これにより、ファイルリストからファイルが削除されるだけで、ドライブからは削除されません。",
"fileTabs": "ファイルタブ"
"fileTabs": "タブ"
}
......@@ -154,5 +154,5 @@
"deferredTodos": "Data limite no futuro",
"noFiltersFound": "Nenhum filtro encontrado",
"fileRemovalPrompt": "Isso removerá apenas o arquivo da lista de arquivos, não será excluído da unidade.",
"fileTabs": "Guias de arquivo"
"fileTabs": "Abas"
}
......@@ -154,5 +154,5 @@
"deferredTodos": "未来的阈值日期",
"noFiltersFound": "未找到过滤器",
"fileRemovalPrompt": "这只会从您的文件列表中删除该文件,而不会从您的驱动器中删除它。",
"fileTabs": "文件标签"
"fileTabs": "标签"
}
......@@ -386,8 +386,9 @@ const createWindow = async function() {
},
{ type: "separator" },
{
role: "close",
accelerator: "Command+W",
click: function () {
mainWindow.close();
},
label: translations.close
},
{
......@@ -445,7 +446,9 @@ const createWindow = async function() {
},
{ type: "separator" },
{
role: "close",
click: function () {
mainWindow.close();
},
label: translations.close
}
];
......@@ -666,6 +669,9 @@ const createWindow = async function() {
const configureWindowEvents = function() {
try {
ipcMain
.on("closeWindow", (event, args) => {
mainWindow.close();
})
.on("userData", (event, args) => {
if(args) userData.set(args[0], args[1]);
mainWindow.webContents.send("userData", userData.data);
......
......@@ -16,7 +16,8 @@ contextBridge.exposeInMainWorld(
"update-badge",
"triggerFunction",
"restart",
"setTheme"
"setTheme",
"closeWindow"
];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
......
......@@ -111,7 +111,7 @@ async function getConfirmation() {
function configureMainView() {
try {
// generate file tabs
files.generateFileTabs();
files.generateFileList();
// close filterContext if open
if(document.getElementById("filterContext").classList.contains("is-active")) document.getElementById("filterContext").classList.remove("is-active");
// set scaling factor if default font size has changed
......@@ -384,6 +384,15 @@ function registerKeyboardShortcuts() {
if((event.ctrlKey || event.metaKey) && event.key === "c" && (document.activeElement.id!="todoTableSearch" && document.activeElement.id!="filterContextInput" && document.activeElement.id!="modalFormInput")) {
window.api.send("openOrCreateFile", "create");
}
// close tab or window
if((event.ctrlKey || event.metaKey) && event.key === "w") {
if(userData.files.length > 1) {
let index = userData.files.findIndex(file => file[0] === 1);
files.removeFileFromList(1, index);
} else {
window.api.send("closeWindow");
}
}
}, true)
window.addEventListener("keyup", function(event) {
// switch files
......@@ -391,6 +400,23 @@ function registerKeyboardShortcuts() {
if(event.key.match(regex) && userData.files.length > 1 && !modalForm.classList.contains("is-active") && (document.activeElement.id!="todoTableSearch" && document.activeElement.id!="filterContextInput" && document.activeElement.id!="modalFormInput")) {
window.api.send("startFileWatcher", userData.files[event.key-1][1]);
}
// cycle through tabs
if(event.ctrlKey && !event.shiftKey && event.keyCode === 9) {
let index = userData.files.findIndex(file => file[0] === 1);
if(!userData.files[index+1]) {
window.api.send("startFileWatcher", userData.files[0][1]);
} else {
window.api.send("startFileWatcher", userData.files[index+1][1]);
}
}
if(event.ctrlKey && event.shiftKey && event.keyCode === 9) {
let index = userData.files.findIndex(file => file[0] === 1);
if(!userData.files[index-1]) {
window.api.send("startFileWatcher", userData.files[userData.files.length-1][1]);
} else {
window.api.send("startFileWatcher", userData.files[index-1][1]);
}
}
// open settings
if(event.key === "," && !modalForm.classList.contains("is-active") && (document.activeElement.id!="todoTableSearch" && document.activeElement.id!="filterContextInput" && document.activeElement.id!="modalFormInput")) {
content.showContent("modalSettings").then(function(response) {
......
......@@ -359,7 +359,8 @@ body.dark {
color: $darker-grey;
}
}
li:hover {
li:hover,
li.is-highlighted:hover {
i {
color: $has-text-link;
}
......
......@@ -11,6 +11,16 @@ body {
}
nav ul,
header,
#drawerClose,
#viewDrawer,
#todoContext,
#filterContext,
#modalChangeFile,
#modalPrompt,
#messages,
#modalForm,
#modalHelp,
#modalSettings,
#btnFiltersResetFilters {
display: none!important;
}
......
......@@ -12,19 +12,29 @@
background: $light-grey;
padding-left: 2.5em;
li {
width: auto;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 15em;
min-width: 8.5em;
float: left;
color: $dark-grey;
background: transparent;
padding: 0.35em 1em 0.35em 2.35em;
padding: 0.35em 2.35em;
margin-top: 2px;
cursor: pointer;
text-align: center;
i {
position: absolute;
top: 0.65em;
right: 0.5em;
color: $light-grey;
padding-left: 0.5em;
}
}
li:hover {
li:hover,
li.is-highlighted:hover {
i {
color: $has-text-link;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment