diff --git a/src/@types/Settings.ts b/src/@types/Settings.ts index 3c43aa9e..ca516931 100644 --- a/src/@types/Settings.ts +++ b/src/@types/Settings.ts @@ -20,6 +20,7 @@ export interface SettingStore { menuBarVisibility: boolean; disableAnimations: boolean; compact: boolean; + multiLineView: boolean; zoom: number; matomo: boolean; diff --git a/src/locales/cs.json b/src/locales/cs.json index 20599660..9d51e5be 100644 --- a/src/locales/cs.json +++ b/src/locales/cs.json @@ -35,6 +35,7 @@ "settings.6": "Sobota", "settings.menuBarVisibility": "Zobrazit menu v panelu", "settings.compact": "Kompaktní zobrazení", + "settings.multiLineView": "Dvouřádkové zobrazení", "attributes": "Atributy", "filters": "Filtry", "sorting": "Řazení", diff --git a/src/locales/de.json b/src/locales/de.json index 8caef7a8..ebde16a5 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -35,6 +35,7 @@ "settings.6": "Samstag", "settings.menuBarVisibility": "Menüleiste anzeigen", "settings.compact": "Kompakte Ansicht", + "settings.multiLineView": "Zweizeilige Ansicht", "attributes": "Attribute", "filters": "Filter", "sorting": "Sortierung", diff --git a/src/locales/en.json b/src/locales/en.json index e13441af..d5620ba2 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -35,6 +35,7 @@ "settings.6": "Saturday", "settings.menuBarVisibility": "Show menu bar", "settings.compact": "Compact view", + "settings.multiLineView": "Two-row view", "attributes": "Attributes", "filters": "Filters", "sorting": "Sorting", diff --git a/src/locales/es.json b/src/locales/es.json index 7705b71e..75e17331 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -35,6 +35,7 @@ "settings.6": "Sábado", "settings.menuBarVisibility": "Mostrar barra de menú", "settings.compact": "Vista compacta", + "settings.multiLineView": "Vista de dos filas", "attributes": "Atributos", "filters": "Filtros", "sorting": "Ordenación", diff --git a/src/locales/fr.json b/src/locales/fr.json index 21789cef..51c9e8e5 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -35,6 +35,7 @@ "settings.6": "Samedi", "settings.menuBarVisibility": "Afficher la barre de menus", "settings.compact": "Vue compacte", + "settings.multiLineView": "Vue sur deux lignes", "attributes": "Attributs", "filters": "Filtres", "sorting": "Tri", diff --git a/src/locales/hi.json b/src/locales/hi.json index 73d59b04..0ad19520 100644 --- a/src/locales/hi.json +++ b/src/locales/hi.json @@ -35,6 +35,7 @@ "settings.6": "शनिवार", "settings.menuBarVisibility": "मेनू बार दिखाएं", "settings.compact": "संकुचित दृश्य", + "settings.multiLineView": "दो-पंक्ति दृश्य", "attributes": "गुण", "filters": "फ़िल्टर", "sorting": "क्रमबद्ध करना", diff --git a/src/locales/hu.json b/src/locales/hu.json index 3b0a1ebf..3cb518b9 100644 --- a/src/locales/hu.json +++ b/src/locales/hu.json @@ -35,6 +35,7 @@ "settings.6": "Szombat", "settings.menuBarVisibility": "Menüsor megjelenítése", "settings.compact": "Komplett nézet", + "settings.multiLineView": "Kétsoros nézet", "attributes": "Tulajdonságok", "filters": "Szűrők", "sorting": "Rendezés", diff --git a/src/locales/it.json b/src/locales/it.json index 10f6743a..48aac2e9 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -35,6 +35,7 @@ "settings.6": "Sabato", "settings.menuBarVisibility": "Mostra la barra dei menu", "settings.compact": "Vista compatta", + "settings.multiLineView": "Vista su due righe", "attributes": "Attributi", "filters": "Filtri", "sorting": "Ordinamento", diff --git a/src/locales/jp.json b/src/locales/jp.json index a2bdafd6..b86db9ca 100644 --- a/src/locales/jp.json +++ b/src/locales/jp.json @@ -35,6 +35,7 @@ "settings.6": "土曜日", "settings.menuBarVisibility": "メニューバーを表示する", "settings.compact": "コンパクトビュー", + "settings.multiLineView": "2行ビュー", "attributes": "属性", "filters": "フィルター", "sorting": "ソート", diff --git a/src/locales/ko.json b/src/locales/ko.json index d7a50699..4db497b7 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -35,6 +35,7 @@ "settings.6": "토요일", "settings.menuBarVisibility": "메뉴 바 표시", "settings.compact": "컴팩트 보기", + "settings.multiLineView": "두 줄 보기", "attributes": "속성", "filters": "필터", "sorting": "정렬", diff --git a/src/locales/pl.json b/src/locales/pl.json index ec854949..18093974 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -35,6 +35,7 @@ "settings.6": "Sobota", "settings.menuBarVisibility": "Pokaż pasek menu", "settings.compact": "Widok kompaktowy", + "settings.multiLineView": "Widok dwuwierszowy", "attributes": "Atrybuty", "filters": "Filtry", "sorting": "Sortowanie", diff --git a/src/locales/pt-br.json b/src/locales/pt-br.json index ef22d1c5..d11cd6fa 100644 --- a/src/locales/pt-br.json +++ b/src/locales/pt-br.json @@ -35,6 +35,7 @@ "settings.6": "Sábado", "settings.menuBarVisibility": "Mostrar barra de menus", "settings.compact": "Visão compacta", + "settings.multiLineView": "Vista em duas linhas", "attributes": "Atributos", "filters": "Filtros", "sorting": "Classificação", diff --git a/src/locales/pt.json b/src/locales/pt.json index 62a94982..ed61ec24 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -35,6 +35,7 @@ "settings.6": "Sábado", "settings.menuBarVisibility": "Mostrar barra de menu", "settings.compact": "Visão compacta", + "settings.multiLineView": "Vista em duas linhas", "attributes": "Atributos", "filters": "Filtros", "sorting": "Ordenação", diff --git a/src/locales/ru.json b/src/locales/ru.json index 8cee60c7..2bdcad1f 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -35,6 +35,7 @@ "settings.6": "Суббота", "settings.menuBarVisibility": "Показать строку меню", "settings.compact": "Компактный вид", + "settings.multiLineView": "Двухстрочный вид", "attributes": "Атрибуты", "filters": "Фильтры", "sorting": "Сортировка", diff --git a/src/locales/tr.json b/src/locales/tr.json index ffffbbb4..45547c5d 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -35,6 +35,7 @@ "settings.6": "Cumartesi", "settings.menuBarVisibility": "Menü çubuğunu göster", "settings.compact": "Kompakt görünüm", + "settings.multiLineView": "İki satırlı görünüm", "attributes": "Özellikler", "filters": "Filtreler", "sorting": "Sıralama", diff --git a/src/locales/zh.json b/src/locales/zh.json index 11f4b524..be727d0c 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -35,6 +35,7 @@ "settings.6": "周六", "settings.menuBarVisibility": "显示菜单栏", "settings.compact": "精简视图", + "settings.multiLineView": "双行视图", "attributes": "属性", "filters": "过滤器", "sorting": "排序", diff --git a/src/main/Stores.ts b/src/main/Stores.ts index 5f741f5d..d8be7127 100644 --- a/src/main/Stores.ts +++ b/src/main/Stores.ts @@ -145,6 +145,10 @@ const migrations = { config.set("invertTrayColor", false); config.set("startMinimized", false); }, + "2.0.27": (config) => { + console.log("Migrating settings store from 2.0.19 → 2.0.27"); + config.set("multiLineView", false); + }, }; const rerenderDefinition = { diff --git a/src/renderer/Grid/Renderer.tsx b/src/renderer/Grid/Renderer.tsx index c30b0948..dbc2f47f 100644 --- a/src/renderer/Grid/Renderer.tsx +++ b/src/renderer/Grid/Renderer.tsx @@ -114,7 +114,159 @@ const RendererComponent: React.FC = memo( return uri; }; + const linkOptions: Components = { + a: ({ children, href, ...props }): JSX.Element | null => { + if (!children) return null; + const childrenStr = + typeof children === "string" ? children : String(children); + const match = /([a-zA-Z]+:\/\/\S+)/g.exec(childrenStr); + const maxChars = 40; + const truncatedChildren = + childrenStr.length > maxChars + ? childrenStr.slice(0, maxChars) + "..." + : childrenStr; + + const link = ( + + handleLinkClick(event, match ? childrenStr : href || childrenStr) + } + > + {truncatedChildren} + + + ); + + return childrenStr.length > maxChars ? ( + + {link} + + ) : ( + link + ); + }, + }; + + if (settings.multiLineView) { + let cleanBody = todoObject.body; + for (const { pattern } of expressions) { + cleanBody = cleanBody.replace(new RegExp(pattern.source, "g"), ""); + } + cleanBody = cleanBody.replace(/\s+/g, " ").trim(); + + const badgeElements: React.ReactNode[] = []; + + const dateBadges: Array<{ type: "due" | "t"; value: string | null }> = [ + { type: "due", value: todoObject.due }, + { type: "t", value: todoObject.t }, + ]; + dateBadges.forEach(({ type, value }) => { + if (!value) return; + badgeElements.push( + + + + ); + }); + + const listBadges: Array<{ type: "projects" | "contexts"; values: string[] | null }> = [ + { type: "projects", values: todoObject.projects }, + { type: "contexts", values: todoObject.contexts }, + ]; + listBadges.forEach(({ type, values }) => { + values?.forEach((value) => { + badgeElements.push( + + + + ); + }); + }); + + if (todoObject.rec) { + badgeElements.push( + + + + ); + } + + if (todoObject.pm) { + badgeElements.push( + + + + ); + } + + const multiLineComponents: Components = { + ...linkOptions, + p: ({ children }): JSX.Element | null => <>{children}, + }; + + return ( + <> + + + {cleanBody} + + + {badgeElements.length > 0 && ( + {badgeElements} + )} + + ); + } + const options: Components = { + ...linkOptions, p: ({ children }): JSX.Element | null => { const mappedChildren = React.Children.map(children, (child) => { if (typeof child !== "string") return child; @@ -146,37 +298,6 @@ const RendererComponent: React.FC = memo( }); return mappedChildren ? <>{mappedChildren} : null; }, - a: ({ children, href, ...props }): JSX.Element | null => { - if (!children) return null; - const childrenStr = - typeof children === "string" ? children : String(children); - const match = /([a-zA-Z]+:\/\/\S+)/g.exec(childrenStr); - const maxChars = 40; - const truncatedChildren = - childrenStr.length > maxChars - ? childrenStr.slice(0, maxChars) + "..." - : childrenStr; - - const link = ( - - handleLinkClick(event, match ? childrenStr : href || childrenStr) - } - > - {truncatedChildren} - - - ); - - return childrenStr.length > maxChars ? ( - - {link} - - ) : ( - link - ); - }, }; return ( diff --git a/src/renderer/Grid/Row.scss b/src/renderer/Grid/Row.scss index ef07d02e..dac11872 100644 --- a/src/renderer/Grid/Row.scss +++ b/src/renderer/Grid/Row.scss @@ -36,6 +36,10 @@ } } +.row-content { + display: contents; +} + .compact { .row { padding: 0.3em; @@ -68,6 +72,34 @@ } } +.multiLineView { + .row { + align-items: flex-start; + padding: 0.3em 0.5em; + + .row-content { + display: flex; + flex-wrap: wrap; + flex: 1; + min-width: 0; + gap: 0.25em; + align-items: center; + } + + .row-text { + flex: 1; + min-width: 0; + } + .row-badges { + width: 100%; + display: flex; + flex-wrap: wrap; + gap: 0.25em; + align-items: center; + } + } +} + .dark { .row { border-color: Variables.$dark-grey; diff --git a/src/renderer/Grid/Row.tsx b/src/renderer/Grid/Row.tsx index 284cb5d7..117e0a2a 100644 --- a/src/renderer/Grid/Row.tsx +++ b/src/renderer/Grid/Row.tsx @@ -174,67 +174,69 @@ const Row: React.FC = memo( onChange={handleCheckboxChange} /> - {(settings.sorting[0].value != "priority" || settings.fileSorting) && - todoObject.priority && ( - - - + + + )} + + {todoObject.completed && ( + + + )} - {todoObject.completed && ( - - - - )} - - {todoObject.created && ( - - - - )} - - {todoObject.hidden && ( - - )} - - + {todoObject.created && ( + + + + )} + + {todoObject.hidden && ( + + )} + + + ); diff --git a/src/renderer/Settings/Settings.tsx b/src/renderer/Settings/Settings.tsx index 7bd031da..5ec9a7a1 100644 --- a/src/renderer/Settings/Settings.tsx +++ b/src/renderer/Settings/Settings.tsx @@ -76,6 +76,9 @@ const visibleSettings: VisibleSettings = { compact: { style: "toggle", }, + multiLineView: { + style: "toggle", + }, notificationsAllowed: { style: "toggle", }, @@ -133,7 +136,7 @@ const SettingsComponent: React.FC = memo( }, [settings.language]); useEffect(() => { - const { shouldUseDarkColors, zoom, compact, disableAnimations } = + const { shouldUseDarkColors, zoom, compact, disableAnimations, multiLineView } = settings; const adjustedFontSize = Math.round(14 * (zoom / 100)); @@ -149,17 +152,19 @@ const SettingsComponent: React.FC = memo( document.body.classList.toggle("disableAnimations", disableAnimations); document.body.classList.toggle("compact", compact); + document.body.classList.toggle("multiLineView", multiLineView); document.body.classList.toggle("dark", shouldUseDarkColors); document.body.classList.toggle("light", !shouldUseDarkColors); return () => { - document.body.classList.remove("dark", "light", "compact"); + document.body.classList.remove("dark", "light", "compact", "multiLineView"); }; }, [ settings.shouldUseDarkColors, settings.zoom, settings.compact, settings.disableAnimations, + settings.multiLineView, ]); const { t } = useTranslation();