diff --git a/src/packages/frontend/i18n/common.ts b/src/packages/frontend/i18n/common.ts index a9355fc2f6d..d0934186308 100644 --- a/src/packages/frontend/i18n/common.ts +++ b/src/packages/frontend/i18n/common.ts @@ -555,7 +555,8 @@ export const labels = defineMessages({ }, select: { id: "labels.select", - defaultMessage: "select", + defaultMessage: "Select", + description: "Short label on a button in a dialog, to confirm a 'selection'." }, select_a_kernel: { id: "labels.select_a_kernel", diff --git a/src/packages/frontend/i18n/trans/ar_EG.json b/src/packages/frontend/i18n/trans/ar_EG.json index a33b06e6863..4abace5fa16 100644 --- a/src/packages/frontend/i18n/trans/ar_EG.json +++ b/src/packages/frontend/i18n/trans/ar_EG.json @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "الحصص و{upgrades}", "project.page.project-licenses.intro": "التراخيص والترقيات حسب الاستخدام تغير الحصص والميزات المتاحة للمشروع", "project.servers.project-servers.description": "يمكنك تشغيل خوادم دفتر ملاحظات مختلفة داخل هذا المشروع بنقرة واحدة. تعمل في نفس البيئة، وتصل إلى نفس الملفات، وتتوقف عندما يتوقف المشروع. يمكنك أيضًا تشغيل خوادمك الخاصة.", + "project.settings.about-box.color.label": "اللون (اختياري)", "project.settings.about-box.description.label": "الوصف (ماركداون)", "project.settings.about-box.image.label": "صورة (اختياري)", "project.settings.about-box.name.label": "الاسم (اختياري)", diff --git a/src/packages/frontend/i18n/trans/de_DE.json b/src/packages/frontend/i18n/trans/de_DE.json index 1278077108f..e8935f7aaab 100644 --- a/src/packages/frontend/i18n/trans/de_DE.json +++ b/src/packages/frontend/i18n/trans/de_DE.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Änderungen speichern", "labels.save_title": "Speichern Sie diese Datei auf die Festplatte", "labels.search": "Suche", - "labels.select": "auswählen", + "labels.select": "Auswählen", "labels.select_a_kernel": "Wählen Sie einen Kernel", "labels.settings": "Einstellungen", "labels.shared": "geteilt", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Quoten und {upgrades}", "project.page.project-licenses.intro": "Lizenzen und Pay-as-you-go-Upgrades ändern die Quoten und Funktionen, die einem Projekt zur Verfügung stehen.", "project.servers.project-servers.description": "Sie können verschiedene Notebook-Server in diesem Projekt mit einem Klick starten. Sie laufen in derselben Umgebung, haben Zugriff auf dieselben Dateien und stoppen, wenn das Projekt stoppt. Sie können auch Ihren eigenen Server starten.", + "project.settings.about-box.color.label": "Farbe (optional)", "project.settings.about-box.description.label": "Beschreibung (Markdown)", "project.settings.about-box.image.label": "Bild (optional)", "project.settings.about-box.name.label": "Name (optional)", diff --git a/src/packages/frontend/i18n/trans/es_ES.json b/src/packages/frontend/i18n/trans/es_ES.json index 08e04b3dc63..cde18e611a5 100644 --- a/src/packages/frontend/i18n/trans/es_ES.json +++ b/src/packages/frontend/i18n/trans/es_ES.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Guardar cambios", "labels.save_title": "Guardar este archivo en el disco", "labels.search": "Buscar", - "labels.select": "seleccionar", + "labels.select": "Seleccionar", "labels.select_a_kernel": "Seleccione un kernel", "labels.settings": "Configuración", "labels.shared": "compartido", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Cuotas y {upgrades}", "project.page.project-licenses.intro": "Las licencias y las actualizaciones de pago por uso cambian las cuotas y características disponibles para un proyecto", "project.servers.project-servers.description": "Puedes ejecutar varios servidores de cuadernos dentro de este proyecto con un solo clic. Se ejecutan en el mismo entorno, tienen acceso a los mismos archivos y se detienen cuando el proyecto se detiene. También puedes ejecutar tus propios servidores.", + "project.settings.about-box.color.label": "Color (opcional)", "project.settings.about-box.description.label": "Descripción (markdown)", "project.settings.about-box.image.label": "Imagen (opcional)", "project.settings.about-box.name.label": "Nombre (opcional)", diff --git a/src/packages/frontend/i18n/trans/es_PV.json b/src/packages/frontend/i18n/trans/es_PV.json index d0363df2adb..0a3b9b7533d 100644 --- a/src/packages/frontend/i18n/trans/es_PV.json +++ b/src/packages/frontend/i18n/trans/es_PV.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Aldaketak gorde", "labels.save_title": "Gorde fitxategi hau diskoan", "labels.search": "Bilatu", - "labels.select": "hautatu", + "labels.select": "Hautatu", "labels.select_a_kernel": "Hautatu Kernel bat", "labels.settings": "Ezarpenak", "labels.shared": "partekatua", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Kuotak eta {upgrades}", "project.page.project-licenses.intro": "Lizentziek eta ordaindu ahala hobekuntzek proiektu bati eskuragarri dauden kuotak eta ezaugarriak aldatzen dituzte.", "project.servers.project-servers.description": "Proiektu honetan klik bakarrarekin hainbat koaderno-zerbitzari exekutatu ditzakezu. Ingurune berean exekutatzen dira, fitxategi berberetarako sarbidea dute eta proiektua gelditzen denean gelditzen dira. Zure zerbitzari propioak ere exekutatu ditzakezu.", + "project.settings.about-box.color.label": "Kolorea (aukerakoa)", "project.settings.about-box.description.label": "Deskribapena (markdown)", "project.settings.about-box.image.label": "Irudi (aukerakoa)", "project.settings.about-box.name.label": "Izena (aukerakoa)", diff --git a/src/packages/frontend/i18n/trans/fr_FR.json b/src/packages/frontend/i18n/trans/fr_FR.json index bcdb904020a..986e4882204 100644 --- a/src/packages/frontend/i18n/trans/fr_FR.json +++ b/src/packages/frontend/i18n/trans/fr_FR.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Enregistrer les modifications", "labels.save_title": "Enregistrer ce fichier sur le disque", "labels.search": "Recherche", - "labels.select": "sélectionner", + "labels.select": "Sélectionner", "labels.select_a_kernel": "Sélectionner un noyau", "labels.settings": "Paramètres", "labels.shared": "partagé", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Quotas et {upgrades}", "project.page.project-licenses.intro": "Les licences et les mises à niveau à la carte modifient les quotas et les fonctionnalités disponibles pour un projet.", "project.servers.project-servers.description": "Vous pouvez exécuter divers serveurs de notebooks à l'intérieur de ce projet en un clic. Ils fonctionnent dans le même environnement, ont accès aux mêmes fichiers et s'arrêtent lorsque le projet s'arrête. Vous pouvez également exécuter vos propres serveurs.", + "project.settings.about-box.color.label": "Couleur (facultatif)", "project.settings.about-box.description.label": "Description (markdown)", "project.settings.about-box.image.label": "Image (optionnel)", "project.settings.about-box.name.label": "Nom (facultatif)", diff --git a/src/packages/frontend/i18n/trans/he_IL.json b/src/packages/frontend/i18n/trans/he_IL.json index 9520dfb5827..61b9964ff9c 100644 --- a/src/packages/frontend/i18n/trans/he_IL.json +++ b/src/packages/frontend/i18n/trans/he_IL.json @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "מכסה ושדרוגים", "project.page.project-licenses.intro": "רישיונות ושדרוגים לפי שימוש משנים את המכסות והתכונות הזמינות לפרויקט", "project.servers.project-servers.description": "ניתן להפעיל שרתי מחברות שונים בתוך הפרויקט הזה בלחיצה אחת. הם פועלים באותה סביבה, יש להם גישה לאותם קבצים, והם נעצרים כאשר הפרויקט נעצר. ניתן גם להפעיל שרתים משלכם.", + "project.settings.about-box.color.label": "צבע (לא חובה)", "project.settings.about-box.description.label": "תיאור (markdown)", "project.settings.about-box.image.label": "תמונה (אופציונלי)", "project.settings.about-box.name.label": "שם (לא חובה)", diff --git a/src/packages/frontend/i18n/trans/hi_IN.json b/src/packages/frontend/i18n/trans/hi_IN.json index 5ab58d16cdd..9f4641812db 100644 --- a/src/packages/frontend/i18n/trans/hi_IN.json +++ b/src/packages/frontend/i18n/trans/hi_IN.json @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "कोटा और {upgrades}", "project.page.project-licenses.intro": "लाइसेंस और पे-एज़-यू-गो अपग्रेड्स प्रोजेक्ट के लिए उपलब्ध कोटा और फीचर्स को बदलते हैं", "project.servers.project-servers.description": "आप इस प्रोजेक्ट के अंदर विभिन्न नोटबुक सर्वर एक क्लिक में चला सकते हैं। वे एक ही वातावरण में चलते हैं, एक ही फाइलों तक पहुँचते हैं, और प्रोजेक्ट के बंद होने पर बंद हो जाते हैं। आप अपने खुद के सर्वर भी चला सकते हैं।", + "project.settings.about-box.color.label": "रंग (वैकल्पिक)", "project.settings.about-box.description.label": "विवरण (मार्कडाउन)", "project.settings.about-box.image.label": "चित्र (वैकल्पिक)", "project.settings.about-box.name.label": "नाम (वैकल्पिक)", diff --git a/src/packages/frontend/i18n/trans/hu_HU.json b/src/packages/frontend/i18n/trans/hu_HU.json index e67d114da13..e575364fed0 100644 --- a/src/packages/frontend/i18n/trans/hu_HU.json +++ b/src/packages/frontend/i18n/trans/hu_HU.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Változások mentése", "labels.save_title": "Mentse el ezt a fájlt a lemezre", "labels.search": "Keresés", - "labels.select": "választ", + "labels.select": "Kiválasztás", "labels.select_a_kernel": "Válasszon egy kernelt", "labels.settings": "Beállítások", "labels.shared": "megosztott", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Kvóták és {upgrades}", "project.page.project-licenses.intro": "A licencek és a fizetés alapú frissítések megváltoztatják a projekthez elérhető kvótákat és funkciókat.", "project.servers.project-servers.description": "Egyetlen kattintással különböző notebook szervereket futtathatsz ebben a projektben. Ugyanabban a környezetben futnak, hozzáférnek ugyanazokhoz a fájlokhoz, és leállnak, amikor a projekt leáll. Saját szervereket is futtathatsz.", + "project.settings.about-box.color.label": "Szín (opcionális)", "project.settings.about-box.description.label": "Leírás (markdown)", "project.settings.about-box.image.label": "Kép (nem kötelező)", "project.settings.about-box.name.label": "Név (opcionális)", diff --git a/src/packages/frontend/i18n/trans/it_IT.json b/src/packages/frontend/i18n/trans/it_IT.json index 77a853d94c8..aac42ca27b0 100644 --- a/src/packages/frontend/i18n/trans/it_IT.json +++ b/src/packages/frontend/i18n/trans/it_IT.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Salva modifiche", "labels.save_title": "Salva questo file su disco", "labels.search": "Cerca", - "labels.select": "seleziona", + "labels.select": "Seleziona", "labels.select_a_kernel": "Seleziona un kernel", "labels.settings": "Impostazioni", "labels.shared": "condiviso", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Quote e {upgrades}", "project.page.project-licenses.intro": "Le licenze e gli aggiornamenti pay as you go cambiano le quote e le funzionalità disponibili per un progetto.", "project.servers.project-servers.description": "Puoi eseguire vari server notebook all'interno di questo progetto con un solo clic. Funzionano nello stesso ambiente, hanno accesso agli stessi file e si fermano quando il progetto si ferma. Puoi anche eseguire i tuoi server.", + "project.settings.about-box.color.label": "Colore (facoltativo)", "project.settings.about-box.description.label": "Descrizione (markdown)", "project.settings.about-box.image.label": "Immagine (opzionale)", "project.settings.about-box.name.label": "Nome (opzionale)", diff --git a/src/packages/frontend/i18n/trans/ja_JP.json b/src/packages/frontend/i18n/trans/ja_JP.json index fa844abb889..9a920be0fe8 100644 --- a/src/packages/frontend/i18n/trans/ja_JP.json +++ b/src/packages/frontend/i18n/trans/ja_JP.json @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "クォータと{upgrades}", "project.page.project-licenses.intro": "ライセンスおよび従量制アップグレードは、プロジェクトに利用可能なクォータと機能を変更します", "project.servers.project-servers.description": "このプロジェクト内で様々なノートブックサーバーをワンクリックで実行できます。それらは同じ環境で動作し、同じファイルにアクセスし、プロジェクトが停止すると停止します。また、自分のサーバーを実行することもできます。", + "project.settings.about-box.color.label": "色(オプション)", "project.settings.about-box.description.label": "説明 (markdown)", "project.settings.about-box.image.label": "画像(オプション)", "project.settings.about-box.name.label": "名前(任意)", diff --git a/src/packages/frontend/i18n/trans/ko_KR.json b/src/packages/frontend/i18n/trans/ko_KR.json index b9c3db2a399..66d0c4a98e0 100644 --- a/src/packages/frontend/i18n/trans/ko_KR.json +++ b/src/packages/frontend/i18n/trans/ko_KR.json @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "할당량 및 {upgrades}", "project.page.project-licenses.intro": "라이선스와 사용량에 따른 업그레이드는 프로젝트에 이용 가능한 할당량과 기능을 변경합니다.", "project.servers.project-servers.description": "이 프로젝트 안에서 다양한 노트북 서버를 한 번의 클릭으로 실행할 수 있습니다. 서버는 같은 환경에서 실행되며, 같은 파일에 접근하고 프로젝트가 중지되면 서버도 중지됩니다. 또한 자신의 서버를 실행할 수도 있습니다.", + "project.settings.about-box.color.label": "색상 (선택 사항)", "project.settings.about-box.description.label": "설명 (마크다운)", "project.settings.about-box.image.label": "이미지 (선택 사항)", "project.settings.about-box.name.label": "이름 (선택 사항)", diff --git a/src/packages/frontend/i18n/trans/nl_NL.json b/src/packages/frontend/i18n/trans/nl_NL.json index 08782822bd2..734020ed0af 100644 --- a/src/packages/frontend/i18n/trans/nl_NL.json +++ b/src/packages/frontend/i18n/trans/nl_NL.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Wijzigingen opslaan", "labels.save_title": "Sla dit bestand op op schijf", "labels.search": "Zoeken", - "labels.select": "selecteer", + "labels.select": "Selecteer", "labels.select_a_kernel": "Selecteer een kernel", "labels.settings": "Instellingen", "labels.shared": "gedeeld", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Quota's en {upgrades}", "project.page.project-licenses.intro": "Licenties en upgrades op basis van betalen per gebruik veranderen de quota en functies die beschikbaar zijn voor een project.", "project.servers.project-servers.description": "Je kunt verschillende notebook-servers binnen dit project met één klik uitvoeren. Ze draaien in dezelfde omgeving, hebben toegang tot dezelfde bestanden, en stoppen wanneer het project stopt. Je kunt ook je eigen servers draaien.", + "project.settings.about-box.color.label": "Kleur (optioneel)", "project.settings.about-box.description.label": "Beschrijving (markdown)", "project.settings.about-box.image.label": "Afbeelding (optioneel)", "project.settings.about-box.name.label": "Naam (optioneel)", diff --git a/src/packages/frontend/i18n/trans/pl_PL.json b/src/packages/frontend/i18n/trans/pl_PL.json index ee2974c908b..843207db693 100644 --- a/src/packages/frontend/i18n/trans/pl_PL.json +++ b/src/packages/frontend/i18n/trans/pl_PL.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Zapisz zmiany", "labels.save_title": "Zapisz ten plik na dysku", "labels.search": "Szukaj", - "labels.select": "wybierz", + "labels.select": "Wybierz", "labels.select_a_kernel": "Wybierz jądro", "labels.settings": "Ustawienia", "labels.shared": "udostępnione", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Limity i {upgrades}", "project.page.project-licenses.intro": "Licencje i ulepszenia pay as you go zmieniają limity i funkcje dostępne dla projektu.", "project.servers.project-servers.description": "Możesz uruchomić różne serwery notebooków w tym projekcie jednym kliknięciem. Działają w tym samym środowisku, mają dostęp do tych samych plików i zatrzymują się, gdy projekt się zatrzymuje. Możesz także uruchomić własne serwery.", + "project.settings.about-box.color.label": "Kolor (opcjonalnie)", "project.settings.about-box.description.label": "Opis (markdown)", "project.settings.about-box.image.label": "Obraz (opcjonalnie)", "project.settings.about-box.name.label": "Nazwa (opcjonalnie)", diff --git a/src/packages/frontend/i18n/trans/pt_BR.json b/src/packages/frontend/i18n/trans/pt_BR.json index 2595f0ef8f5..eb0538187d2 100644 --- a/src/packages/frontend/i18n/trans/pt_BR.json +++ b/src/packages/frontend/i18n/trans/pt_BR.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Salvar alterações", "labels.save_title": "Salve este arquivo no disco", "labels.search": "Buscar", - "labels.select": "selecionar", + "labels.select": "Selecionar", "labels.select_a_kernel": "Selecione um Kernel", "labels.settings": "Configurações", "labels.shared": "compartilhado", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Quotas e {upgrades}", "project.page.project-licenses.intro": "Licenças e upgrades pay as you go alteram as cotas e recursos disponíveis para um projeto.", "project.servers.project-servers.description": "Você pode executar vários servidores de notebook dentro deste projeto com um clique. Eles rodam no mesmo ambiente, têm acesso aos mesmos arquivos e param quando o projeto para. Você também pode executar seus próprios servidores.", + "project.settings.about-box.color.label": "Cor (opcional)", "project.settings.about-box.description.label": "Descrição (markdown)", "project.settings.about-box.image.label": "Imagem (opcional)", "project.settings.about-box.name.label": "Nome (opcional)", diff --git a/src/packages/frontend/i18n/trans/pt_PT.json b/src/packages/frontend/i18n/trans/pt_PT.json index c058d567c4d..2c510a86a8e 100644 --- a/src/packages/frontend/i18n/trans/pt_PT.json +++ b/src/packages/frontend/i18n/trans/pt_PT.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Guardar alterações", "labels.save_title": "Guardar este ficheiro no disco", "labels.search": "Pesquisar", - "labels.select": "selecionar", + "labels.select": "Selecionar", "labels.select_a_kernel": "Selecionar um kernel", "labels.settings": "Configurações", "labels.shared": "partilhado", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Quotas e {upgrades}", "project.page.project-licenses.intro": "Licenças e atualizações pagas conforme o uso alteram as quotas e funcionalidades disponíveis para um projeto.", "project.servers.project-servers.description": "Pode executar vários servidores de cadernos dentro deste projeto com um clique. Eles funcionam no mesmo ambiente, têm acesso aos mesmos ficheiros e param quando o projeto para. Também pode executar os seus próprios servidores.", + "project.settings.about-box.color.label": "Cor (opcional)", "project.settings.about-box.description.label": "Descrição (markdown)", "project.settings.about-box.image.label": "Imagem (opcional)", "project.settings.about-box.name.label": "Nome (opcional)", diff --git a/src/packages/frontend/i18n/trans/ru_RU.json b/src/packages/frontend/i18n/trans/ru_RU.json index 7fbe7b52124..816381a8dda 100644 --- a/src/packages/frontend/i18n/trans/ru_RU.json +++ b/src/packages/frontend/i18n/trans/ru_RU.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Сохранить изменения", "labels.save_title": "Сохранить этот файл на диск", "labels.search": "Поиск", - "labels.select": "выбрать", + "labels.select": "Выбрать", "labels.select_a_kernel": "Выберите ядро", "labels.settings": "Настройки", "labels.shared": "общий", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Квоты и {upgrades}", "project.page.project-licenses.intro": "Лицензии и улучшения по мере использования изменяют квоты и функции, доступные для проекта.", "project.servers.project-servers.description": "Вы можете запустить различные серверы блокнотов внутри этого проекта одним кликом. Они работают в той же среде, имеют доступ к тем же файлам и останавливаются, когда проект останавливается. Вы также можете запустить свои собственные серверы.", + "project.settings.about-box.color.label": "Цвет (необязательно)", "project.settings.about-box.description.label": "Описание (markdown)", "project.settings.about-box.image.label": "Изображение (необязательно)", "project.settings.about-box.name.label": "Имя (необязательно)", diff --git a/src/packages/frontend/i18n/trans/tr_TR.json b/src/packages/frontend/i18n/trans/tr_TR.json index b8e0e243eaa..40a5ac0994b 100644 --- a/src/packages/frontend/i18n/trans/tr_TR.json +++ b/src/packages/frontend/i18n/trans/tr_TR.json @@ -1079,7 +1079,7 @@ "labels.save_changes": "Değişiklikleri kaydet", "labels.save_title": "Bu dosyayı diske kaydet", "labels.search": "Ara", - "labels.select": "seç", + "labels.select": "Seç", "labels.select_a_kernel": "Bir çekirdek seç", "labels.settings": "Ayarlar", "labels.shared": "paylaşılan", @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "Kotalar ve {upgrades}", "project.page.project-licenses.intro": "Lisanslar ve kullanıldıkça öde yükseltmeleri, bir projeye sunulan kotaları ve özellikleri değiştirir.", "project.servers.project-servers.description": "Bu proje içinde tek tıkla çeşitli defter sunucularını çalıştırabilirsiniz. Aynı ortamda çalışırlar, aynı dosyalara erişirler ve proje durduğunda dururlar. Ayrıca kendi sunucularınızı çalıştırabilirsiniz.", + "project.settings.about-box.color.label": "Renk (isteğe bağlı)", "project.settings.about-box.description.label": "Açıklama (markdown)", "project.settings.about-box.image.label": "Görsel (isteğe bağlı)", "project.settings.about-box.name.label": "İsim (isteğe bağlı)", diff --git a/src/packages/frontend/i18n/trans/zh_CN.json b/src/packages/frontend/i18n/trans/zh_CN.json index 13737772113..640eeccd487 100644 --- a/src/packages/frontend/i18n/trans/zh_CN.json +++ b/src/packages/frontend/i18n/trans/zh_CN.json @@ -1337,6 +1337,7 @@ "project.page.project-licenses.header": "配额和{upgrades}", "project.page.project-licenses.intro": "许可证和按需付费升级更改项目的配额和可用功能", "project.servers.project-servers.description": "您可以通过一次点击在此项目内运行各种笔记本服务器。它们在相同的环境中运行,访问相同的文件,并在项目停止时停止。您也可以运行您自己的服务器。", + "project.settings.about-box.color.label": "颜色(可选)", "project.settings.about-box.description.label": "描述 (markdown)", "project.settings.about-box.image.label": "图像(可选)", "project.settings.about-box.name.label": "姓名(可选)", diff --git a/src/packages/frontend/project/history/log-entry.tsx b/src/packages/frontend/project/history/log-entry.tsx index cff0dcb6b9e..e1136d7898a 100644 --- a/src/packages/frontend/project/history/log-entry.tsx +++ b/src/packages/frontend/project/history/log-entry.tsx @@ -5,6 +5,7 @@ import { Space, Tooltip } from "antd"; import React from "react"; import { Avatar } from "@cocalc/frontend/account/avatar/avatar"; +import { avatar_fontcolor } from "@cocalc/frontend/account/avatar/font-color"; import { Col, Grid, Row } from "@cocalc/frontend/antd-bootstrap"; import { CSS, @@ -227,7 +228,9 @@ export const LogEntry: React.FC = React.memo( ); } - function render_start_project(event: ProjectControlEvent): React.JSX.Element { + function render_start_project( + event: ProjectControlEvent, + ): React.JSX.Element { return ( = React.memo( for (const key in obj) { i += 1; const value = obj[key]; - if (key == "image") { + if (key === "image") { result.push( set project image to{" "} @@ -516,6 +519,35 @@ export const LogEntry: React.FC = React.memo( ); continue; } + if (key === "color") { + const textColor = value ? avatar_fontcolor(value) : "black"; + result.push( + + set{" "} + + color + {" "} + to{" "} + + {value || "(none)"} + + , + ); + continue; + } let content = `${key} to ${value}`; if (i < obj.length) { content += "and"; @@ -725,7 +757,9 @@ export const LogEntry: React.FC = React.memo( ); } - function render_invite_nonuser(event: CollaboratorEvent): React.JSX.Element { + function render_invite_nonuser( + event: CollaboratorEvent, + ): React.JSX.Element { return ( = React.memo( ); } - function render_remove_collaborator(event: CollaboratorEvent): React.JSX.Element { + function render_remove_collaborator( + event: CollaboratorEvent, + ): React.JSX.Element { return ( {" "} diff --git a/src/packages/frontend/project/history/log.tsx b/src/packages/frontend/project/history/log.tsx index 6a5bf77a7b8..ff66d915b50 100644 --- a/src/packages/frontend/project/history/log.tsx +++ b/src/packages/frontend/project/history/log.tsx @@ -7,6 +7,7 @@ import { Button } from "antd"; import { List } from "immutable"; import { FormattedMessage } from "react-intl"; import { Virtuoso, VirtuosoHandle } from "react-virtuoso"; + import useVirtuosoScrollHook from "@cocalc/frontend/components/virtuoso-scroll-hook"; import { React, diff --git a/src/packages/frontend/project/settings/about-box.tsx b/src/packages/frontend/project/settings/about-box.tsx index 258f15cf24b..172ee66c817 100644 --- a/src/packages/frontend/project/settings/about-box.tsx +++ b/src/packages/frontend/project/settings/about-box.tsx @@ -4,9 +4,10 @@ */ import ShowError from "@cocalc/frontend/components/error"; -import { Alert, Col, Row, Typography } from "antd"; +import { Alert, Button, Col, Modal, Row, Typography } from "antd"; import React, { useState } from "react"; import { useIntl } from "react-intl"; + import { redux, useAsyncEffect, @@ -20,6 +21,8 @@ import { TextInput, TimeAgo, } from "@cocalc/frontend/components"; +import { avatar_fontcolor } from "@cocalc/frontend/account/avatar/font-color"; +import { ColorPicker } from "@cocalc/frontend/colorpicker"; import { COLORS } from "@cocalc/util/theme"; import { labels } from "@cocalc/frontend/i18n"; import { ProjectTitle } from "@cocalc/frontend/projects/project-title"; @@ -59,6 +62,12 @@ export const AboutBox: React.FC = (props: Readonly) => { const hasReadonlyFields = ["student", "shared"].includes(courseProjectType); const [error, setError] = useState(""); const [avatarImage, setAvatarImage] = useState(undefined); + const [color, setColor] = useState( + project_map?.getIn([project_id, "color"]) as string | undefined, + ); + const [showColorModal, setShowColorModal] = useState(false); + const [nextColor, setNextColor] = useState(color); + const { isProjectBookmarked, setProjectBookmarked } = useBookmarkedProjects(); useAsyncEffect(async () => { @@ -174,16 +183,30 @@ export const AboutBox: React.FC = (props: Readonly) => { vertical={isFlyout} style={{ marginBottom: "15px" }} > -
+
setProjectBookmarked(project_id, !isProjectBookmarked(project_id))} + onClick={() => + setProjectBookmarked( + project_id, + !isProjectBookmarked(project_id), + ) + } /> {isProjectBookmarked(project_id) ? "Enabled" : "Disabled"} @@ -192,7 +215,8 @@ export const AboutBox: React.FC = (props: Readonly) => { {intl.formatMessage({ id: "project.settings.about-box.starred.help", - defaultMessage: "Starred projects can be filtered by clicking the starred filter button in your projects list.", + defaultMessage: + "Starred projects can be filtered by clicking the starred filter button in your projects list.", description: "Help text explaining how project starring works", })} @@ -206,17 +230,120 @@ export const AboutBox: React.FC = (props: Readonly) => { })} vertical={isFlyout} > - { +
+ { + try { + await actions.setProjectImage(project_id, data); + setAvatarImage(data.full); + } catch (err) { + setError(`Error saving project image: ${err}`); + } + }} + /> + {avatarImage && ( + + )} +
+ + +
+ + {color && ( + + )} +
+ { try { - await actions.setProjectImage(project_id, data); - setAvatarImage(data.full); + await actions.setProjectColor(project_id, nextColor ?? ""); + setColor(nextColor); + setShowColorModal(false); } catch (err) { - setError(`Error saving project image: ${err}`); + setError(`Error saving project color: ${err}`); } }} - /> + onCancel={() => { + setShowColorModal(false); + setNextColor(color); + }} + > + { + setNextColor(value); + }} + /> +
{created && ( (current_image); @@ -407,7 +407,7 @@ export function ComputeImageSelector({ >
{`${capitalize(intl.formatMessage(labels.select))}:`}
+ >{`${intl.formatMessage(labels.select)}:`}
{render_selector()}
diff --git a/src/packages/frontend/project_store.ts b/src/packages/frontend/project_store.ts index d64c7b529e7..20b1890eca8 100644 --- a/src/packages/frontend/project_store.ts +++ b/src/packages/frontend/project_store.ts @@ -100,7 +100,7 @@ export interface ProjectStoreState { active_file_sort: TypedMap<{ column_name: string; is_descending: boolean }>; page_number: number; starred_files?: immutable.List; // paths to starred files (synced from conat) - file_action?: string; // undefineds is meaningfully none here + file_action?: string; // undefined is meaningfully none here file_search?: string; show_hidden?: boolean; show_masked?: boolean; diff --git a/src/packages/frontend/projects/actions.ts b/src/packages/frontend/projects/actions.ts index 0ebdac38096..57932fa54f2 100644 --- a/src/packages/frontend/projects/actions.ts +++ b/src/packages/frontend/projects/actions.ts @@ -222,6 +222,32 @@ export class ProjectsActions extends Actions { } }; + setProjectColor = async ( + project_id: string, + color: string, + ): Promise => { + if (!(await this.have_project(project_id))) { + console.warn( + `Can't set project color -- you are not a collaborator on project '${project_id}'.`, + ); + return; + } + const before = store.getIn(["project_map", project_id, "color"]); + if (before === color) return; + try { + // set in the Table + await this.projects_table_set({ project_id, color }); + // create entry in the project's log + await this.redux.getProjectActions(project_id).async_log({ + event: "set", + color, + }); + } catch (err) { + this.projects_table_set({ project_id, color: before }); + throw err; + } + }; + // creates and stores image as a blob in the database. // stores sha1 of that blog in projects map and also returns // the sha1. diff --git a/src/packages/frontend/projects/project-row.tsx b/src/packages/frontend/projects/project-row.tsx index f2f0210ca59..895dc4ad191 100644 --- a/src/packages/frontend/projects/project-row.tsx +++ b/src/packages/frontend/projects/project-row.tsx @@ -7,8 +7,12 @@ Render a single project entry, which goes in the list of projects */ +import { Avatar } from "antd"; +import { CSSProperties, useEffect } from "react"; + import { Col, Row, Well } from "@cocalc/frontend/antd-bootstrap"; import { + CSS, React, redux, useActions, @@ -34,10 +38,9 @@ import track from "@cocalc/frontend/user-tracking"; import { DEFAULT_COMPUTE_IMAGE } from "@cocalc/util/db-schema"; import { KUCALC_COCALC_COM } from "@cocalc/util/db-schema/site-defaults"; import { COLORS } from "@cocalc/util/theme"; -import { Avatar } from "antd"; -import { CSSProperties, useEffect } from "react"; import { ProjectUsers } from "./project-users"; import { useBookmarkedProjects } from "./use-bookmarked-projects"; +import { blendBackgroundColor } from "./util"; const image_name_style: React.CSSProperties = { fontSize: "12px", @@ -210,11 +213,25 @@ export const ProjectRow: React.FC = ({ project_id, index }: Props) => { e.stopPropagation(); } - const project_row_styles: React.CSSProperties = { - backgroundColor: (index ?? 0) % 2 ? "#eee" : "white", + const color = project.get("color"); + const borderStyle = color ? `4px solid ${color}` : undefined; + + // Calculate background color with faint hint of project color + const isEvenRow = (index ?? 0) % 2 === 1; + const baseColor = isEvenRow ? COLORS.GRAY_LL : "white"; // even color same as background in projects-nav.ts ProjectsNav::renderTabBar0 + const backgroundColor = blendBackgroundColor(color, baseColor, isEvenRow); + + const project_row_styles: CSS = { + backgroundColor, marginBottom: 0, cursor: "pointer", wordWrap: "break-word", + ...(borderStyle + ? { + borderLeft: borderStyle, + borderRight: borderStyle, + } + : undefined), }; if (project == null) { @@ -224,7 +241,14 @@ export const ProjectRow: React.FC = ({ project_id, index }: Props) => { return ( - + {!is_anonymous && render_star()} { if (openProjects == null) return []; @@ -280,13 +284,49 @@ export function ProjectsNav(props: ProjectsNavProps) { } function renderTabBar0(tabBarProps, DefaultTabBar) { - return renderTabBar(tabBarProps, DefaultTabBar, { - [activeTopTab]: { - border: "2px solid #d3d3d3", - borderRadius: "8px", - }, - "": { border: "2px solid transparent", borderRadius: "8px" }, - }); + return ( + + {(node) => { + const project_id = node.key; + const isActive = project_id === activeTopTab; + const projectColor = project_map?.getIn([project_id, "color"]) as + | string + | undefined; + + const wrapperStyle: CSS = { + border: isActive + ? `2px solid ${projectColor ? projectColor : "#d3d3d3"}` + : `2px solid ${projectColor ? projectColor : "transparent"}`, + borderRadius: "8px", + }; + + // Add background color if project has a color + if (projectColor) { + // Active tab: lighter/brighter (less color), inactive: darker (more color) + wrapperStyle.backgroundColor = blendBackgroundColor( + projectColor, + isActive ? "white" : COLORS.GRAY_LL, + !isActive, + ); + } + + // Clone the node with additional style props to override Ant Design's background + const styledNode = cloneElement(node, { + style: { + ...node.props.style, + backgroundColor: wrapperStyle.backgroundColor, + }, + }); + + // this is similar to the renderTabBar in sortable-tabs.tsx, but with the above, also styles the background + return ( + + {styledNode} + + ); + }} + + ); } return ( diff --git a/src/packages/frontend/projects/util.ts b/src/packages/frontend/projects/util.ts index 2a22dec68ad..06c0f0115de 100644 --- a/src/packages/frontend/projects/util.ts +++ b/src/packages/frontend/projects/util.ts @@ -194,3 +194,25 @@ function project_is_in_filter( !!project.getIn(["users", account_id, "hide"]) == hidden ); } + +/** + * Blend a base color with a user-selected color to create a subtle hint. + * + * @param custom - The color (hex string or undefined) a user selected for the object + * @param base - The base background color to blend with (i.e. the background, default color) + * @param brighter - Adjust the opacity, e.g. for even/odd rows + */ +export function blendBackgroundColor( + custom: string | undefined, + base: string, + brighter: boolean = false, +): string { + if (!custom) { + return base; + } + + const opacity = brighter ? 0.09 : 0.05; + + // Uses CSS color-mix() to blend the colors + return `color-mix(in srgb, ${custom} ${opacity * 100}%, ${base})`; +} diff --git a/src/packages/util/db-schema/projects.ts b/src/packages/util/db-schema/projects.ts index 088b9a655eb..4115143b371 100644 --- a/src/packages/util/db-schema/projects.ts +++ b/src/packages/util/db-schema/projects.ts @@ -90,6 +90,7 @@ Table({ avatar_image_tiny: null, // do NOT add avatar_image_full here or it will get included in changefeeds, which we don't want. // instead it gets its own virtual table. + color: null, pay_as_you_go_quotas: null, }, }, @@ -113,6 +114,7 @@ Table({ sandbox: true, avatar_image_tiny: true, avatar_image_full: true, + color: true, }, required_fields: { project_id: true, @@ -333,6 +335,12 @@ Table({ desc: "A visual image associated with the project. Could be 150kb. NOT include as part of changefeed of projects, since potentially big (e.g., 200kb x 1000 projects = 200MB!).", render: { type: "image" }, }, + color: { + title: "Color", + type: "string", + desc: "Optional color associated with the project, used for visual identification (e.g., border color in project list).", + render: { type: "text" }, + }, pay_as_you_go_quotas: { type: "map", desc: "Pay as you go quotas that users set so that when they run this project, it gets upgraded to at least what is specified here, and user gets billed later for what is used. Any changes to this table could result in money being spent, so should only be done via the api. This is a map from the account_id of the user that set the quota to the value of the quota spec (which is purchase-quotas.ProjectQuota).",