diff --git a/public/locales/ar.json b/public/locales/ar.json index 5ab9b24..b479d01 100644 --- a/public/locales/ar.json +++ b/public/locales/ar.json @@ -118,7 +118,23 @@ "customizeDrag": "اسحب الأداة", "customizeSize": "الحجم", "customizeSizeFor": "حجم {{widget}}", - "customizeHide": "إخفاء {{widget}}" + "customizeHide": "إخفاء {{widget}}", + "widgetSize_1_1": "c · 1 عرض x 1 ارتفاع", + "widgetSize_1_2": "t · 1 عرض x 2 ارتفاع", + "widgetSize_1_3": "col · 1 عرض x 3 ارتفاع", + "widgetSize_1_4": "tower · 1 عرض x 4 ارتفاع", + "widgetSize_2_1": "w · 2 عرض x 1 ارتفاع", + "widgetSize_2_2": "f · 2 عرض x 2 ارتفاع", + "widgetSize_2_3": "tf · 2 عرض x 3 ارتفاع", + "widgetSize_2_4": "poster · 2 عرض x 4 ارتفاع", + "widgetSize_3_1": "pan · 3 عرض x 1 ارتفاع", + "widgetSize_3_2": "show · 3 عرض x 2 ارتفاع", + "widgetSize_3_3": "board · 3 عرض x 3 ارتفاع", + "widgetSize_4_1": "row · 4 عرض x 1 ارتفاع", + "widgetSize_4_2": "banner · 4 عرض x 2 ارتفاع", + "widgetSize_3_4": "جدار · 3 عرض x 4 ارتفاع", + "widgetSize_4_3": "مركز التحكم · 4 عرض x 3 ارتفاع", + "widgetSize_4_4": "لوحة · 4 عرض x 4 ارتفاع" }, "tasks": { "title": "المهام", diff --git a/public/locales/de.json b/public/locales/de.json index 661f0c0..22c39b2 100644 --- a/public/locales/de.json +++ b/public/locales/de.json @@ -124,7 +124,23 @@ "customizeDrag": "Widget ziehen", "customizeSize": "Größe", "customizeSizeFor": "Größe für {{widget}}", - "customizeHide": "{{widget}} ausblenden" + "customizeHide": "{{widget}} ausblenden", + "widgetSize_1_1": "c · 1 breit x 1 hoch", + "widgetSize_1_2": "t · 1 breit x 2 hoch", + "widgetSize_1_3": "col · 1 breit x 3 hoch", + "widgetSize_1_4": "tower · 1 breit x 4 hoch", + "widgetSize_2_1": "w · 2 breit x 1 hoch", + "widgetSize_2_2": "f · 2 breit x 2 hoch", + "widgetSize_2_3": "tf · 2 breit x 3 hoch", + "widgetSize_2_4": "poster · 2 breit x 4 hoch", + "widgetSize_3_1": "pan · 3 breit x 1 hoch", + "widgetSize_3_2": "show · 3 breit x 2 hoch", + "widgetSize_3_3": "board · 3 breit x 3 hoch", + "widgetSize_4_1": "row · 4 breit x 1 hoch", + "widgetSize_4_2": "banner · 4 breit x 2 hoch", + "widgetSize_3_4": "Wand · 3 breit x 4 hoch", + "widgetSize_4_3": "Kommandozentrale · 4 breit x 3 hoch", + "widgetSize_4_4": "Leinwand · 4 breit x 4 hoch" }, "tasks": { "title": "Aufgaben", diff --git a/public/locales/el.json b/public/locales/el.json index a5a006f..47a337b 100644 --- a/public/locales/el.json +++ b/public/locales/el.json @@ -118,7 +118,23 @@ "customizeDrag": "Σύρετε widget", "customizeSize": "Μέγεθος", "customizeSizeFor": "Μέγεθος για {{widget}}", - "customizeHide": "Απόκρυψη {{widget}}" + "customizeHide": "Απόκρυψη {{widget}}", + "widgetSize_1_1": "c · 1 πλάτος x 1 ύψος", + "widgetSize_1_2": "t · 1 πλάτος x 2 ύψος", + "widgetSize_1_3": "col · 1 πλάτος x 3 ύψος", + "widgetSize_1_4": "tower · 1 πλάτος x 4 ύψος", + "widgetSize_2_1": "w · 2 πλάτος x 1 ύψος", + "widgetSize_2_2": "f · 2 πλάτος x 2 ύψος", + "widgetSize_2_3": "tf · 2 πλάτος x 3 ύψος", + "widgetSize_2_4": "poster · 2 πλάτος x 4 ύψος", + "widgetSize_3_1": "pan · 3 πλάτος x 1 ύψος", + "widgetSize_3_2": "show · 3 πλάτος x 2 ύψος", + "widgetSize_3_3": "board · 3 πλάτος x 3 ύψος", + "widgetSize_4_1": "row · 4 πλάτος x 1 ύψος", + "widgetSize_4_2": "banner · 4 πλάτος x 2 ύψος", + "widgetSize_3_4": "Τοίχος · 3 πλάτος x 4 ύψος", + "widgetSize_4_3": "Κέντρο ελέγχου · 4 πλάτος x 3 ύψος", + "widgetSize_4_4": "Καμβάς · 4 πλάτος x 4 ύψος" }, "tasks": { "title": "Εργασίες", diff --git a/public/locales/en.json b/public/locales/en.json index d58122a..20bae10 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -118,7 +118,23 @@ "customizeDrag": "Drag widget", "customizeSize": "Size", "customizeSizeFor": "Size for {{widget}}", - "customizeHide": "Hide {{widget}}" + "customizeHide": "Hide {{widget}}", + "widgetSize_1_1": "c · 1 wide x 1 tall", + "widgetSize_1_2": "t · 1 wide x 2 tall", + "widgetSize_1_3": "col · 1 wide x 3 tall", + "widgetSize_1_4": "tower · 1 wide x 4 tall", + "widgetSize_2_1": "w · 2 wide x 1 tall", + "widgetSize_2_2": "f · 2 wide x 2 tall", + "widgetSize_2_3": "tf · 2 wide x 3 tall", + "widgetSize_2_4": "poster · 2 wide x 4 tall", + "widgetSize_3_1": "pan · 3 wide x 1 tall", + "widgetSize_3_2": "show · 3 wide x 2 tall", + "widgetSize_3_3": "board · 3 wide x 3 tall", + "widgetSize_4_1": "row · 4 wide x 1 tall", + "widgetSize_4_2": "banner · 4 wide x 2 tall", + "widgetSize_3_4": "Wall · 3 wide x 4 tall", + "widgetSize_4_3": "Command center · 4 wide x 3 tall", + "widgetSize_4_4": "Canvas · 4 wide x 4 tall" }, "tasks": { "title": "Tasks", diff --git a/public/locales/es.json b/public/locales/es.json index a2b438f..1fd2cfa 100644 --- a/public/locales/es.json +++ b/public/locales/es.json @@ -118,7 +118,23 @@ "customizeDrag": "Arrastrar widget", "customizeSize": "Tamaño", "customizeSizeFor": "Tamaño de {{widget}}", - "customizeHide": "Ocultar {{widget}}" + "customizeHide": "Ocultar {{widget}}", + "widgetSize_1_1": "c · 1 ancho x 1 alto", + "widgetSize_1_2": "t · 1 ancho x 2 alto", + "widgetSize_1_3": "col · 1 ancho x 3 alto", + "widgetSize_1_4": "tower · 1 ancho x 4 alto", + "widgetSize_2_1": "w · 2 ancho x 1 alto", + "widgetSize_2_2": "f · 2 ancho x 2 alto", + "widgetSize_2_3": "tf · 2 ancho x 3 alto", + "widgetSize_2_4": "poster · 2 ancho x 4 alto", + "widgetSize_3_1": "pan · 3 ancho x 1 alto", + "widgetSize_3_2": "show · 3 ancho x 2 alto", + "widgetSize_3_3": "board · 3 ancho x 3 alto", + "widgetSize_4_1": "row · 4 ancho x 1 alto", + "widgetSize_4_2": "banner · 4 ancho x 2 alto", + "widgetSize_3_4": "Mural · 3 ancho x 4 alto", + "widgetSize_4_3": "Centro de control · 4 ancho x 3 alto", + "widgetSize_4_4": "Lienzo · 4 ancho x 4 alto" }, "tasks": { "title": "Tareas", diff --git a/public/locales/fr.json b/public/locales/fr.json index 4e5d188..7b0e577 100644 --- a/public/locales/fr.json +++ b/public/locales/fr.json @@ -118,7 +118,23 @@ "customizeDrag": "Faire glisser le widget", "customizeSize": "Taille", "customizeSizeFor": "Taille de {{widget}}", - "customizeHide": "Masquer {{widget}}" + "customizeHide": "Masquer {{widget}}", + "widgetSize_1_1": "c · 1 large x 1 haut", + "widgetSize_1_2": "t · 1 large x 2 haut", + "widgetSize_1_3": "col · 1 large x 3 haut", + "widgetSize_1_4": "tower · 1 large x 4 haut", + "widgetSize_2_1": "w · 2 large x 1 haut", + "widgetSize_2_2": "f · 2 large x 2 haut", + "widgetSize_2_3": "tf · 2 large x 3 haut", + "widgetSize_2_4": "poster · 2 large x 4 haut", + "widgetSize_3_1": "pan · 3 large x 1 haut", + "widgetSize_3_2": "show · 3 large x 2 haut", + "widgetSize_3_3": "board · 3 large x 3 haut", + "widgetSize_4_1": "row · 4 large x 1 haut", + "widgetSize_4_2": "banner · 4 large x 2 haut", + "widgetSize_3_4": "Mur · 3 large x 4 haut", + "widgetSize_4_3": "Centre de commande · 4 large x 3 haut", + "widgetSize_4_4": "Toile · 4 large x 4 haut" }, "tasks": { "title": "Tâches", diff --git a/public/locales/hi.json b/public/locales/hi.json index f54f5ff..9190c81 100644 --- a/public/locales/hi.json +++ b/public/locales/hi.json @@ -118,7 +118,23 @@ "customizeDrag": "विजेट खींचें", "customizeSize": "आकार", "customizeSizeFor": "{{widget}} का आकार", - "customizeHide": "{{widget}} छिपाएँ" + "customizeHide": "{{widget}} छिपाएँ", + "widgetSize_1_1": "c · 1 चौड़ा x 1 ऊँचा", + "widgetSize_1_2": "t · 1 चौड़ा x 2 ऊँचा", + "widgetSize_1_3": "col · 1 चौड़ा x 3 ऊँचा", + "widgetSize_1_4": "tower · 1 चौड़ा x 4 ऊँचा", + "widgetSize_2_1": "w · 2 चौड़ा x 1 ऊँचा", + "widgetSize_2_2": "f · 2 चौड़ा x 2 ऊँचा", + "widgetSize_2_3": "tf · 2 चौड़ा x 3 ऊँचा", + "widgetSize_2_4": "poster · 2 चौड़ा x 4 ऊँचा", + "widgetSize_3_1": "pan · 3 चौड़ा x 1 ऊँचा", + "widgetSize_3_2": "show · 3 चौड़ा x 2 ऊँचा", + "widgetSize_3_3": "board · 3 चौड़ा x 3 ऊँचा", + "widgetSize_4_1": "row · 4 चौड़ा x 1 ऊँचा", + "widgetSize_4_2": "banner · 4 चौड़ा x 2 ऊँचा", + "widgetSize_3_4": "दीवार · 3 चौड़ा x 4 ऊँचा", + "widgetSize_4_3": "कमांड सेंटर · 4 चौड़ा x 3 ऊँचा", + "widgetSize_4_4": "कैनवास · 4 चौड़ा x 4 ऊँचा" }, "tasks": { "title": "कार्य", diff --git a/public/locales/it.json b/public/locales/it.json index d61894e..46116e1 100644 --- a/public/locales/it.json +++ b/public/locales/it.json @@ -118,7 +118,23 @@ "customizeDrag": "Trascina widget", "customizeSize": "Dimensione", "customizeSizeFor": "Dimensione di {{widget}}", - "customizeHide": "Nascondi {{widget}}" + "customizeHide": "Nascondi {{widget}}", + "widgetSize_1_1": "c · 1 largo x 1 alto", + "widgetSize_1_2": "t · 1 largo x 2 alto", + "widgetSize_1_3": "col · 1 largo x 3 alto", + "widgetSize_1_4": "tower · 1 largo x 4 alto", + "widgetSize_2_1": "w · 2 largo x 1 alto", + "widgetSize_2_2": "f · 2 largo x 2 alto", + "widgetSize_2_3": "tf · 2 largo x 3 alto", + "widgetSize_2_4": "poster · 2 largo x 4 alto", + "widgetSize_3_1": "pan · 3 largo x 1 alto", + "widgetSize_3_2": "show · 3 largo x 2 alto", + "widgetSize_3_3": "board · 3 largo x 3 alto", + "widgetSize_4_1": "row · 4 largo x 1 alto", + "widgetSize_4_2": "banner · 4 largo x 2 alto", + "widgetSize_3_4": "Parete · 3 largo x 4 alto", + "widgetSize_4_3": "Centro di comando · 4 largo x 3 alto", + "widgetSize_4_4": "Tela · 4 largo x 4 alto" }, "tasks": { "title": "Compiti", diff --git a/public/locales/ja.json b/public/locales/ja.json index 58b8df4..89cb843 100644 --- a/public/locales/ja.json +++ b/public/locales/ja.json @@ -118,7 +118,23 @@ "customizeDrag": "ウィジェットをドラッグ", "customizeSize": "サイズ", "customizeSizeFor": "{{widget}} のサイズ", - "customizeHide": "{{widget}} を非表示" + "customizeHide": "{{widget}} を非表示", + "widgetSize_1_1": "c · 1 幅 x 1 高さ", + "widgetSize_1_2": "t · 1 幅 x 2 高さ", + "widgetSize_1_3": "col · 1 幅 x 3 高さ", + "widgetSize_1_4": "tower · 1 幅 x 4 高さ", + "widgetSize_2_1": "w · 2 幅 x 1 高さ", + "widgetSize_2_2": "f · 2 幅 x 2 高さ", + "widgetSize_2_3": "tf · 2 幅 x 3 高さ", + "widgetSize_2_4": "poster · 2 幅 x 4 高さ", + "widgetSize_3_1": "pan · 3 幅 x 1 高さ", + "widgetSize_3_2": "show · 3 幅 x 2 高さ", + "widgetSize_3_3": "board · 3 幅 x 3 高さ", + "widgetSize_4_1": "row · 4 幅 x 1 高さ", + "widgetSize_4_2": "banner · 4 幅 x 2 高さ", + "widgetSize_3_4": "ウォール · 3 幅 x 4 高さ", + "widgetSize_4_3": "コマンドセンター · 4 幅 x 3 高さ", + "widgetSize_4_4": "キャンバス · 4 幅 x 4 高さ" }, "tasks": { "title": "タスク", diff --git a/public/locales/pt.json b/public/locales/pt.json index f83121f..8357872 100644 --- a/public/locales/pt.json +++ b/public/locales/pt.json @@ -118,7 +118,23 @@ "customizeDrag": "Arrastar widget", "customizeSize": "Tamanho", "customizeSizeFor": "Tamanho de {{widget}}", - "customizeHide": "Ocultar {{widget}}" + "customizeHide": "Ocultar {{widget}}", + "widgetSize_1_1": "c · 1 largura x 1 altura", + "widgetSize_1_2": "t · 1 largura x 2 altura", + "widgetSize_1_3": "col · 1 largura x 3 altura", + "widgetSize_1_4": "tower · 1 largura x 4 altura", + "widgetSize_2_1": "w · 2 largura x 1 altura", + "widgetSize_2_2": "f · 2 largura x 2 altura", + "widgetSize_2_3": "tf · 2 largura x 3 altura", + "widgetSize_2_4": "poster · 2 largura x 4 altura", + "widgetSize_3_1": "pan · 3 largura x 1 altura", + "widgetSize_3_2": "show · 3 largura x 2 altura", + "widgetSize_3_3": "board · 3 largura x 3 altura", + "widgetSize_4_1": "row · 4 largura x 1 altura", + "widgetSize_4_2": "banner · 4 largura x 2 altura", + "widgetSize_3_4": "Mural · 3 largura x 4 altura", + "widgetSize_4_3": "Central de comando · 4 largura x 3 altura", + "widgetSize_4_4": "Tela · 4 largura x 4 altura" }, "tasks": { "title": "Tarefas", diff --git a/public/locales/ru.json b/public/locales/ru.json index 3294bc6..0d0a16e 100644 --- a/public/locales/ru.json +++ b/public/locales/ru.json @@ -118,7 +118,23 @@ "customizeDrag": "Перетащить виджет", "customizeSize": "Размер", "customizeSizeFor": "Размер для {{widget}}", - "customizeHide": "Скрыть {{widget}}" + "customizeHide": "Скрыть {{widget}}", + "widgetSize_1_1": "c · 1 ширина x 1 высота", + "widgetSize_1_2": "t · 1 ширина x 2 высота", + "widgetSize_1_3": "col · 1 ширина x 3 высота", + "widgetSize_1_4": "tower · 1 ширина x 4 высота", + "widgetSize_2_1": "w · 2 ширина x 1 высота", + "widgetSize_2_2": "f · 2 ширина x 2 высота", + "widgetSize_2_3": "tf · 2 ширина x 3 высота", + "widgetSize_2_4": "poster · 2 ширина x 4 высота", + "widgetSize_3_1": "pan · 3 ширина x 1 высота", + "widgetSize_3_2": "show · 3 ширина x 2 высота", + "widgetSize_3_3": "board · 3 ширина x 3 высота", + "widgetSize_4_1": "row · 4 ширина x 1 высота", + "widgetSize_4_2": "banner · 4 ширина x 2 высота", + "widgetSize_3_4": "Стена · 3 ширина x 4 высота", + "widgetSize_4_3": "Центр управления · 4 ширина x 3 высота", + "widgetSize_4_4": "Холст · 4 ширина x 4 высота" }, "tasks": { "title": "Задачи", diff --git a/public/locales/sv.json b/public/locales/sv.json index 72ff18c..1df6cf1 100644 --- a/public/locales/sv.json +++ b/public/locales/sv.json @@ -118,7 +118,23 @@ "customizeDrag": "Dra widget", "customizeSize": "Storlek", "customizeSizeFor": "Storlek för {{widget}}", - "customizeHide": "Dölj {{widget}}" + "customizeHide": "Dölj {{widget}}", + "widgetSize_1_1": "c · 1 bred x 1 hög", + "widgetSize_1_2": "t · 1 bred x 2 hög", + "widgetSize_1_3": "col · 1 bred x 3 hög", + "widgetSize_1_4": "tower · 1 bred x 4 hög", + "widgetSize_2_1": "w · 2 bred x 1 hög", + "widgetSize_2_2": "f · 2 bred x 2 hög", + "widgetSize_2_3": "tf · 2 bred x 3 hög", + "widgetSize_2_4": "poster · 2 bred x 4 hög", + "widgetSize_3_1": "pan · 3 bred x 1 hög", + "widgetSize_3_2": "show · 3 bred x 2 hög", + "widgetSize_3_3": "board · 3 bred x 3 hög", + "widgetSize_4_1": "row · 4 bred x 1 hög", + "widgetSize_4_2": "banner · 4 bred x 2 hög", + "widgetSize_3_4": "Vägg · 3 bred x 4 hög", + "widgetSize_4_3": "Kommandocenter · 4 bred x 3 hög", + "widgetSize_4_4": "Canvas · 4 bred x 4 hög" }, "tasks": { "title": "Uppgifter", diff --git a/public/locales/tr.json b/public/locales/tr.json index edc90a8..52c18ff 100644 --- a/public/locales/tr.json +++ b/public/locales/tr.json @@ -118,7 +118,23 @@ "customizeDrag": "Widgetı sürükle", "customizeSize": "Boyut", "customizeSizeFor": "{{widget}} boyutu", - "customizeHide": "{{widget}} gizle" + "customizeHide": "{{widget}} gizle", + "widgetSize_1_1": "c · 1 geniş x 1 yüksek", + "widgetSize_1_2": "t · 1 geniş x 2 yüksek", + "widgetSize_1_3": "col · 1 geniş x 3 yüksek", + "widgetSize_1_4": "tower · 1 geniş x 4 yüksek", + "widgetSize_2_1": "w · 2 geniş x 1 yüksek", + "widgetSize_2_2": "f · 2 geniş x 2 yüksek", + "widgetSize_2_3": "tf · 2 geniş x 3 yüksek", + "widgetSize_2_4": "poster · 2 geniş x 4 yüksek", + "widgetSize_3_1": "pan · 3 geniş x 1 yüksek", + "widgetSize_3_2": "show · 3 geniş x 2 yüksek", + "widgetSize_3_3": "board · 3 geniş x 3 yüksek", + "widgetSize_4_1": "row · 4 geniş x 1 yüksek", + "widgetSize_4_2": "banner · 4 geniş x 2 yüksek", + "widgetSize_3_4": "Duvar · 3 geniş x 4 yüksek", + "widgetSize_4_3": "Komuta merkezi · 4 geniş x 3 yüksek", + "widgetSize_4_4": "Tuval · 4 geniş x 4 yüksek" }, "tasks": { "title": "Görevler", diff --git a/public/locales/uk.json b/public/locales/uk.json index a5c4872..59d63f1 100644 --- a/public/locales/uk.json +++ b/public/locales/uk.json @@ -118,7 +118,23 @@ "customizeDrag": "Перетягнути віджет", "customizeSize": "Розмір", "customizeSizeFor": "Розмір для {{widget}}", - "customizeHide": "Приховати {{widget}}" + "customizeHide": "Приховати {{widget}}", + "widgetSize_1_1": "c · 1 ширина x 1 висота", + "widgetSize_1_2": "t · 1 ширина x 2 висота", + "widgetSize_1_3": "col · 1 ширина x 3 висота", + "widgetSize_1_4": "tower · 1 ширина x 4 висота", + "widgetSize_2_1": "w · 2 ширина x 1 висота", + "widgetSize_2_2": "f · 2 ширина x 2 висота", + "widgetSize_2_3": "tf · 2 ширина x 3 висота", + "widgetSize_2_4": "poster · 2 ширина x 4 висота", + "widgetSize_3_1": "pan · 3 ширина x 1 висота", + "widgetSize_3_2": "show · 3 ширина x 2 висота", + "widgetSize_3_3": "board · 3 ширина x 3 висота", + "widgetSize_4_1": "row · 4 ширина x 1 висота", + "widgetSize_4_2": "banner · 4 ширина x 2 висота", + "widgetSize_3_4": "Стіна · 3 ширина x 4 висота", + "widgetSize_4_3": "Командний центр · 4 ширина x 3 висота", + "widgetSize_4_4": "Полотно · 4 ширина x 4 висота" }, "tasks": { "title": "Завдання", diff --git a/public/locales/zh.json b/public/locales/zh.json index edbafa1..9291600 100644 --- a/public/locales/zh.json +++ b/public/locales/zh.json @@ -118,7 +118,23 @@ "customizeDrag": "拖动小组件", "customizeSize": "大小", "customizeSizeFor": "{{widget}} 的大小", - "customizeHide": "隐藏 {{widget}}" + "customizeHide": "隐藏 {{widget}}", + "widgetSize_1_1": "c · 1 宽 x 1 高", + "widgetSize_1_2": "t · 1 宽 x 2 高", + "widgetSize_1_3": "col · 1 宽 x 3 高", + "widgetSize_1_4": "tower · 1 宽 x 4 高", + "widgetSize_2_1": "w · 2 宽 x 1 高", + "widgetSize_2_2": "f · 2 宽 x 2 高", + "widgetSize_2_3": "tf · 2 宽 x 3 高", + "widgetSize_2_4": "poster · 2 宽 x 4 高", + "widgetSize_3_1": "pan · 3 宽 x 1 高", + "widgetSize_3_2": "show · 3 宽 x 2 高", + "widgetSize_3_3": "board · 3 宽 x 3 高", + "widgetSize_4_1": "row · 4 宽 x 1 高", + "widgetSize_4_2": "banner · 4 宽 x 2 高", + "widgetSize_3_4": "墙面 · 3 宽 x 4 高", + "widgetSize_4_3": "指挥中心 · 4 宽 x 3 高", + "widgetSize_4_4": "画布 · 4 宽 x 4 高" }, "tasks": { "title": "任务", diff --git a/public/pages/dashboard.js b/public/pages/dashboard.js index 24b3049..a7668e1 100644 --- a/public/pages/dashboard.js +++ b/public/pages/dashboard.js @@ -113,16 +113,11 @@ function showOnboarding(appContainer) { // NEU — primäre Inhalte (tasks, calendar) ganz oben const WIDGET_IDS = ['tasks', 'calendar', 'weather', 'meals', 'shopping', 'birthdays', 'budget', 'family', 'notes']; -const WIDGET_SIZE_OPTIONS = ['1x1', '2x1', '2x2', '3x1', '3x2', '4x1', '4x2']; -const WIDGET_SIZE_LABELS = { - '1x1': '1x1', - '2x1': '2x1', - '2x2': '2x2', - '3x1': '3x1', - '3x2': '3x2', - '4x1': '4x1', - '4x2': '4x2', -}; +const WIDGET_SIZE_OPTIONS = ['1x1', '1x2', '1x3', '1x4', '2x1', '2x2', '2x3', '2x4', '3x1', '3x2', '3x3', '3x4', '4x1', '4x2', '4x3', '4x4']; + +function widgetSizeLabel(size) { + return t(`dashboard.widgetSize_${size.replace('x', '_')}`); +} function defaultWidgetSize(id) { if (['tasks', 'calendar'].includes(id)) return '2x2'; @@ -612,9 +607,22 @@ function widgetSizeClass(size) { return WIDGET_SIZE_OPTIONS.includes(size) ? `widget-size--${size}` : 'widget-size--1x1'; } +function renderSizeMiniGrid(size) { + return `${renderSizeMiniGridCells(size)}`; +} + +function renderSizeMiniGridCells(size) { + const [cols, rows] = size.split('x').map(Number); + return Array.from({ length: 16 }, (_, i) => { + const col = (i % 4) + 1; + const row = Math.floor(i / 4) + 1; + return ``; + }).join(''); +} + function renderWidgetCustomizeControls(w) { const sizeOptions = WIDGET_SIZE_OPTIONS.map((size) => ` - ${WIDGET_SIZE_LABELS[size]} + ${widgetSizeLabel(size)} `).join(''); return ` @@ -624,6 +632,7 @@ function renderWidgetCustomizeControls(w) { ${t('dashboard.customizeSize')} + ${renderSizeMiniGrid(w.size)} ${sizeOptions} @@ -878,7 +887,7 @@ function openCustomizeModal(currentConfig, onSave) { const isFirst = i === 0; const isLast = i === draft.length - 1; const sizeOptions = WIDGET_SIZE_OPTIONS.map((size) => ` - ${WIDGET_SIZE_LABELS[size]} + ${widgetSizeLabel(size)} `).join(''); return ` @@ -891,6 +900,7 @@ function openCustomizeModal(currentConfig, onSave) { ${widgetLabel(w.id)} ${t('dashboard.customizeSize')} + ${renderSizeMiniGrid(w.size)} ${sizeOptions} @@ -969,7 +979,13 @@ function openCustomizeModal(currentConfig, onSave) { list.querySelectorAll('[data-size-id]').forEach((select) => { select.addEventListener('change', () => { const entry = draft.find((w) => w.id === select.dataset.sizeId); - if (entry && WIDGET_SIZE_OPTIONS.includes(select.value)) entry.size = select.value; + if (!entry || !WIDGET_SIZE_OPTIONS.includes(select.value)) return; + entry.size = select.value; + const mini = select.closest('.customize-row__size')?.querySelector('.widget-size-mini'); + if (mini) { + mini.replaceChildren(); + mini.insertAdjacentHTML('afterbegin', renderSizeMiniGridCells(select.value)); + } }); }); @@ -1094,16 +1110,47 @@ function wireLinks(container, rerender, { editing = false } = {}) { }); } -function reorderWidgetConfig(config, fromId, toId) { +function reorderWidgetConfig(config, fromId, toId, placement = 'before') { const fromIdx = config.findIndex((w) => w.id === fromId); - const toIdx = config.findIndex((w) => w.id === toId); + let toIdx = config.findIndex((w) => w.id === toId); if (fromIdx === -1 || toIdx === -1 || fromIdx === toIdx) return config; const next = config.map((w) => ({ ...w })); const [moved] = next.splice(fromIdx, 1); + if (fromIdx < toIdx) toIdx -= 1; + if (placement === 'after') toIdx += 1; next.splice(toIdx, 0, moved); return next.map((w, i) => ({ ...w, order: i })); } +function closestWidgetDrop(grid, event, draggedId) { + const candidates = [...grid.querySelectorAll('.widget-wrapper[data-widget-id]')] + .filter((item) => item.dataset.widgetId !== draggedId); + if (!candidates.length) return null; + + let nearest = null; + let nearestDistance = Number.POSITIVE_INFINITY; + for (const item of candidates) { + const rect = item.getBoundingClientRect(); + const centerX = rect.left + rect.width / 2; + const centerY = rect.top + rect.height / 2; + const dx = event.clientX - centerX; + const dy = event.clientY - centerY; + const distance = (dy * dy * 1.7) + (dx * dx); + if (distance < nearestDistance) { + nearestDistance = distance; + nearest = { item, rect }; + } + } + if (!nearest) return null; + + const sameRow = event.clientY >= nearest.rect.top && event.clientY <= nearest.rect.bottom; + const placement = sameRow + ? (event.clientX > nearest.rect.left + nearest.rect.width / 2 ? 'after' : 'before') + : (event.clientY > nearest.rect.top + nearest.rect.height / 2 ? 'after' : 'before'); + + return { id: nearest.item.dataset.widgetId, placement, item: nearest.item }; +} + function updateWidgetConfig(config, id, patch) { return config.map((w) => w.id === id ? { ...w, ...patch } : w) .map((w, i) => ({ ...w, order: i })); @@ -1179,6 +1226,23 @@ export async function render(container, { user }) { const grid = container.querySelector('#dashboard-widget-grid'); if (!grid) return; let draggedId = ''; + let currentDrop = null; + + const clearDropHint = () => { + grid.querySelectorAll('.widget-wrapper--drop-before, .widget-wrapper--drop-after').forEach((el) => { + el.classList.remove('widget-wrapper--drop-before', 'widget-wrapper--drop-after'); + }); + }; + + const updateDropHint = (event) => { + if (!draggedId) return null; + clearDropHint(); + currentDrop = closestWidgetDrop(grid, event, draggedId); + if (currentDrop) { + currentDrop.item.classList.add(currentDrop.placement === 'after' ? 'widget-wrapper--drop-after' : 'widget-wrapper--drop-before'); + } + return currentDrop; + }; grid.querySelectorAll('.widget-wrapper[data-widget-id]').forEach((wrapper) => { wrapper.addEventListener('dragstart', (event) => { @@ -1190,26 +1254,32 @@ export async function render(container, { user }) { wrapper.addEventListener('dragend', () => { draggedId = ''; wrapper.classList.remove('widget-wrapper--dragging'); - grid.querySelectorAll('.widget-wrapper--drag-over').forEach((el) => el.classList.remove('widget-wrapper--drag-over')); + currentDrop = null; + clearDropHint(); }); - wrapper.addEventListener('dragover', (event) => { - event.preventDefault(); - if (draggedId && draggedId !== wrapper.dataset.widgetId) { - wrapper.classList.add('widget-wrapper--drag-over'); - event.dataTransfer.dropEffect = 'move'; - } - }); - wrapper.addEventListener('dragleave', () => { - wrapper.classList.remove('widget-wrapper--drag-over'); - }); - wrapper.addEventListener('drop', (event) => { - event.preventDefault(); - wrapper.classList.remove('widget-wrapper--drag-over'); - const fromId = event.dataTransfer.getData('text/plain') || draggedId; - const toId = wrapper.dataset.widgetId; - widgetConfig = reorderWidgetConfig(widgetConfig, fromId, toId); + }); + + grid.addEventListener('dragover', (event) => { + event.preventDefault(); + event.dataTransfer.dropEffect = 'move'; + updateDropHint(event); + }); + + grid.addEventListener('dragleave', (event) => { + if (!grid.contains(event.relatedTarget)) { + currentDrop = null; + clearDropHint(); + } + }); + + grid.addEventListener('drop', (event) => { + event.preventDefault(); + const fromId = event.dataTransfer.getData('text/plain') || draggedId; + const drop = currentDrop || updateDropHint(event); + if (fromId && drop) { + widgetConfig = reorderWidgetConfig(widgetConfig, fromId, drop.id, drop.placement); rebuildDashboard(widgetConfig); - }); + } }); grid.querySelectorAll('[data-widget-size]').forEach((select) => { diff --git a/public/styles/dashboard.css b/public/styles/dashboard.css index cb2ddd4..22731ec 100644 --- a/public/styles/dashboard.css +++ b/public/styles/dashboard.css @@ -188,10 +188,16 @@ .widget-size--2x1, .widget-size--2x2, + .widget-size--2x3, + .widget-size--2x4, .widget-size--3x1, .widget-size--3x2, + .widget-size--3x3, + .widget-size--3x4, .widget-size--4x1, - .widget-size--4x2 { + .widget-size--4x2, + .widget-size--4x3, + .widget-size--4x4 { grid-column: span 2; } } @@ -208,10 +214,20 @@ grid-column: span 2; } + .widget-size--1x2, + .widget-size--1x3, + .widget-size--1x4 { + grid-column: span 1; + } + .widget-size--3x1, .widget-size--3x2, + .widget-size--3x3, + .widget-size--3x4, .widget-size--4x1, - .widget-size--4x2 { + .widget-size--4x2, + .widget-size--4x3, + .widget-size--4x4 { grid-column: span 3; } @@ -222,11 +238,29 @@ grid-row: span 1; } + .widget-size--1x2, .widget-size--2x2, .widget-size--3x2, .widget-size--4x2 { grid-row: span 2; } + + .widget-size--1x3, + .widget-size--2x3, + .widget-size--3x3 { + grid-row: span 3; + } + + .widget-size--1x4, + .widget-size--2x4, + .widget-size--3x4, + .widget-size--4x4 { + grid-row: span 4; + } + + .widget-size--4x3 { + grid-row: span 3; + } } @media (min-width: 1280px) { @@ -234,25 +268,43 @@ grid-template-columns: repeat(4, 1fr); } - .widget-size--1x1 { grid-column: span 1; } + .widget-size--1x1, + .widget-size--1x2, + .widget-size--1x3, + .widget-size--1x4 { grid-column: span 1; } .widget-size--2x1, - .widget-size--2x2 { + .widget-size--2x2, + .widget-size--2x3, + .widget-size--2x4 { grid-column: span 2; } .widget-size--3x1, - .widget-size--3x2 { + .widget-size--3x2, + .widget-size--3x3, + .widget-size--3x4 { grid-column: span 3; } .widget-size--4x1, - .widget-size--4x2 { + .widget-size--4x2, + .widget-size--4x3, + .widget-size--4x4 { grid-column: span 4; } } /* Primäre Widgets: subtile Akzentlinie oben */ +.widget-size--1x2 > .widget, +.widget-size--1x3 > .widget, +.widget-size--1x4 > .widget, .widget-size--2x2 > .widget, +.widget-size--2x3 > .widget, +.widget-size--2x4 > .widget, .widget-size--3x2 > .widget, -.widget-size--4x2 > .widget { +.widget-size--3x3 > .widget, +.widget-size--3x4 > .widget, +.widget-size--4x2 > .widget, +.widget-size--4x3 > .widget, +.widget-size--4x4 > .widget { border-top: 2px solid var(--active-module-accent, var(--color-accent)); } @@ -1396,11 +1448,12 @@ gap: var(--space-1); color: var(--color-text-secondary); font-size: var(--text-xs); + min-width: 190px; } .customize-row__select { min-height: 30px; - width: 86px; + width: 132px; padding: 0 var(--space-1); font-size: var(--text-xs); } @@ -2167,11 +2220,6 @@ opacity: 0.45; } -.widget-wrapper--drag-over { - outline: 2px dashed var(--module-accent); - background: color-mix(in srgb, var(--module-accent) 9%, transparent); -} - .widget-edit-controls { position: absolute; top: 6px; @@ -2227,7 +2275,7 @@ } .widget-edit-controls__select { - min-width: 76px; + min-width: 132px; height: 30px; border: 1px solid var(--color-border); border-radius: 6px; @@ -2236,6 +2284,53 @@ font-size: var(--text-xs); } +.widget-wrapper--drop-before::after, +.widget-wrapper--drop-after::after { + content: ''; + position: absolute; + z-index: 5; + border-radius: var(--radius-full); + background: var(--module-accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--module-accent) 18%, transparent); + pointer-events: none; +} + +.widget-wrapper--drop-before::after { + left: 4px; + top: -7px; + right: 4px; + height: 4px; +} + +.widget-wrapper--drop-after::after { + left: 4px; + right: 4px; + bottom: -7px; + height: 4px; +} + +.widget-size-mini { + display: grid; + grid-template-columns: repeat(4, 5px); + grid-template-rows: repeat(4, 5px); + gap: 2px; + padding: 3px; + border: 1px solid var(--color-border); + border-radius: 6px; + background: var(--color-surface-2); + flex: 0 0 auto; +} + +.widget-size-mini span { + display: block; + border-radius: 2px; + background: var(--color-border); +} + +.widget-size-mini .is-active { + background: var(--module-accent); +} + .dashboard-kpi-grid { display: grid; gap: var(--space-3); diff --git a/server/routes/preferences.js b/server/routes/preferences.js index f943fed..9ff8d00 100644 --- a/server/routes/preferences.js +++ b/server/routes/preferences.js @@ -26,7 +26,7 @@ const VALID_TIME_FORMATS = ['24h', '12h']; const DEFAULT_TIME_FORMAT = '24h'; const VALID_WIDGET_IDS = ['tasks', 'calendar', 'weather', 'meals', 'shopping', 'birthdays', 'budget', 'family', 'notes']; -const VALID_WIDGET_SIZES = ['1x1', '2x1', '2x2', '3x1', '3x2', '4x1', '4x2']; +const VALID_WIDGET_SIZES = ['1x1', '1x2', '1x3', '1x4', '2x1', '2x2', '2x3', '2x4', '3x1', '3x2', '3x3', '3x4', '4x1', '4x2', '4x3', '4x4']; function defaultWidgetSize(id) { if (['tasks', 'calendar'].includes(id)) return '2x2';