diff --git a/flatpak/com.github.ransome1.sleek.appdata.xml b/flatpak/com.github.ransome1.sleek.appdata.xml
index 4e434ded..b11f88a8 100755
--- a/flatpak/com.github.ransome1.sleek.appdata.xml
+++ b/flatpak/com.github.ransome1.sleek.appdata.xml
@@ -9,7 +9,7 @@
Robin Ahle
-
+
https://github.com/ransome1/sleek
https://github.com/ransome1/sleek/issues
diff --git a/flatpak/com.github.ransome1.sleek.desktop b/flatpak/com.github.ransome1.sleek.desktop
index 41256a90..f2191a90 100755
--- a/flatpak/com.github.ransome1.sleek.desktop
+++ b/flatpak/com.github.ransome1.sleek.desktop
@@ -1,5 +1,5 @@
[Desktop Entry]
-Version=2.0.4
+Version=2.0.5
Name=sleek
Exec=sleek
Type=Application
diff --git a/package.json b/package.json
index 038c2a13..a860b2c6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "sleek",
- "version": "2.0.4",
+ "version": "2.0.5",
"main": "./src/main/main.tsx",
"scripts": {
"build": "concurrently \"yarn run peggy\" \"yarn run build:main\" \"yarn run build:renderer\"",
@@ -141,7 +141,7 @@
"webpack-merge": "^5.9.0"
},
"build": {
- "buildVersion": "31",
+ "buildVersion": "34",
"asar": true,
"asarUnpack": "**\\*.{node,dll}",
"files": [
@@ -210,7 +210,8 @@
"target": [
"zip",
"portable",
- "nsis"
+ "nsis",
+ "appx"
],
"icon": "assets/icons/sleek.ico",
"artifactName": "${productName}-${version}-win.${ext}"
diff --git a/release/app/package.json b/release/app/package.json
index 4208b8fc..034a4d42 100644
--- a/release/app/package.json
+++ b/release/app/package.json
@@ -1,6 +1,6 @@
{
"name": "sleek",
- "version": "2.0.4",
+ "version": "2.0.5",
"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)",
"keywords": [
@@ -19,7 +19,7 @@
"url": "https://github.com/ransome1/sleek.git"
},
"author": "Robin Ahle ",
- "copyright": "Copyright © 2023 ${author}",
+ "copyright": "Copyright © 2024 ${author}",
"license": "MIT",
"main": "./dist/main/main.js",
"scripts": {
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index 945cca66..39e648d5 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -1,6 +1,6 @@
name: sleek
base: core20
-version: "2.0.4"
+version: "2.0.5"
summary: todo.txt manager for Linux, free and open-source (FOSS)
description: |
sleek is an open-source (FOSS) todo manager based on the todo.txt syntax. Stripped down to only the most necessary features, and with a clean and simple interface, sleek aims to help you focus on getting things done.
diff --git a/src/main/config.tsx b/src/main/config.tsx
index 6c2cf065..6d8fff4b 100644
--- a/src/main/config.tsx
+++ b/src/main/config.tsx
@@ -5,7 +5,7 @@ import fs from 'fs';
import { mainWindow } from './main';
import { createFileWatcher } from './modules/File/Watcher';
import { createTray } from './modules/Tray';
-import processDataRequest from './modules/ProcessDataRequest/ProcessDataRequest';
+import { processDataRequest, searchString } from './modules/ProcessDataRequest/ProcessDataRequest';
import handleTheme from './modules/Theme';
import crypto from 'crypto';
@@ -112,7 +112,7 @@ if(!fs.existsSync(customStylesPath)) {
filterStorage.onDidAnyChange(async () => {
try {
- await processDataRequest();
+ await processDataRequest(searchString);
} catch(error: any) {
console.error(error);
}
@@ -120,7 +120,7 @@ filterStorage.onDidAnyChange(async () => {
configStorage.onDidAnyChange(async(settings) => {
try {
- await processDataRequest();
+ await processDataRequest(searchString);
mainWindow!.webContents.send('settingsChanged', settings);
} catch(error: any) {
console.error(error);
diff --git a/src/main/main.tsx b/src/main/main.tsx
index c546e95a..6bc27246 100644
--- a/src/main/main.tsx
+++ b/src/main/main.tsx
@@ -10,9 +10,6 @@ import { createTray } from './modules/Tray';
import './modules/Ipc';
const environment: string | undefined = process.env.NODE_ENV;
-const files: FileObject[] = (configStorage.get('files') as FileObject[]) || [];
-let tray: boolean = configStorage.get('tray');
-const colorTheme = configStorage.get('colorTheme');
let mainWindow: BrowserWindow | null = null;
let eventListeners: Record = {};
@@ -24,7 +21,7 @@ const handleCreateWindow = () => {
}
}
-const handleClosed = async () => {
+const handleClosed = async (event) => {
if(watcher) await watcher.close();
mainWindow = null;
@@ -93,9 +90,15 @@ const handleWindowSizeAndPosition = () => {
}
const createMainWindow = () => {
+ const colorTheme = configStorage.get('colorTheme');
+ const shouldUseDarkColors = configStorage.get('shouldUseDarkColors');
+ const files: FileObject[] = (configStorage.get('files') as FileObject[]) || [];
+ const tray = configStorage.get('tray');
+
mainWindow = new BrowserWindow({
width: 1280,
height: 1000,
+ backgroundColor: (shouldUseDarkColors) ? '#212224' : '#fff',
icon: process.platform === 'win32' ? getAssetPath('icons/sleek.ico') : getAssetPath('icons/512x512.png'),
autoHideMenuBar: true,
webPreferences: {
@@ -108,16 +111,12 @@ const createMainWindow = () => {
},
});
- if (environment === 'development') {
- mainWindow.webContents.openDevTools();
- }
+ mainWindow?.loadURL(resolveHtmlPath('index.html'));
handleWindowSizeAndPosition();
nativeTheme.themeSource = colorTheme;
- mainWindow?.loadURL(resolveHtmlPath('index.html'));
-
mainWindow
.on('ready-to-show', handleReadyToShow)
.on('resize', handleResize)
@@ -135,6 +134,16 @@ const createMainWindow = () => {
eventListeners.handleMaximize = handleMaximize
eventListeners.handleUnmaximize = handleUnmaximize;
+ createMenu(files);
+
+ if(tray) {
+ createTray();
+ }
+
+ if (environment === 'development') {
+ mainWindow.webContents.openDevTools();
+ }
+
const customStylesPath: string = configStorage.get('customStylesPath');
if(customStylesPath) {
fs.readFile(customStylesPath, 'utf8', (error: Error | null, data) => {
@@ -149,16 +158,17 @@ const createMainWindow = () => {
}
const handleReadyToShow = async () => {
+ const files: FileObject[] = (configStorage.get('files') as FileObject[]) || [];
if(files?.length > 0) {
createFileWatcher(files);
}
}
const handleWindowAllClosed = () => {
- tray = configStorage.get('tray');
+ const tray = configStorage.get('tray');
if(process.platform !== 'darwin' && !tray) {
app.quit();
- } else if(process.platform === 'darwin' && tray) {
+ } else if(!process.mas && process.platform === 'darwin' && tray) {
app.dock?.hide();
} else {
mainWindow?.hide();
@@ -183,12 +193,6 @@ app
createMainWindow();
- createMenu(files);
-
- if(tray) {
- createTray();
- }
-
eventListeners.handleCreateWindow = handleCreateWindow
eventListeners.handleWindowAllClosed = handleWindowAllClosed
eventListeners.handleBeforeQuit = handleBeforeQuit;
diff --git a/src/main/modules/File/Watcher.tsx b/src/main/modules/File/Watcher.tsx
index 4f49984c..a9101966 100644
--- a/src/main/modules/File/Watcher.tsx
+++ b/src/main/modules/File/Watcher.tsx
@@ -1,5 +1,5 @@
import chokidar, { FSWatcher } from 'chokidar';
-import processDataRequest from '../ProcessDataRequest/ProcessDataRequest';
+import { processDataRequest, searchString } from '../ProcessDataRequest/ProcessDataRequest';
import { configStorage } from '../../config';
import { eventListeners } from '../../main';
@@ -24,7 +24,7 @@ function createFileWatcher(files: FileObject[]): void {
})
.on('change', async (file) => {
try {
- await processDataRequest();
+ await processDataRequest(searchString);
console.log(`${file} has been changed`);
} catch(error: any) {
console.error(error.message);
diff --git a/src/main/modules/Ipc.tsx b/src/main/modules/Ipc.tsx
index be40b2f7..9479f989 100644
--- a/src/main/modules/Ipc.tsx
+++ b/src/main/modules/Ipc.tsx
@@ -1,6 +1,6 @@
import { shell } from 'electron';
import { ipcMain, app, IpcMainEvent, clipboard } from 'electron';
-import processDataRequest from './ProcessDataRequest/ProcessDataRequest';
+import { processDataRequest } from './ProcessDataRequest/ProcessDataRequest';
import { changeCompleteState } from './ProcessDataRequest/ChangeCompleteState';
import { writeTodoObjectToFile, removeLineFromFile } from './File/Write';
import { archiveTodos, handleRequestArchive } from './File/Archive';
diff --git a/src/main/modules/Menu.tsx b/src/main/modules/Menu.tsx
index aa007919..462fda15 100644
--- a/src/main/modules/Menu.tsx
+++ b/src/main/modules/Menu.tsx
@@ -4,6 +4,7 @@ import { mainWindow } from '../main';
import { openFile, createFile } from './File/Dialog';
import { handleRequestArchive } from './File/Archive';
import { configStorage, filterStorage } from '../config';
+import { isCyrillic } from '../util';
import appPackage from '../../../release/app/package.json';
const isMac: boolean = process.platform === 'darwin';
@@ -148,6 +149,13 @@ function createMenu(files: FileObject[]) {
{
label: 'Todos',
submenu: [
+ {
+ label: 'Add new todo',
+ accelerator: 'CmdOrCtrl+N',
+ click: () => {
+ mainWindow!.webContents.send('isDialogOpen');
+ },
+ },
{
label: 'Find',
accelerator: 'CmdOrCtrl+F',
@@ -166,7 +174,7 @@ function createMenu(files: FileObject[]) {
},
{
label: 'Reset filters',
- accelerator: 'Ctrl+0',
+ accelerator: 'CmdOrCtrl+0',
click: async () => {
filterStorage.set('filters', {});
},
diff --git a/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx b/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx
index 39c28bd2..8d26a390 100644
--- a/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx
+++ b/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx
@@ -11,12 +11,18 @@ function createTodoObject(index: number, string: string, attributeType?: string,
let content = string.replaceAll(/[\x10\r\n]/g, ' [LB] ');
let JsTodoTxtObject = new Item(content);
+ const extensions = JsTodoTxtObject.extensions();
- if(attributeType && attributeValue) {
+ if(attributeType) {
if(attributeType === 'priority') {
- JsTodoTxtObject.setPriority(attributeValue);
+ const value = (attributeValue === '-') ? null : attributeValue;
+ JsTodoTxtObject.setPriority(value);
} else {
- JsTodoTxtObject.setExtension(attributeType, attributeValue);
+ if(!attributeValue) {
+ JsTodoTxtObject.removeExtension(attributeType);
+ } else {
+ JsTodoTxtObject.setExtension(attributeType, attributeValue);
+ }
}
}
@@ -29,7 +35,7 @@ function createTodoObject(index: number, string: string, attributeType?: string,
const notify = speakingDates['due:']?.notify || false;
const t = speakingDates['t:']?.date || null;
const tString = speakingDates['t:']?.string || null;
- const extensions = JsTodoTxtObject.extensions();
+
const hidden = extensions.some(extension => extension.key === 'h' && extension.value === '1');
const pm: string | number | null = extensions.find(extension => extension.key === 'pm')?.value || null;
const rec = extensions.find(extension => extension.key === 'rec')?.value || null;
diff --git a/src/main/modules/ProcessDataRequest/ProcessDataRequest.tsx b/src/main/modules/ProcessDataRequest/ProcessDataRequest.tsx
index 735edea4..bfaafdd0 100644
--- a/src/main/modules/ProcessDataRequest/ProcessDataRequest.tsx
+++ b/src/main/modules/ProcessDataRequest/ProcessDataRequest.tsx
@@ -61,4 +61,4 @@ async function processDataRequest(search?: string): Promise {
mainWindow!.webContents.send('requestData', requestedData);
}
-export default processDataRequest;
+export { processDataRequest, searchString };
diff --git a/src/renderer/App.scss b/src/renderer/App.scss
index 8e94e895..dec5d87b 100644
--- a/src/renderer/App.scss
+++ b/src/renderer/App.scss
@@ -18,12 +18,10 @@ body {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-
code {
background: $lighter-grey;
color: $mid-grey;
}
-
#root {
.flexContainer {
display: flex;
@@ -40,7 +38,6 @@ body {
display: flex;
flex-direction: column;
}
-
&.hideNavigation {
transition: margin-left 0.3s ease;
margin-left: 0;
diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx
index 1553085c..18215b41 100644
--- a/src/renderer/App.tsx
+++ b/src/renderer/App.tsx
@@ -4,7 +4,7 @@ import IpcComponent from './Ipc';
import MatomoComponent from './Matomo';
import { CssBaseline, Snackbar, Alert, Box, AlertColor } from '@mui/material';
import NavigationComponent from './Navigation';
-import TodoDataGrid from './DataGrid/Grid';
+import GridComponent from './Grid/Grid';
import SplashScreen from './SplashScreen';
import FileTabs from './Header/FileTabs';
import { darkTheme, lightTheme } from './Themes';
@@ -140,7 +140,7 @@ const App = () => {
)}
{todoObjects && todoObjects.length > 0 && (
<>
- = ({
const handleChange = (date: dayjs.Dayjs | null) => {
try {
- ipcRenderer.send('updateTodoObject', todoObject?.id, textFieldValue, type, dayjs(date).format('YYYY-MM-DD'));
+ const dateString = (date) ? dayjs(date).format('YYYY-MM-DD') : null;
+ ipcRenderer.send('updateTodoObject', todoObject?.id, textFieldValue, type, dateString);
} catch(error: any) {
console.error(error);
}
@@ -41,8 +42,11 @@ const DatePickerComponent: React.FC = ({
label={t(`todoDialog.datePicker.${type}`)}
value={date ? dayjs(date) : null}
onChange={(date) => handleChange(date)}
- data-testid={`data-testid=dialog-picker-date-${type}`}
- InputProps={{"data-testid": `dialog-picker-date-${type}`}}
+ // data-testid={`dialog-picker-date-${type}`}
+ // InputProps={{ 'data-testid': `dialog-picker-date-${type}` }}
+ slotProps={{
+ field: { clearable: true, onClear: () => handleChange(null) },
+ }}
/>
);
diff --git a/src/renderer/Dialog/Dialog.tsx b/src/renderer/Dialog/Dialog.tsx
index 3724e0c2..db78ade4 100644
--- a/src/renderer/Dialog/Dialog.tsx
+++ b/src/renderer/Dialog/Dialog.tsx
@@ -73,7 +73,7 @@ const DialogComponent: React.FC = memo(({
};
const handleKeyDown = (event: any) => {
- if(event.metaKey && event.key === 'Enter') {
+ if((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
event.preventDefault();
handleAdd();
}
diff --git a/src/renderer/Dialog/PomodoroPicker.tsx b/src/renderer/Dialog/PomodoroPicker.tsx
index 3b4be72d..c9b92d19 100644
--- a/src/renderer/Dialog/PomodoroPicker.tsx
+++ b/src/renderer/Dialog/PomodoroPicker.tsx
@@ -19,7 +19,8 @@ const PomodoroPicker: React.FC = ({
const handleChange = (event: React.ChangeEvent) => {
try {
- ipcRenderer.send('updateTodoObject', todoObject?.id, textFieldValue, 'pm', event.target.value);
+ const value = (event.target.value === '0') ? null : event.target.value;
+ ipcRenderer.send('updateTodoObject', todoObject?.id, textFieldValue, 'pm', value);
} catch(error: any) {
console.error(error);
}
diff --git a/src/renderer/DataGrid/DatePickerInline.tsx b/src/renderer/Grid/DatePickerInline.tsx
similarity index 96%
rename from src/renderer/DataGrid/DatePickerInline.tsx
rename to src/renderer/Grid/DatePickerInline.tsx
index b32d4b3a..d7d617ba 100644
--- a/src/renderer/DataGrid/DatePickerInline.tsx
+++ b/src/renderer/Grid/DatePickerInline.tsx
@@ -67,7 +67,10 @@ const DatePickerInline: React.FC = ({
};
return (
>;
@@ -17,7 +17,7 @@ interface TodoDataGridProps {
setLoadMoreRows: React.Dispatch>;
}
-const TodoDataGrid: React.FC = memo(({
+const GridComponent: React.FC = memo(({
todoObjects,
filters,
setDialogOpen,
@@ -31,7 +31,7 @@ const TodoDataGrid: React.FC = memo(({
setLoadMoreRows,
}) => {
- const list = document.getElementById('dataGrid');
+ const list = document.getElementById('grid');
const totalRowCount = todoObjects?.length || 0;
const handleKeyUp = (event: KeyboardEvent) => {
@@ -83,7 +83,7 @@ const TodoDataGrid: React.FC = memo(({
const visibleTodoObjects = todoObjects?.slice(0, visibleRowCount);
return (
-
+
{visibleTodoObjects?.map((row, index) => (
= memo(({
);
});
-export default TodoDataGrid;
+export default GridComponent;
diff --git a/src/renderer/DataGrid/Group.tsx b/src/renderer/Grid/Group.tsx
similarity index 100%
rename from src/renderer/DataGrid/Group.tsx
rename to src/renderer/Grid/Group.tsx
diff --git a/src/renderer/DataGrid/Row.scss b/src/renderer/Grid/Row.scss
similarity index 100%
rename from src/renderer/DataGrid/Row.scss
rename to src/renderer/Grid/Row.scss
diff --git a/src/renderer/DataGrid/Row.tsx b/src/renderer/Grid/Row.tsx
similarity index 100%
rename from src/renderer/DataGrid/Row.tsx
rename to src/renderer/Grid/Row.tsx
diff --git a/src/renderer/Navigation.tsx b/src/renderer/Navigation.tsx
index 216e0304..04a44319 100644
--- a/src/renderer/Navigation.tsx
+++ b/src/renderer/Navigation.tsx
@@ -7,6 +7,7 @@ import SettingsIcon from '@mui/icons-material/Settings';
import KeyboardArrowLeftIcon from '@mui/icons-material/KeyboardArrowLeft';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import { Button, Box } from '@mui/material';
+import { isCyrillic } from './Shared';
import './Navigation.scss';
const { ipcRenderer, store } = window.api;
@@ -28,21 +29,26 @@ const NavigationComponent: React.FC = memo(({
}) => {
const handleOpen = () => {
- setTodoObject(null);
- setDialogOpen(true);
+ if(settings.files?.length > 0) {
+ setTodoObject(null);
+ setDialogOpen(true);
+ }
};
useEffect(() => {
- const handleKeyDown = (event: KeyboardEvent) => {
- if(settings.files?.length > 0 && (event.metaKey || event.ctrlKey) && event.key === 'n') {
+ const handleKeyDown = (event) => {
+ if(event.ctrlKey & event.key === 'т') {
handleOpen();
}
};
- document.addEventListener('keydown', handleKeyDown);
+
+ ipcRenderer.on('isDialogOpen', handleOpen);
+ if(isCyrillic()) document.addEventListener('keydown', handleKeyDown)
return () => {
- document.removeEventListener('keydown', handleKeyDown);
+ ipcRenderer.off('isDialogOpen', handleOpen);
+ if(isCyrillic()) document.removeEventListener('keydown', handleKeyDown)
};
- }, [settings.files]);
+ }, []);
return (
<>
diff --git a/src/renderer/Settings/Settings.scss b/src/renderer/Settings/Settings.scss
index b7af75a5..532f0140 100644
--- a/src/renderer/Settings/Settings.scss
+++ b/src/renderer/Settings/Settings.scss
@@ -23,4 +23,12 @@
.MuiSelect-select {
min-width: 9em;
}
+ .MuiBadge-badge {
+ top: 0.3em;
+ right: -0.3em;
+ svg {
+ font-size: 1.2em;
+ color: $blue;
+ }
+ }
}
diff --git a/src/renderer/Settings/Settings.tsx b/src/renderer/Settings/Settings.tsx
index 20f7ca52..4f1d59ac 100644
--- a/src/renderer/Settings/Settings.tsx
+++ b/src/renderer/Settings/Settings.tsx
@@ -1,5 +1,6 @@
import React, { useEffect, memo } from 'react';
-import { Box, FormControl, FormControlLabel, InputLabel, MenuItem, Modal, Select, Switch, Slider } from '@mui/material';
+import { Link, Badge, Box, FormControl, FormControlLabel, InputLabel, MenuItem, Modal, Select, Switch, Slider } from '@mui/material';
+import HelpIcon from '@mui/icons-material/Help';
import { withTranslation, WithTranslation } from 'react-i18next';
import LanguageSelector, { i18n } from './LanguageSelector';
import './Settings.scss';
@@ -35,6 +36,7 @@ const visibleSettings: VisibleSettings = {
},
notificationsAllowed: {
style: 'toggle',
+ help: 'https://github.com/ransome1/sleek/wiki/Notifications-and-badges',
},
notificationThreshold: {
style: 'slider',
@@ -42,6 +44,7 @@ const visibleSettings: VisibleSettings = {
max: 10,
unit: ' days',
step: 1,
+ help: 'https://github.com/ransome1/sleek/wiki/Notifications-and-badges',
},
zoom: {
style: 'slider',
@@ -84,7 +87,19 @@ const Settings: React.FC = memo(({
name={settingName}
/>
}
- label={t(`settings.${settingName}`)}
+ label={
+ settingValue.help ? (
+
+
+
+ }>
+ {t(`settings.${settingName}`)}
+
+ ) : (
+ t(`settings.${settingName}`)
+ )
+ }
/>
) : (
settingValue.style === 'select' ? (
diff --git a/src/renderer/Shared.tsx b/src/renderer/Shared.tsx
index 2adee625..1462fd38 100644
--- a/src/renderer/Shared.tsx
+++ b/src/renderer/Shared.tsx
@@ -34,4 +34,9 @@ export const handleFilterSelect = (key: string, value: string | string[] | null,
} catch (error: any) {
console.error(error);
}
+};
+
+export const isCyrillic = () => {
+ const locale = navigator.language;
+ return locale.includes('ru') || locale.includes('bg') || locale.includes('sr') || locale.includes('uk') || locale.includes('be') || locale.includes('mk') || locale.includes('ky') || locale.includes('kk') || locale.includes('mn') || locale.includes('tg') || locale.includes('tt') || locale.includes('uz');
};
\ No newline at end of file