From 60184425283d337565e30fd90cf85133ffea5cdd Mon Sep 17 00:00:00 2001 From: ransome1 Date: Thu, 4 Jan 2024 22:36:55 +0100 Subject: [PATCH] Added background color to mainWindow, which should avoid some flickering during window creation, added help icons to settings, fixed lost search string, setting pm: to 0 will remove it, added clear date icon to date picker in dialog, fixed Ctrl & N shortcut on cyrillic keyboards --- flatpak/com.github.ransome1.sleek.appdata.xml | 2 +- flatpak/com.github.ransome1.sleek.desktop | 2 +- package.json | 7 ++-- release/app/package.json | 4 +- snap/snapcraft.yaml | 2 +- src/main/config.tsx | 6 +-- src/main/main.tsx | 38 ++++++++++--------- src/main/modules/File/Watcher.tsx | 4 +- src/main/modules/Ipc.tsx | 2 +- src/main/modules/Menu.tsx | 10 ++++- .../ProcessDataRequest/CreateTodoObjects.tsx | 14 +++++-- .../ProcessDataRequest/ProcessDataRequest.tsx | 2 +- src/renderer/App.scss | 3 -- src/renderer/App.tsx | 4 +- src/renderer/Dialog/DatePicker.scss | 2 +- src/renderer/Dialog/DatePicker.tsx | 10 +++-- src/renderer/Dialog/Dialog.tsx | 2 +- src/renderer/Dialog/PomodoroPicker.tsx | 3 +- .../{DataGrid => Grid}/DatePickerInline.tsx | 5 ++- src/renderer/{DataGrid => Grid}/Elements.tsx | 0 src/renderer/{DataGrid => Grid}/Grid.scss | 4 +- src/renderer/{DataGrid => Grid}/Grid.tsx | 10 ++--- src/renderer/{DataGrid => Grid}/Group.tsx | 0 src/renderer/{DataGrid => Grid}/Row.scss | 0 src/renderer/{DataGrid => Grid}/Row.tsx | 0 src/renderer/Navigation.tsx | 20 ++++++---- src/renderer/Settings/Settings.scss | 8 ++++ src/renderer/Settings/Settings.tsx | 19 +++++++++- src/renderer/Shared.tsx | 5 +++ 29 files changed, 123 insertions(+), 65 deletions(-) rename src/renderer/{DataGrid => Grid}/DatePickerInline.tsx (96%) rename src/renderer/{DataGrid => Grid}/Elements.tsx (100%) rename src/renderer/{DataGrid => Grid}/Grid.scss (94%) rename src/renderer/{DataGrid => Grid}/Grid.tsx (92%) rename src/renderer/{DataGrid => Grid}/Group.tsx (100%) rename src/renderer/{DataGrid => Grid}/Row.scss (100%) rename src/renderer/{DataGrid => Grid}/Row.tsx (100%) 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