From e9b7dabed44012f57c5bda30a7a0571d11ed827b Mon Sep 17 00:00:00 2001 From: L3P3 Date: Mon, 22 Jan 2024 18:26:39 +0100 Subject: [PATCH] world list features --- locales/de.csv | 25 ++- locales/en.csv | 25 ++- locales/ru.csv | 33 +++- locales/uk.csv | 25 ++- package.json | 2 +- src/app.css | 54 ++++--- src/etc/helpers.js | 11 +- src/etc/locale.js | 25 ++- src/externs.js | 8 + src/game/c_menu_start.js | 323 ++++++++++++++++++++++++++++++++++----- 10 files changed, 452 insertions(+), 79 deletions(-) diff --git a/locales/de.csv b/locales/de.csv index dedf15f..fedd643 100644 --- a/locales/de.csv +++ b/locales/de.csv @@ -1,8 +1,14 @@ amount: Anzahl +ask_world_delete_1: Welt " +ask_world_delete_2: " wirklich löschen? back_to_game: Zurück zum Spiel +change_world_name: Welt-Namen ändern chunk_regenerated: Chunk neu generiert. chunks_loaded: Chunks geladen. commands: Befehle +delete_local: Löschen (lokal) +delete_world: Welt löschen +delete: Löschen download_world_from_server: Welt von Server herunterladen download: Herunterladen error_amount_minimum_1: Anzahl muss mindestens 1 sein! @@ -11,7 +17,9 @@ error_conflict_2: " wurde sowohl hier als auch woanders geändert.\nOK: Die vom error_conflict_3: ) | Abbrechen: Die hier hochladen ( error_conflict_4: ) error_connection: Verbindungsfehler. +error_delete_world: Fehler beim Löschen der Welt: error_download_world: Fehler beim Herunterladen der Welt: +error_edit_world: Fehler beim Bearbeiten der Welt: error_gamemode_range: Spielmodus muss in 0..2 sein! error_invalid_block_type: Ungültiger Blocktyp! error_inventory_full: Inventar ist voll! @@ -19,6 +27,7 @@ error_list_is_loading: Liste wird noch geladen! error_loading_worldlist: Fehler beim Laden der Weltenliste: error_name_too_long: Der Name ist zu lang! error_no_permission_logged_in: Keine Berechtigung. Angemeldet? +error_no_permission: Fehlende Berechtigung! error_no_world_selected: Keine Welt ausgewählt! error_not_logged_in: Nicht angemeldet! error_only_vert_supported: Nur "vert" wird unterstützt! @@ -29,6 +38,7 @@ error_upload_world: Fehler beim Hochladen der Welt: error_world_is_loading: Die Welt wird noch geladen! error_world_is_present_both_sides: Die Welt ist schon auf beiden Seiten vorhanden! error_world_not_downloaded: Die Welt ist noch nicht heruntergeladen! +error_world_not_uploaded: Die Welt ist nicht hochgeladen! game_saved: Spiel gespeichert. gamemode_set_to: Spielmodus gesetzt auf inventory_cleared: Inventar geleert @@ -37,17 +47,24 @@ item_labels: Luft,Stein,Grasblock,Erde,Bruchstein,Holzbretter,Grundgestein,Stamm items_given: Items gegeben join_selected_world: Ausgewählte Welt betreten login: Anmelden +modification: Änderung mouse_mode_normal: Normaler Mausmodus. mouse_mode_selection: Auswahl mit Maustasten. mouse_sensitivity: Mausempfindlichkeit +name_existing_world: Neuer Name der Welt:\n(max. 16 Zeichen) name_new_world: Name der neuen Welt:\n(max. 16 Zeichen) new_world: Neue Welt +no: Nein only_local: Nur lokale Welt open: Öffnen +owner: Besitzer player: Spieler project_page: Projektseite +public: Öffentlich +publish_world: Welt veröffentlichen refresh: Aktualisieren reload_list: Liste neu laden +rename: Umbenennen resolution: Auflösung selection_expanded: Auswahl erweitert. selection_none: nichts @@ -56,24 +73,28 @@ selection_primary: Erster Auswahlpunkt selection_secondary_short: Zweiter selection_secondary: Zweiter Auswahlpunkt settings: Einstellungen +show_world_settings: Aktionen/Einstellungen zur Welt anzeigen spawn_updated: Startpunkt aktualisiert. surfaces_colored: Einfarbig surfaces_textured: Texturiert surfaces: Oberflächen teleported_to_spawn: Zum Startpunkt teleportiert. teleported_to: Teleportiert zu +today: heute transfer: Übertragen unknown_command: Ungültiger Befehl -unknown_world: Unbekannte Welt unknown_world_found: Es wurde eine namenlose lokale Welt gefunden. Wie soll sie heißen? +unknown_world: Unbekannte Welt +unpublish_world: Welt privat machen upload_world_to_server: Welt auf den Server hochladen upload: Hochladen -user_colon: Nutzer: version_1: Version version_2: von L3P3 view_angle: Blickwinkel view_distance: Sichtweite warn_world_remote_missing_1: Die Welt " warn_world_remote_missing_2: " wurde auf dem Server nicht gefunden, ist also jetzt eine lokale! +world_etc: Welt... world_leave: Welt verlassen worlds: Welten +yes: Ja diff --git a/locales/en.csv b/locales/en.csv index 943f2b7..df1d0bc 100644 --- a/locales/en.csv +++ b/locales/en.csv @@ -1,8 +1,14 @@ amount: Amount +ask_world_delete_1: Really delete world " +ask_world_delete_2: "? back_to_game: Back to game +change_world_name: Change world name chunk_regenerated: Chunk regenerated. chunks_loaded: Chunks loaded. commands: Commands +delete_local: Delete (local) +delete_world: Delete world +delete: Delete download_world_from_server: Download world from server download: Download error_amount_minimum_1: Amount must be at least 1! @@ -11,7 +17,9 @@ error_conflict_2: " was modified here and somewhere else.\nOK: Take variant from error_conflict_3: ) | Cancel: Keep local variant ( error_conflict_4: ) error_connection: Connection error. +error_delete_world: Error while deleting world: error_download_world: Error while downloading world: +error_edit_world: Error while editing world: error_gamemode_range: Game mode must be in 0..2! error_invalid_block_type: Invalid block type! error_inventory_full: Inventory is full! @@ -19,6 +27,7 @@ error_list_is_loading: List is loading! error_loading_worldlist: Error while loading world list: error_name_too_long: Name is too long! error_no_permission_logged_in: Missing permission. Logged in? +error_no_permission: No permission! error_no_world_selected: No world selected! error_not_logged_in: Not logged in! error_only_vert_supported: Only "vert" supported! @@ -29,6 +38,7 @@ error_upload_world: Error while uploading world: error_world_is_loading: The world is still loading! error_world_is_present_both_sides: The world is present on both sides! error_world_not_downloaded: The world is not downloaded yet! +error_world_not_uploaded: The world is not uploaded! game_saved: Game saved. gamemode_set_to: Game mode set to inventory_cleared: Inventory cleared. @@ -37,17 +47,24 @@ item_labels: !!!not used in english!!! items_given: Gave items join_selected_world: Enter selected world login: Login +modification: Modified mouse_mode_normal: Normal mouse mode. mouse_mode_selection: Select using mouse buttons. mouse_sensitivity: Mouse sensitivity +name_existing_world: World\'s new label:\n(max. 16 characters) name_new_world: New world\'s label:\n(max. 16 characters) new_world: New world +no: No only_local: Just a local world open: Enter +owner: Owner player: Player project_page: Project page +public: Public +publish_world: Publish world refresh: Refresh reload_list: Reload list +rename: Rename resolution: Resolution selection_expanded: Expanded selection. selection_none: none @@ -56,24 +73,28 @@ selection_primary: Primary point selection_secondary_short: Secondary selection_secondary: Secondary point settings: Settings +show_world_settings: Show world settings spawn_updated: Spawn updated. surfaces_colored: Plain surfaces_textured: Textured surfaces: Surfaces teleported_to_spawn: Teleported to spawn. teleported_to: Teleported to +today: today transfer: Transfer unknown_command: Unknown command -unknown_world: Unknown world unknown_world_found: There was an unnamed world found. How should it be called? +unknown_world: Unknown world +unpublish_world: Unpublish world upload_world_to_server: Upload world to server upload: Upload -user_colon: User: version_1: Version version_2: by L3P3 view_angle: View angle view_distance: View distance warn_world_remote_missing_1: The world " warn_world_remote_missing_2: " was not found on the server, so it is a local world now. +world_etc: World... world_leave: Leave world worlds: Worlds +yes: Yes diff --git a/locales/ru.csv b/locales/ru.csv index 24eded8..5e22d99 100644 --- a/locales/ru.csv +++ b/locales/ru.csv @@ -1,8 +1,14 @@ amount: Число +ask_world_delete_1: Мир " +ask_world_delete_2: " реално удалить? back_to_game: Назад к игре +change_world_name: Изменит имя миру chunk_regenerated: Чанки перезагружаютца. chunks_loaded: Чанки загружаютца. commands: Команда +delete_local: Удалить (локал) +delete_world: Удалить мир +delete: Удалить download_world_from_server: Загрузит мир из сервера download: Скачать error_amount_minimum_1: Число должно быт минимумь 1! @@ -11,24 +17,28 @@ error_conflict_2: " было изменено как здесь, так и в д error_conflict_3: ) | Отменит: Вот это hochladen ( error_conflict_4: ) error_connection: Ошибка поключения. -error_download_world: Ошыбка при загруске мира: +error_delete_world: Ошибка при удаления мира: +error_download_world: Ошибка при загруске мира: +error_edit_world: Ошибка при изменения мира: error_gamemode_range: Игровой режим должен быт in 0..2! error_invalid_block_type: Неверный тип блока! error_inventory_full: Инвентар полный! error_list_is_loading: Список еще загружаетца! -error_loading_worldlist: Ошыбка при загруске списка миров: +error_loading_worldlist: Ошибка при загруске списка миров: error_name_too_long: Имя слишком долгое! error_no_permission_logged_in: Нету разрешения. Зарегестрирован? +error_no_permission: Нету авторизации! error_no_world_selected: Мир был не выбрань! error_not_logged_in: Не зарегестрирован! error_only_vert_supported: Толко "vert" подержуваетца! error_pitch: Неповезло! error_selection_required: Выберите сначяло! error_storage: Нехватает памяти! -error_upload_world: Ошыбка при загруске мира: +error_upload_world: Ошибка при загруске мира: error_world_is_loading: Мир еще загружаетса! error_world_is_present_both_sides: Мир уже есть на двух страниц! error_world_not_downloaded: Мир еще не скачень! +error_world_not_uploaded: Мир не загружен! game_saved: Игра сохранена. gamemode_set_to: Игровой режим сменен на inventory_cleared: Инвентар пусть @@ -37,17 +47,24 @@ item_labels: Воздух,Камень,Блок травы,Земля,Булыж items_given: Вещи даны join_selected_world: Зайти на выбраный сервер login: Зарегестрироватся +modification: Изменения mouse_mode_normal: Классический режим мыщы. mouse_mode_selection: Выборь с мыщы. mouse_sensitivity: Чуствителност мыщы. +name_existing_world: Новое имя мира:\n(макс. 16 символов) name_new_world: Имя нового Мира:\n(макс. 16 симболов) new_world: Новый мир +no: Нет only_local: Толко локалный мир open: Открыт +owner: Владелец player: Игрок project_page: Сайт проекта +public: Публичный +publish_world: Опубликоват мир refresh: Обновит reload_list: Обновит список +rename: Переименовать resolution: Качество selection_expanded: Выборь увеличен. selection_none: ничего @@ -56,24 +73,28 @@ selection_primary: Первая выбраная точка selection_secondary_short: Второй selection_secondary: Вторая выбраная точка settings: Настроики +show_world_settings: Акции/Показать настройки мира spawn_updated: Началная точка обновлена surfaces_colored: Одноцветный surfaces_textured: С текстурами surfaces: Поверхность teleported_to_spawn: Переместитца к стартовой точки teleported_to: Перенестица к +today: сегодня transfer: Перенести unknown_command: Неправилная Команда -unknown_world: Неизвестный Мир unknown_world_found: Был найден безмяный локалный мир. Как его назвать? +unknown_world: Неизвестный м +unpublish_world: Заприватит мир upload_world_to_server: Загрузит мир на сервер upload: Загрузит -user_colon: Ползовател: version_1: Версия version_2: от L3P3 view_angle: Радиус зрения view_distance: Далность зрения warn_world_remote_missing_1: Мир " warn_world_remote_missing_2: " был на сервере не найдень, поэтому он теперь локалный! -world_leave: Покинут Мир +world_etc: Мир... +world_leave: Покинут мир worlds: Миры +yes: Да diff --git a/locales/uk.csv b/locales/uk.csv index 4b5b20d..1548bc6 100644 --- a/locales/uk.csv +++ b/locales/uk.csv @@ -1,8 +1,14 @@ amount: Номер +ask_world_delete_1: Світ " +ask_world_delete_2: " дійсно видалити? back_to_game: Повернуться в игру +change_world_name: Змінити имя світу chunk_regenerated: Участки відновлени. chunks_loaded: Участки будуть завантаженні. commands: Укази +delete_local: видалити (локальні) +delete_world: Видалити світ +delete: видалити download_world_from_server: Завантажити світ з сервера download: Завантажити error_amount_minimum_1: Номер повинен бути як мінімум 1! @@ -11,7 +17,9 @@ error_conflict_2: " Було змінено як тут, так і в інших error_conflict_3: ) | Скасувати: Завантажте це сюди ( error_conflict_4: ) error_connection: Ошибка поключения +error_delete_world: Помилка при видалення світу: error_download_world: Помилка завантаження світу: +error_edit_world: Помилка редагування світу: error_gamemode_range: Ігровий режим повинен бути 0..2! error_invalid_block_type: Недійсний тип блоку! error_inventory_full: Інвентар повний! @@ -19,6 +27,7 @@ error_list_is_loading: Список ще завантажується! error_loading_worldlist: Помилка завантаження списку світ: error_name_too_long: Назва занадто довга! error_no_permission_logged_in: Нема авторизації. Зареєстрований? +error_no_permission: Відсутня авторизація! error_no_world_selected: Не вибраний світ! error_not_logged_in: Не зареєстрований! error_only_vert_supported: Підтримується тільки "vert"! @@ -29,6 +38,7 @@ error_upload_world: Помилка завантаження світу: error_world_is_loading: Світ ще завантажується! error_world_is_present_both_sides: Світ уже існує на сайті! error_world_not_downloaded: Світ ще не завантажений! +error_world_not_uploaded: Світ ще ни завантажень! game_saved: Игра сохранена. gamemode_set_to: Ігровий режим встановлен на inventory_cleared: Інвентар теперь порожній @@ -37,17 +47,24 @@ item_labels: Повітря,Камінь,Блок трави,Земля,Буто items_given: Дані предмети join_selected_world: Ввійти у вибраний світ login: Зареєструватися +modification: Зміни mouse_mode_normal: Звичайний режим миші. mouse_mode_selection: Виділення кнопками миші. mouse_sensitivity: Чутливість миші +name_existing_world: Нове имя світу:\n(макс. 16 символів) name_new_world: Имя новому світу:\n(макс. 16 Символів) new_world: Новий світ +no: Ні only_local: Тільки локальні світ. open: Відчинити +owner: Власник player: Игрок project_page: Сторінка проекту +public: Публічно +publish_world: Зробіть світ публічним refresh: Оновити reload_list: Оновити список +rename: Перейменувати resolution: Дозвіл selection_expanded: Вибір розширен. selection_none: нічого @@ -56,24 +73,28 @@ selection_primary: Перша точка вибору selection_secondary_short: Другий selection_secondary: Друга точка вибору settings: Налаштування +show_world_settings: Акції/Показати Налаштування Світу. spawn_updated: Початкова точка оновлена. surfaces_colored: Однотонні surfaces_textured: Текстурований surfaces: Поверхности teleported_to_spawn: Перемістился до початкової точки. teleported_to: Переміститися к +today: сегодня transfer: Перемістит unknown_command: Недійсна команда +unknown_world_found: Бул знайден безіменний локальний світ. Як ії назвати? unknown_world: Недійсни світ -unknown_world_found: Бул знайден безіменний локальний світ. Як ії назвати? +unpublish_world: Зробіть світ приватним upload_world_to_server: Завантажити світ на сервер upload: Завантажити -user_colon: Користувач: version_1: Версія version_2: от L3P3 view_angle: Точка огляду view_distance: Видимість warn_world_remote_missing_1: Світ " warn_world_remote_missing_2: " був не знайден на сервере, тому він тепер локальний! +world_etc: Світ... world_leave: Покинуті світ worlds: Світі +yes: Так diff --git a/package.json b/package.json index 2e42d85..63af2c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minicraft", - "version": "0.9.7", + "version": "0.9.8", "description": "voxel-based 3d game, written in javascript", "homepage": "https://l3p3.de/minicraft", "repository": { diff --git a/src/app.css b/src/app.css index 5a2500c..fa7d59e 100644 --- a/src/app.css +++ b/src/app.css @@ -23,7 +23,8 @@ div { box-sizing: border-box; } button { - font-family: inherit; + cursor: unset; + font-family: unset; } .game { @@ -46,7 +47,6 @@ button { .game > .bar { position: absolute; width: 22.5rem; - max-width: 100%; left: 50%; margin-left: -11.25rem; bottom: 0; @@ -58,6 +58,7 @@ button { .game > .bar { left: 0; margin-left: 0; + width: 100%; } } .game > .bar > * { @@ -216,25 +217,31 @@ button { transform: rotate(45deg); } -.game > .menu { +.game .menu { position: absolute; width: 100%; height: 100%; } -.game > .menu.overlay { +.game .menu.busy { + cursor: wait; +} +.game .menu.overlay { + left: 0; + top: 0; background: rgba(0, 0, 0, .7); } -.game > .menu > h1 { +.game .menu h1 { text-align: center; } -.game > .menu > center { +.game .menu > center { margin: 1rem 0; } -.game > .menu > center button { +.game .menu center button { width: 12rem; + max-width: calc(50vw - 1rem); height: 3rem; } -.game > .menu > .worlds { +.game .menu > .worlds { width: 100%; max-width: 30rem; margin: 1rem auto; @@ -242,32 +249,32 @@ button { overflow-y: scroll; touch-action: pan-y; } -.game > .menu > .worlds > * { +.game .menu > .worlds > * { cursor: pointer; padding: .2rem .5rem; } -.game > .menu > .worlds > :nth-child(odd) { +.game .menu > .worlds > :nth-child(odd) { background: #222; } -.game > .menu > .worlds > .selected { +.game .menu > .worlds > .selected { background: green; } -.game > .menu > .worlds > * > :last-child { +.game .menu > .worlds > * > :last-child { float: right; } -.game > .menu > .settings { +.game .menu > .settings { margin: 1rem; display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); grid-template-rows: 3rem; gap: 1rem; } -.game > .menu.inventory { +.game .menu.inventory, .game .menu.advanced { display: flex; align-items: center; justify-content: center; } -.game > .menu.inventory > .window { +.game .menu > .window { border-radius: .5rem; background: #ccc; display: flex; @@ -276,21 +283,25 @@ button { gap: .5rem; color: #333; } -.game > .menu.inventory > .window > .grid { +.game .menu > .window > h2 { + margin: 0; + font-size: unset; +} +.game .menu.inventory > .window > .grid { display: grid; grid-template-columns: repeat(9, 2rem); gap: .25rem; } -.game > .menu.inventory > .window > .grid > * { +.game .menu.inventory > .window > .grid > * { width: 2rem; height: 2rem; background: #aaa; } -.game > .menu.inventory > .window > .grid > .first { +.game .menu.inventory > .window > .grid > .first { grid-row-start: 4; background: #999; } -.game > .menu.inventory > .hand { +.game .menu.inventory > .hand { position: absolute; left: 0; top: 0; @@ -335,8 +346,9 @@ button { .game > .terminal > input { border: none; background: black; - color: inherit; - font: inherit; + color: unset; + font: unset; + padding: 4px; } .game > .messages { position: absolute; diff --git a/src/etc/helpers.js b/src/etc/helpers.js index db9f692..469d5e2 100644 --- a/src/etc/helpers.js +++ b/src/etc/helpers.js @@ -1,3 +1,7 @@ +import { + locale_today, +} from '../etc/locale.js'; + export const window_ = window; export const document_ = document; const Math_ = Math; @@ -73,7 +77,7 @@ export const touch_id_get = event => event.changedTouches[0].identifier; */ export const handler_noop = () => false; -export const datify = time => { +export const datify = (time, short) => { const date_now = new Date_(); const date_then = new Date_(time); @@ -101,8 +105,11 @@ export const datify = time => { result || date < date_now.getDate() ) { - result += date + '/'; + result += date; } + if (short) return result || locale_today; + if (result) result += '/'; + return result + date_then.getHours() + ':' + number_padStart2(date_then.getMinutes(), '0'); } diff --git a/src/etc/locale.js b/src/etc/locale.js index d057296..348551e 100644 --- a/src/etc/locale.js +++ b/src/etc/locale.js @@ -1,8 +1,14 @@ export const locale_amount = 'Anzahl'; +export const locale_ask_world_delete_1 = 'Welt "'; +export const locale_ask_world_delete_2 = '" wirklich löschen?'; export const locale_back_to_game = 'Zurück zum Spiel'; +export const locale_change_world_name = 'Welt-Namen ändern'; export const locale_chunk_regenerated = 'Chunk neu generiert.'; export const locale_chunks_loaded = 'Chunks geladen.'; export const locale_commands = 'Befehle'; +export const locale_delete_local = 'Löschen (lokal)'; +export const locale_delete_world = 'Welt löschen'; +export const locale_delete = 'Löschen'; export const locale_download_world_from_server = 'Welt von Server herunterladen'; export const locale_download = 'Herunterladen'; export const locale_error_amount_minimum_1 = 'Anzahl muss mindestens 1 sein!'; @@ -11,7 +17,9 @@ export const locale_error_conflict_2 = '" wurde sowohl hier als auch woanders ge export const locale_error_conflict_3 = ') | Abbrechen: Die hier hochladen ('; export const locale_error_conflict_4 = ')'; export const locale_error_connection = 'Verbindungsfehler.'; +export const locale_error_delete_world = 'Fehler beim Löschen der Welt: '; export const locale_error_download_world = 'Fehler beim Herunterladen der Welt: '; +export const locale_error_edit_world = 'Fehler beim Bearbeiten der Welt: '; export const locale_error_gamemode_range = 'Spielmodus muss in 0..2 sein!'; export const locale_error_invalid_block_type = 'Ungültiger Blocktyp!'; export const locale_error_inventory_full = 'Inventar ist voll!'; @@ -19,6 +27,7 @@ export const locale_error_list_is_loading = 'Liste wird noch geladen!'; export const locale_error_loading_worldlist = 'Fehler beim Laden der Weltenliste: '; export const locale_error_name_too_long = 'Der Name ist zu lang!'; export const locale_error_no_permission_logged_in = 'Keine Berechtigung. Angemeldet?'; +export const locale_error_no_permission = 'Fehlende Berechtigung!'; export const locale_error_no_world_selected = 'Keine Welt ausgewählt!'; export const locale_error_not_logged_in = 'Nicht angemeldet!'; export const locale_error_only_vert_supported = 'Nur "vert" wird unterstützt!'; @@ -29,6 +38,7 @@ export const locale_error_upload_world = 'Fehler beim Hochladen der Welt: '; export const locale_error_world_is_loading = 'Die Welt wird noch geladen!'; export const locale_error_world_is_present_both_sides = 'Die Welt ist schon auf beiden Seiten vorhanden!'; export const locale_error_world_not_downloaded = 'Die Welt ist noch nicht heruntergeladen!'; +export const locale_error_world_not_uploaded = 'Die Welt ist nicht hochgeladen!'; export const locale_game_saved = 'Spiel gespeichert.'; export const locale_gamemode_set_to = 'Spielmodus gesetzt auf'; export const locale_inventory_cleared = 'Inventar geleert'; @@ -37,17 +47,24 @@ export const locale_item_labels = 'Luft,Stein,Grasblock,Erde,Bruchstein,Holzbret export const locale_items_given = 'Items gegeben'; export const locale_join_selected_world = 'Ausgewählte Welt betreten'; export const locale_login = 'Anmelden'; +export const locale_modification = 'Änderung'; export const locale_mouse_mode_normal = 'Normaler Mausmodus.'; export const locale_mouse_mode_selection = 'Auswahl mit Maustasten.'; export const locale_mouse_sensitivity = 'Mausempfindlichkeit'; +export const locale_name_existing_world = 'Neuer Name der Welt:\n(max. 16 Zeichen)'; export const locale_name_new_world = 'Name der neuen Welt:\n(max. 16 Zeichen)'; export const locale_new_world = 'Neue Welt'; +export const locale_no = 'Nein'; export const locale_only_local = 'Nur lokale Welt'; export const locale_open = 'Öffnen'; +export const locale_owner = 'Besitzer'; export const locale_player = 'Spieler'; export const locale_project_page = 'Projektseite'; +export const locale_public = 'Öffentlich'; +export const locale_publish_world = 'Welt veröffentlichen'; export const locale_refresh = 'Aktualisieren'; export const locale_reload_list = 'Liste neu laden'; +export const locale_rename = 'Umbenennen'; export const locale_resolution = 'Auflösung'; export const locale_selection_expanded = 'Auswahl erweitert.'; export const locale_selection_none = 'nichts'; @@ -56,24 +73,28 @@ export const locale_selection_primary = 'Erster Auswahlpunkt'; export const locale_selection_secondary_short = 'Zweiter'; export const locale_selection_secondary = 'Zweiter Auswahlpunkt'; export const locale_settings = 'Einstellungen'; +export const locale_show_world_settings = 'Aktionen/Einstellungen zur Welt anzeigen'; export const locale_spawn_updated = 'Startpunkt aktualisiert.'; export const locale_surfaces_colored = 'Einfarbig'; export const locale_surfaces_textured = 'Texturiert'; export const locale_surfaces = 'Oberflächen'; export const locale_teleported_to_spawn = 'Zum Startpunkt teleportiert.'; export const locale_teleported_to = 'Teleportiert zu'; +export const locale_today = 'heute'; export const locale_transfer = 'Übertragen'; export const locale_unknown_command = 'Ungültiger Befehl'; -export const locale_unknown_world = 'Unbekannte Welt'; export const locale_unknown_world_found = 'Es wurde eine namenlose lokale Welt gefunden. Wie soll sie heißen?'; +export const locale_unknown_world = 'Unbekannte Welt'; +export const locale_unpublish_world = 'Welt privat machen'; export const locale_upload_world_to_server = 'Welt auf den Server hochladen'; export const locale_upload = 'Hochladen'; -export const locale_user_colon = 'Nutzer: '; export const locale_version_1 = 'Version '; export const locale_version_2 = ' von L3P3'; export const locale_view_angle = 'Blickwinkel'; export const locale_view_distance = 'Sichtweite'; export const locale_warn_world_remote_missing_1 = 'Die Welt "'; export const locale_warn_world_remote_missing_2 = '" wurde auf dem Server nicht gefunden, ist also jetzt eine lokale!'; +export const locale_world_etc = 'Welt...'; export const locale_world_leave = 'Welt verlassen'; export const locale_worlds = 'Welten'; +export const locale_yes = 'Ja'; diff --git a/src/externs.js b/src/externs.js index e60b613..e80e608 100644 --- a/src/externs.js +++ b/src/externs.js @@ -296,6 +296,7 @@ var TYPE_WORLD_LISTING_LOCAL; id: number, label: string, modified: number, + public: boolean, writable: boolean, }} */ @@ -330,3 +331,10 @@ var TYPE_CHAT_API; }} */ var TYPE_RESPONSE_INITIAL; + +/** + @typedef {{ + busy: boolean, + }} +*/ +var TYPE_CSS_CLASSES; diff --git a/src/game/c_menu_start.js b/src/game/c_menu_start.js index dd92160..0604d2e 100644 --- a/src/game/c_menu_start.js +++ b/src/game/c_menu_start.js @@ -30,6 +30,12 @@ import { localStorage_setItem, } from '../etc/helpers.js'; import { + locale_ask_world_delete_1, + locale_ask_world_delete_2, + locale_change_world_name, + locale_delete, + locale_delete_local, + locale_delete_world, locale_download_world_from_server, locale_download, locale_error_conflict_1, @@ -37,10 +43,13 @@ import { locale_error_conflict_3, locale_error_conflict_4, locale_error_connection, + locale_error_delete_world, locale_error_download_world, + locale_error_edit_world, locale_error_list_is_loading, locale_error_loading_worldlist, locale_error_name_too_long, + locale_error_no_permission, locale_error_no_permission_logged_in, locale_error_no_world_selected, locale_error_not_logged_in, @@ -49,24 +58,35 @@ import { locale_error_world_is_loading, locale_error_world_is_present_both_sides, locale_error_world_not_downloaded, + locale_error_world_not_uploaded, locale_join_selected_world, locale_login, + locale_modification, + locale_name_existing_world, locale_name_new_world, locale_new_world, + locale_no, locale_only_local, locale_open, + locale_owner, locale_project_page, + locale_public, + locale_publish_world, locale_refresh, locale_reload_list, + locale_rename, + locale_show_world_settings, locale_transfer, + locale_unpublish_world, locale_upload_world_to_server, locale_upload, - locale_user_colon, locale_version_1, locale_version_2, locale_warn_world_remote_missing_1, locale_warn_world_remote_missing_2, + locale_world_etc, locale_worlds, + locale_yes, } from '../etc/locale.js'; function WorldItem({ @@ -97,7 +117,11 @@ function WorldItem({ ) : '_' }${ - I.remote ? 'R' : '_' + !I.remote + ? '_' + : I.public + ? 'R' + : 'r' }`; if (world_busy_id === I.id) { flags = `[${flags}]`; @@ -106,10 +130,14 @@ function WorldItem({ return [ node_dom('span', { innerText: `${flags} ${I.label}`, - title: I.account_name ? locale_user_colon + I.account_name : locale_only_local, + title: ( + I.account_name + ? locale_owner + ': ' + I.account_name + : locale_only_local + ), }), node_dom('span', { - innerText: datify(Math.max(I.local, I.remote)), + innerText: datify(Math.max(I.local, I.remote), true), }), ]; } @@ -182,6 +210,7 @@ export default function MenuStart({ id: world.id, label: world.label, local: 0, + public: world.public, remote: world.modified, writable: world.writable, })) @@ -203,8 +232,8 @@ export default function MenuStart({ locale_error_conflict_1 + world_local.label + locale_error_conflict_2 + - datify(last_change_there) + locale_error_conflict_3 + - datify(last_change_here) + + datify(last_change_there, false) + locale_error_conflict_3 + + datify(last_change_here, false) + locale_error_conflict_4 )) { actions.world_prop(world_local.id, { @@ -240,6 +269,7 @@ export default function MenuStart({ id: world_local.id, label: world_local.label, local: world_local.mod_l, + public: false, remote: world_local.mod_r === 1 ? 1 : 0, writable: true, }); @@ -420,6 +450,10 @@ export default function MenuStart({ }; }, [world_busy_id]); + const [menu_opened, menu_opened_set] = hook_state(false); + if (!world_selected) menu_opened_set(false); + const [busy, busy_set] = hook_state(false); + return [ node_dom(`h1[innerText=${locale_worlds}]`), node_dom(`button[innerText=${locale_refresh}][style=position:absolute;left:0;top:0;height:2rem][title=${locale_reload_list}]`, { @@ -466,47 +500,18 @@ export default function MenuStart({ : locale_join_selected_world ), }), - node_dom('button', { + node_dom(`button[innerText=${locale_world_etc}]`, { disabled: ( - !world_list_remote || !world_selected || - world_selected.local > 0 && world_selected.remote > 0 || - !world_selected.remote && !account.rank - ), - innerText: ( - world_selected && !world_selected.local - ? locale_download - : world_list_remote && world_selected && !world_selected.remote - ? locale_upload - : locale_transfer + menu_opened ), onclick: () => { - if (!world_selected.local) { - actions.world_add({ - id: world_selected.id, - label: world_selected.label, - mod_l: 1, - mod_r: world_selected.remote, - }); - } - else if (!world_selected.remote) { - actions.world_prop(world_selected.id, { - mod_r: 1, - }); - } + menu_opened_set(true); }, title: ( - !world_list_remote - ? locale_error_list_is_loading - : !world_selected - ? locale_error_no_world_selected - : !world_selected.local - ? locale_download_world_from_server - : world_selected.remote - ? locale_error_world_is_present_both_sides - : account.rank - ? locale_upload_world_to_server - : locale_error_not_logged_in + world_selected + ? locale_show_world_settings + : locale_error_no_world_selected ), }), ]), @@ -537,5 +542,241 @@ export default function MenuStart({ node_dom('center', null, [ node_dom(`small[innerText=${locale_version_1 + VERSION + locale_version_2}]`), ]), + menu_opened && + world_selected && + node_dom('div', { + F: { + 'menu overlay advanced': true, + busy, + }, + onclick: event => { + if (event.target.className === 'menu overlay advanced') { + menu_opened_set(false); + } + }, + }, [ + node_dom('div[className=window]', null, [ + node_dom('h2', { + innerText: '"' + world_selected.label +'"', + }), + node_dom('table', null, [ + !!world_selected.account_name && + node_dom('tr', null, [ + node_dom(`td[innerText=${locale_owner}:]`), + node_dom('td', { + innerText: world_selected.account_name, + }), + ]), + node_dom('tr', null, [ + node_dom(`td[innerText=${locale_modification}:]`), + node_dom('td', { + innerText: datify(Math.max( + world_selected.local, + world_selected.remote + ), false), + }), + ]), + ]), + node_dom('center', null, [ + node_dom(`button[innerText=${locale_rename}]`, { + disabled: ( + busy || + !world_selected.writable + ), + onclick: () => { + const name = prompt(locale_name_existing_world, world_selected.label); + if ( + !name || + name === world_selected.label || + name.length > 16 + ) return; + if (world_selected.local) { + actions.world_prop(world_selected.id, { + label: name, + }); + } + if (world_selected.remote) { + busy_set(true); + fetch(API + 'world', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON_stringify({ + what: 'meta', + world: world_selected.id, + label: name, + }), + }) + .then(response => { + if (!response.ok) throw new Error( + response.status === 403 + ? locale_error_no_permission_logged_in + : locale_error_connection + ); + return response.json(); + }) + .catch(error => { + alert(locale_error_edit_world + error.message); + }) + .then(() => { + busy_set(false); + }); + } + }, + title: ( + world_selected.writable + ? locale_change_world_name + : locale_error_no_permission + ), + }), + node_dom('button', { + disabled: ( + busy || + !world_selected.local && + !world_selected.writable + ), + innerText: ( + world_selected.local + ? locale_delete_local + : locale_delete + ), + onclick: () => { + if (!confirm( + locale_ask_world_delete_1 + world_selected.label + locale_ask_world_delete_2 + )) return; + if (world_selected.local) { + actions.world_remove(world_selected.id); + } + else { + busy_set(true); + fetch(API + 'world', { + method: 'DELETE', + headers: {'Content-Type': 'application/json'}, + body: JSON_stringify({ + what: 'world', + world: world_selected.id, + }), + }) + .then(response => { + if (!response.ok) throw new Error( + response.status === 403 + ? locale_error_no_permission_logged_in + : locale_error_connection + ); + defer(); + world_selected_id_set(null); + menu_opened_set(false); + refresh(); + busy_set(false); + defer_end(); + return response.json(); + }) + .catch(error => { + alert(locale_error_delete_world + error.message); + busy_set(false); + }); + } + }, + title: ( + !world_selected.local && + !world_selected.writable + ? locale_error_no_permission + : locale_delete_world + ), + }), + ]), + node_dom('center', null, [ + node_dom('button', { + disabled: ( + busy || + !world_selected.remote || + !world_selected.writable + ), + innerText: `${locale_public}: ${ + world_selected.public + ? locale_yes + : locale_no + }`, + onclick: () => { + busy_set(true); + fetch(API + 'world', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON_stringify({ + what: 'meta', + world: world_selected.id, + public: !world_selected.public, + }), + }) + .then(response => { + if (!response.ok) throw new Error( + response.status === 403 + ? locale_error_no_permission_logged_in + : locale_error_connection + ); + defer(); + refresh(); + busy_set(false); + defer_end(); + return response.json(); + }) + .catch(error => { + alert(locale_error_edit_world + error.message); + busy_set(false); + }); + }, + title: ( + !world_selected.remote + ? locale_error_world_not_uploaded + : !world_selected.writable + ? locale_error_no_permission + : world_selected.public + ? locale_unpublish_world + : locale_publish_world + ), + }), + node_dom('button', { + disabled: ( + busy || + !world_list_remote || + world_selected.local > 0 && world_selected.remote > 0 || + !world_selected.remote && !account.rank + ), + innerText: ( + !world_selected.local + ? locale_download + : world_list_remote && world_selected && !world_selected.remote + ? locale_upload + : locale_transfer + ), + onclick: () => { + if (!world_selected.local) { + actions.world_add({ + id: world_selected.id, + label: world_selected.label, + mod_l: 1, + mod_r: world_selected.remote, + }); + } + else if (!world_selected.remote) { + actions.world_prop(world_selected.id, { + mod_r: 1, + }); + } + }, + title: ( + !world_list_remote + ? locale_error_list_is_loading + : !world_selected.local + ? locale_download_world_from_server + : world_selected.remote + ? locale_error_world_is_present_both_sides + : account.rank + ? locale_upload_world_to_server + : locale_error_not_logged_in + ), + }), + ]), + ]), + ]), ]; }