localize room settings
This commit is contained in:
parent
d120a9a933
commit
becdbc3d3a
33 changed files with 836 additions and 291 deletions
|
|
@ -607,5 +607,228 @@
|
||||||
"existing_space": "Existing Space",
|
"existing_space": "Existing Space",
|
||||||
"add_room": "Add Room",
|
"add_room": "Add Room",
|
||||||
"existing_room": "Existing Room"
|
"existing_room": "Existing Room"
|
||||||
|
},
|
||||||
|
|
||||||
|
"RoomSettings": {
|
||||||
|
"general": "General",
|
||||||
|
"members": "Members",
|
||||||
|
"permissions": "Permissions",
|
||||||
|
"emojis_stickers": "Emojis & Stickers",
|
||||||
|
"developer_tools": "Developer Tools",
|
||||||
|
|
||||||
|
"profile": "Profile",
|
||||||
|
"edit": "Edit",
|
||||||
|
"unknown": "Unknown",
|
||||||
|
"avatar": "Avatar",
|
||||||
|
"upload": "Upload",
|
||||||
|
"reset": "Reset",
|
||||||
|
"remove": "Remove",
|
||||||
|
"name": "Name",
|
||||||
|
"topic": "Topic",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
|
||||||
|
"options": "Options",
|
||||||
|
"addresses": "Addresses",
|
||||||
|
"advanced_options": "Advanced Options",
|
||||||
|
|
||||||
|
"space_access": "Space Access",
|
||||||
|
"room_access": "Room Access",
|
||||||
|
"space_access_desc": "Change how people can join the space.",
|
||||||
|
"room_access_desc": "Change how people can join the room.",
|
||||||
|
|
||||||
|
"join_invite_only": "Invite Only",
|
||||||
|
"join_knock_invite": "Knock & Invite",
|
||||||
|
"join_space_members_or_knock": "Space Members or Knock",
|
||||||
|
"join_space_members": "Space Members",
|
||||||
|
"join_public": "Public",
|
||||||
|
"join_unsupported": "Unsupported",
|
||||||
|
|
||||||
|
"history_visibility": "Message History Visibility",
|
||||||
|
"history_visibility_desc": "Changes to history visibility will only apply to future messages and will not affect existing history.",
|
||||||
|
"visibility_after_invite": "After Invite",
|
||||||
|
"visibility_after_join": "After Join",
|
||||||
|
"visibility_all_messages": "All Messages",
|
||||||
|
"visibility_all_messages_guests": "All Messages (Guests)",
|
||||||
|
|
||||||
|
"room_encryption": "Room Encryption",
|
||||||
|
"encryption_enabled_desc": "Messages in this room are protected by end-to-end encryption.",
|
||||||
|
"encryption_disabled_desc": "Once enabled, encryption cannot be disabled!",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"enable": "Enable",
|
||||||
|
"enable_encryption": "Enable Encryption",
|
||||||
|
"enable_encryption_confirm": "Are you sure? Once enabled, encryption cannot be disabled!",
|
||||||
|
"enable_e2e_encryption": "Enable E2E Encryption",
|
||||||
|
|
||||||
|
"publish_to_directory": "Publish to Directory",
|
||||||
|
"publish_space_desc": "List the space in the public directory to make it discoverable by others.",
|
||||||
|
"publish_room_desc": "List the room in the public directory to make it discoverable by others.",
|
||||||
|
|
||||||
|
"published_addresses": "Published Addresses",
|
||||||
|
"published_addresses_desc": "If access is <b>Public</b>, Published addresses will be used to join by anyone.",
|
||||||
|
"no_addresses": "No Addresses",
|
||||||
|
"no_addresses_hint": "To publish an address, it needs to be set as a local address first",
|
||||||
|
"main": "Main",
|
||||||
|
"unset_main": "Unset Main",
|
||||||
|
"set_main": "Set Main",
|
||||||
|
"address_in_use": "Address is already in use!",
|
||||||
|
"published": "Published",
|
||||||
|
"unpublish": "Unpublish",
|
||||||
|
"publish": "Publish",
|
||||||
|
"delete": "Delete",
|
||||||
|
"selected_count": "{{count}} Selected",
|
||||||
|
|
||||||
|
"local_addresses": "Local Addresses",
|
||||||
|
"local_addresses_desc": "Set local address so users can join through your homeserver.",
|
||||||
|
"collapse": "Collapse",
|
||||||
|
"expand": "Expand",
|
||||||
|
"loading": "Loading...",
|
||||||
|
|
||||||
|
"space_upgrade": "Space Upgrade",
|
||||||
|
"room_upgrade": "Room Upgrade",
|
||||||
|
"upgrade": "Upgrade",
|
||||||
|
"action_irreversible": "This action is irreversible!",
|
||||||
|
"upgrade_space": "Upgrade Space",
|
||||||
|
"upgrade_room": "Upgrade Room",
|
||||||
|
"space_replaced": "This space has been replaced!",
|
||||||
|
"room_replaced": "This room has been replaced!",
|
||||||
|
"current_version": "Current version: {{version}}.",
|
||||||
|
"old_space": "Old Space",
|
||||||
|
"old_room": "Old Room",
|
||||||
|
"open_new_space": "Open New Space",
|
||||||
|
"open_new_room": "Open New Room",
|
||||||
|
|
||||||
|
"members_count": "{{count}} Members",
|
||||||
|
"search": "Search",
|
||||||
|
"no_results": "No Results",
|
||||||
|
"results_count": "{{count}} Results",
|
||||||
|
"scroll_to_top": "Scroll to Top",
|
||||||
|
"no_membership_members": "No \"{{filter}}\" Members",
|
||||||
|
|
||||||
|
"filter_joined": "Joined",
|
||||||
|
"filter_invited": "Invited",
|
||||||
|
"filter_left": "Left",
|
||||||
|
"filter_kicked": "Kicked",
|
||||||
|
"filter_banned": "Banned",
|
||||||
|
|
||||||
|
"sort_a_to_z": "A to Z",
|
||||||
|
"sort_z_to_a": "Z to A",
|
||||||
|
"sort_newest": "Newest",
|
||||||
|
"sort_oldest": "Oldest",
|
||||||
|
|
||||||
|
"perm_messages": "Messages",
|
||||||
|
"perm_send_messages": "Send Messages",
|
||||||
|
"perm_send_stickers": "Send Stickers",
|
||||||
|
"perm_send_reactions": "Send Reactions",
|
||||||
|
"perm_ping_room": "Ping @room",
|
||||||
|
"perm_pin_messages": "Pin Messages",
|
||||||
|
"perm_other_message_events": "Other Message Events",
|
||||||
|
"perm_calls": "Calls",
|
||||||
|
"perm_join_call": "Join Call",
|
||||||
|
"perm_moderation": "Moderation",
|
||||||
|
"perm_invite": "Invite",
|
||||||
|
"perm_kick": "Kick",
|
||||||
|
"perm_ban": "Ban",
|
||||||
|
"perm_delete_others_messages": "Delete Others' Messages",
|
||||||
|
"perm_delete_self_messages": "Delete Self Messages",
|
||||||
|
"perm_room_overview": "Room Overview",
|
||||||
|
"perm_room_avatar": "Room Avatar",
|
||||||
|
"perm_room_name": "Room Name",
|
||||||
|
"perm_room_topic": "Room Topic",
|
||||||
|
"perm_settings": "Settings",
|
||||||
|
"perm_change_room_access": "Change Room Access",
|
||||||
|
"perm_publish_address": "Publish Address",
|
||||||
|
"perm_change_all_permission": "Change All Permissions",
|
||||||
|
"perm_edit_power_levels": "Edit Power Levels",
|
||||||
|
"perm_enable_encryption": "Enable Encryption",
|
||||||
|
"perm_history_visibility": "History Visibility",
|
||||||
|
"perm_upgrade_room": "Upgrade Room",
|
||||||
|
"perm_other_settings": "Other Settings",
|
||||||
|
"perm_other": "Other",
|
||||||
|
"perm_manage_emojis_stickers": "Manage Emojis & Stickers",
|
||||||
|
"perm_change_server_acls": "Change Server ACLs",
|
||||||
|
"perm_modify_widgets": "Modify Widgets",
|
||||||
|
|
||||||
|
"founders": "Founders",
|
||||||
|
"founders_desc": "Founding members have all permissions and can only be changed during a room upgrade.",
|
||||||
|
"power_levels": "Power Levels",
|
||||||
|
"power_levels_desc": "Manage and customize incremental power levels for users.",
|
||||||
|
|
||||||
|
"new_power_level": "New Power Level",
|
||||||
|
"new_power_level_desc": "Create a new power level.",
|
||||||
|
"power_level_placeholder": "Bot",
|
||||||
|
"create": "Create",
|
||||||
|
"color": "Color",
|
||||||
|
"pick": "Pick",
|
||||||
|
"power": "Power",
|
||||||
|
"icon": "Icon",
|
||||||
|
"import": "Import",
|
||||||
|
"undo": "Undo",
|
||||||
|
"used_power_level": "Used Power Level",
|
||||||
|
"used_power_level_desc": "You have to remove its use before you can delete it.",
|
||||||
|
"changes_saved": "Changes saved! Apply when ready.",
|
||||||
|
"failed_to_apply": "Failed to apply changes! Please try again.",
|
||||||
|
"apply_changes": "Apply Changes",
|
||||||
|
"and_above": "& Above",
|
||||||
|
|
||||||
|
"users": "Users",
|
||||||
|
"default_power": "Default Power",
|
||||||
|
"default_power_desc": "Default power level for all users.",
|
||||||
|
|
||||||
|
"packs": "Packs",
|
||||||
|
"new_pack": "New Pack",
|
||||||
|
"new_pack_desc": "Add your own emoji and sticker pack to use in room.",
|
||||||
|
"no_packs": "No Packs",
|
||||||
|
"no_packs_desc": "There are no emoji or sticker packs to display at the moment.",
|
||||||
|
"view": "View",
|
||||||
|
"failed_to_remove_packs": "Failed to remove packs! Please try again.",
|
||||||
|
"delete_selected_packs": "Delete selected packs. ({{count}} selected)",
|
||||||
|
|
||||||
|
"enable_developer_tools": "Enable Developer Tools",
|
||||||
|
"room_id": "Room ID",
|
||||||
|
"room_id_desc": "Copy room ID to clipboard.",
|
||||||
|
"copy": "Copy",
|
||||||
|
"data": "Data",
|
||||||
|
"new_message_event": "New Message Event",
|
||||||
|
"new_message_event_desc": "Create and send a new message event within the room.",
|
||||||
|
"compose": "Compose",
|
||||||
|
"room_state": "Room State",
|
||||||
|
"room_state_desc": "State events of the room.",
|
||||||
|
"events": "Events",
|
||||||
|
"total": "Total: {{count}}",
|
||||||
|
"add_new": "Add New",
|
||||||
|
"default_key": "Default",
|
||||||
|
"account_data": "Account Data",
|
||||||
|
"account_data_desc": "Private personalization data stored within room.",
|
||||||
|
"state_event": "State Event",
|
||||||
|
"json_content": "JSON Content",
|
||||||
|
"state_event_type": "State Event Type",
|
||||||
|
"message_event_type": "Message Event Type",
|
||||||
|
"send": "Send",
|
||||||
|
"state_key_optional": "State Key (Optional)",
|
||||||
|
|
||||||
|
"pack": "Pack",
|
||||||
|
"images_usage": "Images Usage",
|
||||||
|
"images_usage_desc": "Select how the images are being used: as emojis, as stickers, or as both.",
|
||||||
|
"images": "Images",
|
||||||
|
"upload_images": "Upload Images",
|
||||||
|
"upload_images_desc": "Select images from your storage to upload them in pack.",
|
||||||
|
"select": "Select",
|
||||||
|
"pack_avatar": "Pack Avatar",
|
||||||
|
"attribution": "Attribution",
|
||||||
|
"shortcode": "Shortcode:",
|
||||||
|
"body": "Body:",
|
||||||
|
"usage_both": "Both",
|
||||||
|
"usage_sticker": "Sticker",
|
||||||
|
"usage_emoji": "Emoji",
|
||||||
|
|
||||||
|
"power_goku": "Goku",
|
||||||
|
"power_manager": "Manager",
|
||||||
|
"power_founder": "Founder",
|
||||||
|
"power_admin": "Admin",
|
||||||
|
"power_moderator": "Moderator",
|
||||||
|
"power_member": "Member",
|
||||||
|
"power_muted": "Muted",
|
||||||
|
"power_team": "Team"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -609,5 +609,228 @@
|
||||||
"existing_space": "Существующее пространство",
|
"existing_space": "Существующее пространство",
|
||||||
"add_room": "Добавить комнату",
|
"add_room": "Добавить комнату",
|
||||||
"existing_room": "Существующая комната"
|
"existing_room": "Существующая комната"
|
||||||
|
},
|
||||||
|
|
||||||
|
"RoomSettings": {
|
||||||
|
"general": "Основные",
|
||||||
|
"members": "Участники",
|
||||||
|
"permissions": "Права доступа",
|
||||||
|
"emojis_stickers": "Эмодзи и стикеры",
|
||||||
|
"developer_tools": "Инструменты разработчика",
|
||||||
|
|
||||||
|
"profile": "Профиль",
|
||||||
|
"edit": "Редактировать",
|
||||||
|
"unknown": "Неизвестно",
|
||||||
|
"avatar": "Аватар",
|
||||||
|
"upload": "Загрузить",
|
||||||
|
"reset": "Сбросить",
|
||||||
|
"remove": "Удалить",
|
||||||
|
"name": "Название",
|
||||||
|
"topic": "Тема",
|
||||||
|
"save": "Сохранить",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
|
||||||
|
"options": "Настройки",
|
||||||
|
"addresses": "Адреса",
|
||||||
|
"advanced_options": "Дополнительные настройки",
|
||||||
|
|
||||||
|
"space_access": "Доступ к пространству",
|
||||||
|
"room_access": "Доступ к комнате",
|
||||||
|
"space_access_desc": "Изменить способ вступления в пространство.",
|
||||||
|
"room_access_desc": "Изменить способ вступления в комнату.",
|
||||||
|
|
||||||
|
"join_invite_only": "Только по приглашению",
|
||||||
|
"join_knock_invite": "Запрос и приглашение",
|
||||||
|
"join_space_members_or_knock": "Участники пространства или запрос",
|
||||||
|
"join_space_members": "Участники пространства",
|
||||||
|
"join_public": "Публичный",
|
||||||
|
"join_unsupported": "Не поддерживается",
|
||||||
|
|
||||||
|
"history_visibility": "Видимость истории сообщений",
|
||||||
|
"history_visibility_desc": "Изменения видимости истории применяются только к новым сообщениям и не затрагивают существующую историю.",
|
||||||
|
"visibility_after_invite": "После приглашения",
|
||||||
|
"visibility_after_join": "После вступления",
|
||||||
|
"visibility_all_messages": "Все сообщения",
|
||||||
|
"visibility_all_messages_guests": "Все сообщения (гости)",
|
||||||
|
|
||||||
|
"room_encryption": "Шифрование комнаты",
|
||||||
|
"encryption_enabled_desc": "Сообщения в этой комнате защищены сквозным шифрованием.",
|
||||||
|
"encryption_disabled_desc": "После включения шифрование невозможно отключить!",
|
||||||
|
"enabled": "Включено",
|
||||||
|
"enable": "Включить",
|
||||||
|
"enable_encryption": "Включить шифрование",
|
||||||
|
"enable_encryption_confirm": "Вы уверены? После включения шифрование невозможно отключить!",
|
||||||
|
"enable_e2e_encryption": "Включить E2E-шифрование",
|
||||||
|
|
||||||
|
"publish_to_directory": "Показывать в поиске",
|
||||||
|
"publish_space_desc": "Сделать пространство видимым в общем списке, чтобы другие пользователи могли его найти.",
|
||||||
|
"publish_room_desc": "Сделать комнату видимой в общем списке, чтобы другие пользователи могли её найти.",
|
||||||
|
|
||||||
|
"published_addresses": "Опубликованные адреса",
|
||||||
|
"published_addresses_desc": "Если доступ <b>публичный</b>, опубликованные адреса будут использоваться для присоединения.",
|
||||||
|
"no_addresses": "Нет адресов",
|
||||||
|
"no_addresses_hint": "Чтобы опубликовать адрес, его сначала нужно задать как локальный",
|
||||||
|
"main": "Основной",
|
||||||
|
"unset_main": "Снять основной",
|
||||||
|
"set_main": "Сделать основным",
|
||||||
|
"address_in_use": "Адрес уже занят!",
|
||||||
|
"published": "Опубликован",
|
||||||
|
"unpublish": "Снять публикацию",
|
||||||
|
"publish": "Опубликовать",
|
||||||
|
"delete": "Удалить",
|
||||||
|
"selected_count": "Выбрано: {{count}}",
|
||||||
|
|
||||||
|
"local_addresses": "Локальные адреса",
|
||||||
|
"local_addresses_desc": "Задайте локальный адрес, чтобы пользователи могли присоединиться через ваш сервер.",
|
||||||
|
"collapse": "Свернуть",
|
||||||
|
"expand": "Развернуть",
|
||||||
|
"loading": "Загрузка...",
|
||||||
|
|
||||||
|
"space_upgrade": "Обновление пространства",
|
||||||
|
"room_upgrade": "Обновление комнаты",
|
||||||
|
"upgrade": "Обновить",
|
||||||
|
"action_irreversible": "Это действие необратимо!",
|
||||||
|
"upgrade_space": "Обновить пространство",
|
||||||
|
"upgrade_room": "Обновить комнату",
|
||||||
|
"space_replaced": "Это пространство было заменено!",
|
||||||
|
"room_replaced": "Эта комната была заменена!",
|
||||||
|
"current_version": "Текущая версия: {{version}}.",
|
||||||
|
"old_space": "Старое пространство",
|
||||||
|
"old_room": "Старая комната",
|
||||||
|
"open_new_space": "Открыть новое пространство",
|
||||||
|
"open_new_room": "Открыть новую комнату",
|
||||||
|
|
||||||
|
"members_count": "{{count}} участников",
|
||||||
|
"search": "Поиск",
|
||||||
|
"no_results": "Ничего не найдено",
|
||||||
|
"results_count": "{{count}} результатов",
|
||||||
|
"scroll_to_top": "Наверх",
|
||||||
|
"no_membership_members": "Нет участников «{{filter}}»",
|
||||||
|
|
||||||
|
"filter_joined": "Вступившие",
|
||||||
|
"filter_invited": "Приглашённые",
|
||||||
|
"filter_left": "Вышедшие",
|
||||||
|
"filter_kicked": "Исключённые",
|
||||||
|
"filter_banned": "Забаненные",
|
||||||
|
|
||||||
|
"sort_a_to_z": "А — Я",
|
||||||
|
"sort_z_to_a": "Я — А",
|
||||||
|
"sort_newest": "Новые",
|
||||||
|
"sort_oldest": "Старые",
|
||||||
|
|
||||||
|
"perm_messages": "Сообщения",
|
||||||
|
"perm_send_messages": "Отправка сообщений",
|
||||||
|
"perm_send_stickers": "Отправка стикеров",
|
||||||
|
"perm_send_reactions": "Отправка реакций",
|
||||||
|
"perm_ping_room": "Упоминание @room",
|
||||||
|
"perm_pin_messages": "Закрепление сообщений",
|
||||||
|
"perm_other_message_events": "Прочие события сообщений",
|
||||||
|
"perm_calls": "Звонки",
|
||||||
|
"perm_join_call": "Присоединиться к звонку",
|
||||||
|
"perm_moderation": "Модерация",
|
||||||
|
"perm_invite": "Приглашение",
|
||||||
|
"perm_kick": "Исключение",
|
||||||
|
"perm_ban": "Бан",
|
||||||
|
"perm_delete_others_messages": "Удаление чужих сообщений",
|
||||||
|
"perm_delete_self_messages": "Удаление своих сообщений",
|
||||||
|
"perm_room_overview": "Обзор комнаты",
|
||||||
|
"perm_room_avatar": "Аватар комнаты",
|
||||||
|
"perm_room_name": "Название комнаты",
|
||||||
|
"perm_room_topic": "Тема комнаты",
|
||||||
|
"perm_settings": "Настройки",
|
||||||
|
"perm_change_room_access": "Изменение доступа к комнате",
|
||||||
|
"perm_publish_address": "Публикация адреса",
|
||||||
|
"perm_change_all_permission": "Изменение всех прав",
|
||||||
|
"perm_edit_power_levels": "Редактирование уровней власти",
|
||||||
|
"perm_enable_encryption": "Включение шифрования",
|
||||||
|
"perm_history_visibility": "Видимость истории",
|
||||||
|
"perm_upgrade_room": "Обновление комнаты",
|
||||||
|
"perm_other_settings": "Прочие настройки",
|
||||||
|
"perm_other": "Прочее",
|
||||||
|
"perm_manage_emojis_stickers": "Управление эмодзи и стикерами",
|
||||||
|
"perm_change_server_acls": "Изменение ACL серверов",
|
||||||
|
"perm_modify_widgets": "Изменение виджетов",
|
||||||
|
|
||||||
|
"founders": "Основатели",
|
||||||
|
"founders_desc": "Основатели имеют все права. Изменить их состав можно только при обновлении комнаты.",
|
||||||
|
"power_levels": "Уровни власти",
|
||||||
|
"power_levels_desc": "Управление и настройка уровней власти для пользователей.",
|
||||||
|
|
||||||
|
"new_power_level": "Новый уровень власти",
|
||||||
|
"power_level_placeholder": "Бот",
|
||||||
|
"new_power_level_desc": "Создать новый уровень власти.",
|
||||||
|
"create": "Создать",
|
||||||
|
"color": "Цвет",
|
||||||
|
"pick": "Выбрать",
|
||||||
|
"power": "Уровень",
|
||||||
|
"icon": "Иконка",
|
||||||
|
"import": "Импорт",
|
||||||
|
"undo": "Отменить",
|
||||||
|
"used_power_level": "Используемый уровень власти",
|
||||||
|
"used_power_level_desc": "Необходимо убрать его использование, прежде чем удалить.",
|
||||||
|
"changes_saved": "Изменения сохранены! Примените, когда будете готовы.",
|
||||||
|
"failed_to_apply": "Не удалось применить изменения! Попробуйте ещё раз.",
|
||||||
|
"apply_changes": "Применить изменения",
|
||||||
|
"and_above": "и выше",
|
||||||
|
|
||||||
|
"users": "Пользователи",
|
||||||
|
"default_power": "Уровень по умолчанию",
|
||||||
|
"default_power_desc": "Уровень власти по умолчанию для всех пользователей.",
|
||||||
|
|
||||||
|
"packs": "Паки",
|
||||||
|
"new_pack": "Новый пак",
|
||||||
|
"new_pack_desc": "Добавьте свой пак эмодзи и стикеров для использования в комнате.",
|
||||||
|
"no_packs": "Нет паков",
|
||||||
|
"no_packs_desc": "На данный момент нет паков эмодзи или стикеров для отображения.",
|
||||||
|
"view": "Открыть",
|
||||||
|
"failed_to_remove_packs": "Не удалось удалить паки! Попробуйте ещё раз.",
|
||||||
|
"delete_selected_packs": "Удалить выбранные паки. (Выбрано: {{count}})",
|
||||||
|
|
||||||
|
"enable_developer_tools": "Включить инструменты разработчика",
|
||||||
|
"room_id": "ID комнаты",
|
||||||
|
"room_id_desc": "Скопировать ID комнаты в буфер обмена.",
|
||||||
|
"copy": "Копировать",
|
||||||
|
"data": "Данные",
|
||||||
|
"new_message_event": "Новое событие сообщения",
|
||||||
|
"new_message_event_desc": "Создать и отправить новое событие сообщения в комнату.",
|
||||||
|
"compose": "Создать",
|
||||||
|
"room_state": "Состояние комнаты",
|
||||||
|
"room_state_desc": "State-события комнаты.",
|
||||||
|
"events": "События",
|
||||||
|
"total": "Всего: {{count}}",
|
||||||
|
"add_new": "Добавить",
|
||||||
|
"default_key": "По умолчанию",
|
||||||
|
"account_data": "Данные аккаунта",
|
||||||
|
"account_data_desc": "Персональные данные, хранящиеся в комнате.",
|
||||||
|
"state_event": "State-событие",
|
||||||
|
"json_content": "JSON-содержимое",
|
||||||
|
"state_event_type": "Тип state-события",
|
||||||
|
"message_event_type": "Тип события сообщения",
|
||||||
|
"send": "Отправить",
|
||||||
|
"state_key_optional": "State Key (необязательно)",
|
||||||
|
|
||||||
|
"pack": "Пак",
|
||||||
|
"images_usage": "Использование изображений",
|
||||||
|
"images_usage_desc": "Выберите, как используются изображения: как эмодзи, как стикеры или как и то, и другое.",
|
||||||
|
"images": "Изображения",
|
||||||
|
"upload_images": "Загрузить изображения",
|
||||||
|
"upload_images_desc": "Выберите изображения из хранилища для загрузки в пак.",
|
||||||
|
"select": "Выбрать",
|
||||||
|
"pack_avatar": "Аватар пака",
|
||||||
|
"attribution": "Авторство",
|
||||||
|
"shortcode": "Шорткод:",
|
||||||
|
"body": "Описание:",
|
||||||
|
"usage_both": "Оба",
|
||||||
|
"usage_sticker": "Стикер",
|
||||||
|
"usage_emoji": "Эмодзи",
|
||||||
|
|
||||||
|
"power_goku": "Гоку",
|
||||||
|
"power_manager": "Менеджер",
|
||||||
|
"power_founder": "Основатель",
|
||||||
|
"power_admin": "Админ",
|
||||||
|
"power_moderator": "Модератор",
|
||||||
|
"power_member": "Участник",
|
||||||
|
"power_muted": "Без голоса",
|
||||||
|
"power_team": "Команда"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import {
|
||||||
Scroll,
|
Scroll,
|
||||||
config,
|
config,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MatrixError } from 'matrix-js-sdk';
|
import { MatrixError } from 'matrix-js-sdk';
|
||||||
import { Cursor } from '../plugins/text-area';
|
import { Cursor } from '../plugins/text-area';
|
||||||
import { syntaxErrorPosition } from '../utils/dom';
|
import { syntaxErrorPosition } from '../utils/dom';
|
||||||
|
|
@ -47,6 +48,7 @@ function AccountDataEdit({
|
||||||
onCancel,
|
onCancel,
|
||||||
onSave,
|
onSave,
|
||||||
}: AccountDataEditProps) {
|
}: AccountDataEditProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const alive = useAlive();
|
const alive = useAlive();
|
||||||
|
|
||||||
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
|
@ -121,7 +123,7 @@ function AccountDataEdit({
|
||||||
aria-disabled={submitting}
|
aria-disabled={submitting}
|
||||||
>
|
>
|
||||||
<Box shrink="No" direction="Column" gap="100">
|
<Box shrink="No" direction="Column" gap="100">
|
||||||
<Text size="L400">Account Data</Text>
|
<Text size="L400">{t('RoomSettings.account_data')}</Text>
|
||||||
<Box gap="300">
|
<Box gap="300">
|
||||||
<Box grow="Yes" direction="Column">
|
<Box grow="Yes" direction="Column">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -142,7 +144,7 @@ function AccountDataEdit({
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
before={submitting && <Spinner variant="Primary" fill="Solid" size="300" />}
|
before={submitting && <Spinner variant="Primary" fill="Solid" size="300" />}
|
||||||
>
|
>
|
||||||
<Text size="B400">Save</Text>
|
<Text size="B400">{t('RoomSettings.save')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="Secondary"
|
variant="Secondary"
|
||||||
|
|
@ -153,7 +155,7 @@ function AccountDataEdit({
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
>
|
>
|
||||||
<Text size="B400">Cancel</Text>
|
<Text size="B400">{t('RoomSettings.cancel')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
@ -165,7 +167,7 @@ function AccountDataEdit({
|
||||||
</Box>
|
</Box>
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
<Text size="L400">JSON Content</Text>
|
<Text size="L400">{t('RoomSettings.json_content')}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<TextAreaComponent
|
<TextAreaComponent
|
||||||
ref={textAreaRef}
|
ref={textAreaRef}
|
||||||
|
|
@ -198,6 +200,7 @@ type AccountDataViewProps = {
|
||||||
onEdit: () => void;
|
onEdit: () => void;
|
||||||
};
|
};
|
||||||
function AccountDataView({ type, defaultContent, onEdit }: AccountDataViewProps) {
|
function AccountDataView({ type, defaultContent, onEdit }: AccountDataViewProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
direction="Column"
|
direction="Column"
|
||||||
|
|
@ -208,7 +211,7 @@ function AccountDataView({ type, defaultContent, onEdit }: AccountDataViewProps)
|
||||||
>
|
>
|
||||||
<Box shrink="No" gap="300" alignItems="End">
|
<Box shrink="No" gap="300" alignItems="End">
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Text size="L400">Account Data</Text>
|
<Text size="L400">{t('RoomSettings.account_data')}</Text>
|
||||||
<Input
|
<Input
|
||||||
variant="SurfaceVariant"
|
variant="SurfaceVariant"
|
||||||
size="400"
|
size="400"
|
||||||
|
|
@ -219,11 +222,11 @@ function AccountDataView({ type, defaultContent, onEdit }: AccountDataViewProps)
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Button variant="Secondary" size="400" radii="300" onClick={onEdit}>
|
<Button variant="Secondary" size="400" radii="300" onClick={onEdit}>
|
||||||
<Text size="B400">Edit</Text>
|
<Text size="B400">{t('RoomSettings.edit')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Text size="L400">JSON Content</Text>
|
<Text size="L400">{t('RoomSettings.json_content')}</Text>
|
||||||
<SequenceCard variant="SurfaceVariant">
|
<SequenceCard variant="SurfaceVariant">
|
||||||
<Scroll visibility="Always" size="300" hideTrack>
|
<Scroll visibility="Always" size="300" hideTrack>
|
||||||
<TextViewerContent
|
<TextViewerContent
|
||||||
|
|
@ -254,6 +257,7 @@ export function AccountDataEditor({
|
||||||
submitChange,
|
submitChange,
|
||||||
requestClose,
|
requestClose,
|
||||||
}: AccountDataEditorProps) {
|
}: AccountDataEditorProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [data, setData] = useState<AccountDataInfo>({
|
const [data, setData] = useState<AccountDataInfo>({
|
||||||
type: type ?? '',
|
type: type ?? '',
|
||||||
content: content ?? {},
|
content: content ?? {},
|
||||||
|
|
@ -290,7 +294,7 @@ export function AccountDataEditor({
|
||||||
onClick={requestClose}
|
onClick={requestClose}
|
||||||
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
||||||
>
|
>
|
||||||
<Text size="T300">Developer Tools</Text>
|
<Text size="T300">{t('RoomSettings.developer_tools')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import { JoinRule } from 'matrix-js-sdk';
|
import { JoinRule } from 'matrix-js-sdk';
|
||||||
import FocusTrap from 'focus-trap-react';
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { stopPropagation } from '../utils/keyboard';
|
import { stopPropagation } from '../utils/keyboard';
|
||||||
import { getRoomIconSrc } from '../utils/room';
|
import { getRoomIconSrc } from '../utils/room';
|
||||||
|
|
||||||
|
|
@ -37,18 +38,20 @@ export const useJoinRuleIcons = (roomType?: string): JoinRuleIcons =>
|
||||||
);
|
);
|
||||||
|
|
||||||
type JoinRuleLabels = Record<ExtendedJoinRules, string>;
|
type JoinRuleLabels = Record<ExtendedJoinRules, string>;
|
||||||
export const useRoomJoinRuleLabel = (): JoinRuleLabels =>
|
export const useRoomJoinRuleLabel = (): JoinRuleLabels => {
|
||||||
useMemo(
|
const { t } = useTranslation();
|
||||||
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
[JoinRule.Invite]: 'Invite Only',
|
[JoinRule.Invite]: t('RoomSettings.join_invite_only'),
|
||||||
[JoinRule.Knock]: 'Knock & Invite',
|
[JoinRule.Knock]: t('RoomSettings.join_knock_invite'),
|
||||||
knock_restricted: 'Space Members or Knock',
|
knock_restricted: t('RoomSettings.join_space_members_or_knock'),
|
||||||
[JoinRule.Restricted]: 'Space Members',
|
[JoinRule.Restricted]: t('RoomSettings.join_space_members'),
|
||||||
[JoinRule.Public]: 'Public',
|
[JoinRule.Public]: t('RoomSettings.join_public'),
|
||||||
[JoinRule.Private]: 'Invite Only',
|
[JoinRule.Private]: t('RoomSettings.join_invite_only'),
|
||||||
}),
|
}),
|
||||||
[]
|
[t]
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
type JoinRulesSwitcherProps<T extends ExtendedJoinRules[]> = {
|
type JoinRulesSwitcherProps<T extends ExtendedJoinRules[]> = {
|
||||||
icons: JoinRuleIcons;
|
icons: JoinRuleIcons;
|
||||||
|
|
@ -68,6 +71,7 @@ export function JoinRulesSwitcher<T extends ExtendedJoinRules[]>({
|
||||||
disabled,
|
disabled,
|
||||||
changing,
|
changing,
|
||||||
}: JoinRulesSwitcherProps<T>) {
|
}: JoinRulesSwitcherProps<T>) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [cords, setCords] = useState<RectCords>();
|
const [cords, setCords] = useState<RectCords>();
|
||||||
|
|
||||||
const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||||
|
|
@ -138,7 +142,7 @@ export function JoinRulesSwitcher<T extends ExtendedJoinRules[]>({
|
||||||
onClick={handleOpenMenu}
|
onClick={handleOpenMenu}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<Text size="B300">{labels[value] ?? 'Unsupported'}</Text>
|
<Text size="B300">{labels[value] ?? t('RoomSettings.join_unsupported')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</PopOut>
|
</PopOut>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { as, Box, Text, config, Button, Menu, Spinner } from 'folds';
|
import { as, Box, Text, config, Button, Menu, Spinner } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
ImagePack,
|
ImagePack,
|
||||||
ImageUsage,
|
ImageUsage,
|
||||||
|
|
@ -33,6 +34,7 @@ export type ImagePackContentProps = {
|
||||||
|
|
||||||
export const ImagePackContent = as<'div', ImagePackContentProps>(
|
export const ImagePackContent = as<'div', ImagePackContentProps>(
|
||||||
({ imagePack, canEdit, onUpdate, ...props }, ref) => {
|
({ imagePack, canEdit, onUpdate, ...props }, ref) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
|
|
||||||
const [metaEditing, setMetaEditing] = useState(false);
|
const [metaEditing, setMetaEditing] = useState(false);
|
||||||
|
|
@ -256,11 +258,11 @@ export const ImagePackContent = as<'div', ImagePackContentProps>(
|
||||||
<Box grow="Yes" direction="Column">
|
<Box grow="Yes" direction="Column">
|
||||||
{applyState.status === AsyncStatus.Error ? (
|
{applyState.status === AsyncStatus.Error ? (
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
<b>Failed to apply changes! Please try again.</b>
|
<b>{t('RoomSettings.failed_to_apply')}</b>
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
<b>Changes saved! Apply when ready.</b>
|
<b>{t('RoomSettings.changes_saved')}</b>
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -273,7 +275,7 @@ export const ImagePackContent = as<'div', ImagePackContentProps>(
|
||||||
disabled={!canApplyChanges || applying}
|
disabled={!canApplyChanges || applying}
|
||||||
onClick={handleResetSavedChanges}
|
onClick={handleResetSavedChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Reset</Text>
|
<Text size="B300">{t('RoomSettings.reset')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="300"
|
size="300"
|
||||||
|
|
@ -283,14 +285,14 @@ export const ImagePackContent = as<'div', ImagePackContentProps>(
|
||||||
before={applying && <Spinner variant="Success" fill="Solid" size="100" />}
|
before={applying && <Spinner variant="Success" fill="Solid" size="100" />}
|
||||||
onClick={applyChanges}
|
onClick={applyChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Apply Changes</Text>
|
<Text size="B300">{t('RoomSettings.apply_changes')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Menu>
|
</Menu>
|
||||||
)}
|
)}
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Pack</Text>
|
<Text size="L400">{t('RoomSettings.pack')}</Text>
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
style={{ padding: config.space.S300 }}
|
style={{ padding: config.space.S300 }}
|
||||||
variant="SurfaceVariant"
|
variant="SurfaceVariant"
|
||||||
|
|
@ -318,8 +320,8 @@ export const ImagePackContent = as<'div', ImagePackContentProps>(
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Images Usage"
|
title={t('RoomSettings.images_usage')}
|
||||||
description="Select how the images are being used: as emojis, as stickers, or as both."
|
description={t('RoomSettings.images_usage_desc')}
|
||||||
after={
|
after={
|
||||||
<UsageSwitcher
|
<UsageSwitcher
|
||||||
usage={currentMeta.usage}
|
usage={currentMeta.usage}
|
||||||
|
|
@ -332,7 +334,7 @@ export const ImagePackContent = as<'div', ImagePackContentProps>(
|
||||||
</Box>
|
</Box>
|
||||||
{images.length === 0 && !canEdit ? null : (
|
{images.length === 0 && !canEdit ? null : (
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Images</Text>
|
<Text size="L400">{t('RoomSettings.images')}</Text>
|
||||||
{canEdit && (
|
{canEdit && (
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
style={{ padding: config.space.S300 }}
|
style={{ padding: config.space.S300 }}
|
||||||
|
|
@ -341,8 +343,8 @@ export const ImagePackContent = as<'div', ImagePackContentProps>(
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Upload Images"
|
title={t('RoomSettings.upload_images')}
|
||||||
description="Select images from your storage to upload them in pack."
|
description={t('RoomSettings.upload_images_desc')}
|
||||||
after={
|
after={
|
||||||
<Button
|
<Button
|
||||||
variant="Secondary"
|
variant="Secondary"
|
||||||
|
|
@ -353,7 +355,7 @@ export const ImagePackContent = as<'div', ImagePackContentProps>(
|
||||||
outlined
|
outlined
|
||||||
onClick={() => pickFiles('image/*')}
|
onClick={() => pickFiles('image/*')}
|
||||||
>
|
>
|
||||||
<Text size="B300">Select</Text>
|
<Text size="B300">{t('RoomSettings.select')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, IconButton, Text, Icon, Icons, Scroll, Chip } from 'folds';
|
import { Box, IconButton, Text, Icon, Icons, Scroll, Chip } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PackAddress } from '../../plugins/custom-emoji';
|
import { PackAddress } from '../../plugins/custom-emoji';
|
||||||
import { Page, PageHeader, PageContent } from '../page';
|
import { Page, PageHeader, PageContent } from '../page';
|
||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||||
|
|
@ -11,6 +12,7 @@ type ImagePackViewProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function ImagePackView({ address, requestClose }: ImagePackViewProps) {
|
export function ImagePackView({ address, requestClose }: ImagePackViewProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = address && mx.getRoom(address.roomId);
|
const room = address && mx.getRoom(address.roomId);
|
||||||
|
|
||||||
|
|
@ -25,7 +27,7 @@ export function ImagePackView({ address, requestClose }: ImagePackViewProps) {
|
||||||
onClick={requestClose}
|
onClick={requestClose}
|
||||||
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
||||||
>
|
>
|
||||||
<Text size="T300">Emojis & Stickers</Text>
|
<Text size="T300">{t('RoomSettings.emojis_stickers')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { FormEventHandler, ReactNode, useMemo, useState } from 'react';
|
import React, { FormEventHandler, ReactNode, useMemo, useState } from 'react';
|
||||||
import { Badge, Box, Button, Chip, Icon, Icons, Input, Text } from 'folds';
|
import { Badge, Box, Button, Chip, Icon, Icons, Input, Text } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { UsageSwitcher, useUsageStr } from './UsageSwitcher';
|
import { UsageSwitcher, useUsageStr } from './UsageSwitcher';
|
||||||
import { mxcUrlToHttp } from '../../utils/matrix';
|
import { mxcUrlToHttp } from '../../utils/matrix';
|
||||||
import * as css from './style.css';
|
import * as css from './style.css';
|
||||||
|
|
@ -30,6 +31,7 @@ export function ImageTile({
|
||||||
onDeleteToggle,
|
onDeleteToggle,
|
||||||
deleted,
|
deleted,
|
||||||
}: ImageTileProps) {
|
}: ImageTileProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const getUsageStr = useUsageStr();
|
const getUsageStr = useUsageStr();
|
||||||
|
|
||||||
|
|
@ -71,7 +73,7 @@ export function ImageTile({
|
||||||
radii="Pill"
|
radii="Pill"
|
||||||
onClick={() => onDeleteToggle?.(defaultShortcode)}
|
onClick={() => onDeleteToggle?.(defaultShortcode)}
|
||||||
>
|
>
|
||||||
{deleted ? <Text size="B300">Undo</Text> : <Icon size="50" src={Icons.Delete} />}
|
{deleted ? <Text size="B300">{t('RoomSettings.undo')}</Text> : <Icon size="50" src={Icons.Delete} />}
|
||||||
</Chip>
|
</Chip>
|
||||||
{!deleted && (
|
{!deleted && (
|
||||||
<Chip
|
<Chip
|
||||||
|
|
@ -79,7 +81,7 @@ export function ImageTile({
|
||||||
radii="Pill"
|
radii="Pill"
|
||||||
onClick={() => onEdit?.(defaultShortcode, image)}
|
onClick={() => onEdit?.(defaultShortcode, image)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Edit</Text>
|
<Text size="B300">{t('RoomSettings.edit')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -120,6 +122,7 @@ export function ImageTileEdit({
|
||||||
onCancel,
|
onCancel,
|
||||||
onSave,
|
onSave,
|
||||||
}: ImageTileEditProps) {
|
}: ImageTileEditProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const defaultUsage = image.usage ?? packUsage;
|
const defaultUsage = image.usage ?? packUsage;
|
||||||
|
|
||||||
|
|
@ -171,7 +174,7 @@ export function ImageTileEdit({
|
||||||
<Box as="form" onSubmit={handleSubmit} direction="Column" gap="200">
|
<Box as="form" onSubmit={handleSubmit} direction="Column" gap="200">
|
||||||
<Box direction="Column" className={css.ImagePackImageInputs}>
|
<Box direction="Column" className={css.ImagePackImageInputs}>
|
||||||
<Input
|
<Input
|
||||||
before={<Text size="L400">Shortcode:</Text>}
|
before={<Text size="L400">{t('RoomSettings.shortcode')}</Text>}
|
||||||
defaultValue={image.shortcode}
|
defaultValue={image.shortcode}
|
||||||
name="shortcodeInput"
|
name="shortcodeInput"
|
||||||
variant="Secondary"
|
variant="Secondary"
|
||||||
|
|
@ -181,7 +184,7 @@ export function ImageTileEdit({
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
before={<Text size="L400">Body:</Text>}
|
before={<Text size="L400">{t('RoomSettings.body')}</Text>}
|
||||||
defaultValue={image.body}
|
defaultValue={image.body}
|
||||||
name="bodyInput"
|
name="bodyInput"
|
||||||
variant="Secondary"
|
variant="Secondary"
|
||||||
|
|
@ -195,7 +198,7 @@ export function ImageTileEdit({
|
||||||
</Box>
|
</Box>
|
||||||
<Box grow="Yes" />
|
<Box grow="Yes" />
|
||||||
<Button type="submit" variant="Success" size="300" radii="300">
|
<Button type="submit" variant="Success" size="300" radii="300">
|
||||||
<Text size="B300">Save</Text>
|
<Text size="B300">{t('RoomSettings.save')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="reset"
|
type="reset"
|
||||||
|
|
@ -205,7 +208,7 @@ export function ImageTileEdit({
|
||||||
radii="300"
|
radii="300"
|
||||||
onClick={() => onCancel(defaultShortcode)}
|
onClick={() => onCancel(defaultShortcode)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Cancel</Text>
|
<Text size="B300">{t('RoomSettings.cancel')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import {
|
||||||
Chip,
|
Chip,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import Linkify from 'linkify-react';
|
import Linkify from 'linkify-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { mxcUrlToHttp } from '../../utils/matrix';
|
import { mxcUrlToHttp } from '../../utils/matrix';
|
||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||||
import { nameInitials } from '../../utils/common';
|
import { nameInitials } from '../../utils/common';
|
||||||
|
|
@ -31,13 +32,14 @@ type ImagePackAvatarProps = {
|
||||||
name?: string;
|
name?: string;
|
||||||
};
|
};
|
||||||
function ImagePackAvatar({ url, name }: ImagePackAvatarProps) {
|
function ImagePackAvatar({ url, name }: ImagePackAvatarProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Avatar size="500" className={ContainerColor({ variant: 'Secondary' })}>
|
<Avatar size="500" className={ContainerColor({ variant: 'Secondary' })}>
|
||||||
{url ? (
|
{url ? (
|
||||||
<AvatarImage src={url} alt={name ?? 'Unknown'} />
|
<AvatarImage src={url} alt={name ?? t('RoomSettings.unknown')} />
|
||||||
) : (
|
) : (
|
||||||
<AvatarFallback>
|
<AvatarFallback>
|
||||||
<Text size="H2">{nameInitials(name ?? 'Unknown')}</Text>
|
<Text size="H2">{nameInitials(name ?? t('RoomSettings.unknown'))}</Text>
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
)}
|
)}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
|
|
@ -50,6 +52,7 @@ type ImagePackProfileProps = {
|
||||||
onEdit?: () => void;
|
onEdit?: () => void;
|
||||||
};
|
};
|
||||||
export function ImagePackProfile({ meta, canEdit, onEdit }: ImagePackProfileProps) {
|
export function ImagePackProfile({ meta, canEdit, onEdit }: ImagePackProfileProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const avatarUrl = meta.avatar
|
const avatarUrl = meta.avatar
|
||||||
|
|
@ -61,7 +64,7 @@ export function ImagePackProfile({ meta, canEdit, onEdit }: ImagePackProfileProp
|
||||||
<Box grow="Yes" direction="Column" gap="300">
|
<Box grow="Yes" direction="Column" gap="300">
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text className={BreakWord} size="H5">
|
<Text className={BreakWord} size="H5">
|
||||||
{meta.name ?? 'Unknown'}
|
{meta.name ?? t('RoomSettings.unknown')}
|
||||||
</Text>
|
</Text>
|
||||||
{meta.attribution && (
|
{meta.attribution && (
|
||||||
<Text className={BreakWord} size="T200">
|
<Text className={BreakWord} size="T200">
|
||||||
|
|
@ -79,7 +82,7 @@ export function ImagePackProfile({ meta, canEdit, onEdit }: ImagePackProfileProp
|
||||||
onClick={onEdit}
|
onClick={onEdit}
|
||||||
outlined
|
outlined
|
||||||
>
|
>
|
||||||
<Text size="B300">Edit</Text>
|
<Text size="B300">{t('RoomSettings.edit')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
@ -97,6 +100,7 @@ type ImagePackProfileEditProps = {
|
||||||
onSave: (meta: PackMetaReader) => void;
|
onSave: (meta: PackMetaReader) => void;
|
||||||
};
|
};
|
||||||
export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfileEditProps) {
|
export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfileEditProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const [avatar, setAvatar] = useState(meta.avatar);
|
const [avatar, setAvatar] = useState(meta.avatar);
|
||||||
|
|
@ -147,7 +151,7 @@ export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfil
|
||||||
<Box as="form" onSubmit={handleSubmit} direction="Column" gap="400">
|
<Box as="form" onSubmit={handleSubmit} direction="Column" gap="400">
|
||||||
<Box gap="400">
|
<Box gap="400">
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Text size="L400">Pack Avatar</Text>
|
<Text size="L400">{t('RoomSettings.pack_avatar')}</Text>
|
||||||
{uploadAtom ? (
|
{uploadAtom ? (
|
||||||
<Box gap="200" direction="Column">
|
<Box gap="200" direction="Column">
|
||||||
<CompactUploadCardRenderer
|
<CompactUploadCardRenderer
|
||||||
|
|
@ -166,7 +170,7 @@ export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfil
|
||||||
radii="300"
|
radii="300"
|
||||||
onClick={() => pickFile('image/*')}
|
onClick={() => pickFile('image/*')}
|
||||||
>
|
>
|
||||||
<Text size="B300">Upload</Text>
|
<Text size="B300">{t('RoomSettings.upload')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
{!avatar && meta.avatar && (
|
{!avatar && meta.avatar && (
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -177,7 +181,7 @@ export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfil
|
||||||
radii="300"
|
radii="300"
|
||||||
onClick={() => setAvatar(meta.avatar)}
|
onClick={() => setAvatar(meta.avatar)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Reset</Text>
|
<Text size="B300">{t('RoomSettings.reset')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{avatar && (
|
{avatar && (
|
||||||
|
|
@ -189,7 +193,7 @@ export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfil
|
||||||
radii="300"
|
radii="300"
|
||||||
onClick={() => setAvatar(undefined)}
|
onClick={() => setAvatar(undefined)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Remove</Text>
|
<Text size="B300">{t('RoomSettings.remove')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -200,11 +204,11 @@ export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfil
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box direction="Inherit" gap="100">
|
<Box direction="Inherit" gap="100">
|
||||||
<Text size="L400">Name</Text>
|
<Text size="L400">{t('RoomSettings.name')}</Text>
|
||||||
<Input name="nameInput" defaultValue={meta.name} variant="Secondary" radii="300" required />
|
<Input name="nameInput" defaultValue={meta.name} variant="Secondary" radii="300" required />
|
||||||
</Box>
|
</Box>
|
||||||
<Box direction="Inherit" gap="100">
|
<Box direction="Inherit" gap="100">
|
||||||
<Text size="L400">Attribution</Text>
|
<Text size="L400">{t('RoomSettings.attribution')}</Text>
|
||||||
<TextArea
|
<TextArea
|
||||||
name="attributionTextArea"
|
name="attributionTextArea"
|
||||||
defaultValue={meta.attribution}
|
defaultValue={meta.attribution}
|
||||||
|
|
@ -214,7 +218,7 @@ export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfil
|
||||||
</Box>
|
</Box>
|
||||||
<Box gap="300">
|
<Box gap="300">
|
||||||
<Button type="submit" variant="Success" size="300" radii="300" disabled={uploadingAvatar}>
|
<Button type="submit" variant="Success" size="300" radii="300" disabled={uploadingAvatar}>
|
||||||
<Text size="B300">Save</Text>
|
<Text size="B300">{t('RoomSettings.save')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="reset"
|
type="reset"
|
||||||
|
|
@ -224,7 +228,7 @@ export function ImagePackProfileEdit({ meta, onCancel, onSave }: ImagePackProfil
|
||||||
size="300"
|
size="300"
|
||||||
radii="300"
|
radii="300"
|
||||||
>
|
>
|
||||||
<Text size="B300">Cancel</Text>
|
<Text size="B300">{t('RoomSettings.cancel')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
import React, { MouseEventHandler, useMemo, useState } from 'react';
|
import React, { MouseEventHandler, useMemo, useState } from 'react';
|
||||||
import { Box, Button, config, Icon, Icons, Menu, MenuItem, PopOut, RectCords, Text } from 'folds';
|
import { Box, Button, config, Icon, Icons, Menu, MenuItem, PopOut, RectCords, Text } from 'folds';
|
||||||
import FocusTrap from 'focus-trap-react';
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ImageUsage } from '../../plugins/custom-emoji';
|
import { ImageUsage } from '../../plugins/custom-emoji';
|
||||||
import { stopPropagation } from '../../utils/keyboard';
|
import { stopPropagation } from '../../utils/keyboard';
|
||||||
|
|
||||||
export const useUsageStr = (): ((usage: ImageUsage[]) => string) => {
|
export const useUsageStr = (): ((usage: ImageUsage[]) => string) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const getUsageStr = (usage: ImageUsage[]): string => {
|
const getUsageStr = (usage: ImageUsage[]): string => {
|
||||||
const sticker = usage.includes(ImageUsage.Sticker);
|
const sticker = usage.includes(ImageUsage.Sticker);
|
||||||
const emoticon = usage.includes(ImageUsage.Emoticon);
|
const emoticon = usage.includes(ImageUsage.Emoticon);
|
||||||
|
|
||||||
if (sticker && emoticon) return 'Both';
|
if (sticker && emoticon) return t('RoomSettings.usage_both');
|
||||||
if (sticker) return 'Sticker';
|
if (sticker) return t('RoomSettings.usage_sticker');
|
||||||
if (emoticon) return 'Emoji';
|
if (emoticon) return t('RoomSettings.usage_emoji');
|
||||||
return 'Both';
|
return t('RoomSettings.usage_both');
|
||||||
};
|
};
|
||||||
return getUsageStr;
|
return getUsageStr;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import {
|
||||||
config,
|
config,
|
||||||
color,
|
color,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
import { SequenceCardStyle } from '../styles.css';
|
import { SequenceCardStyle } from '../styles.css';
|
||||||
|
|
@ -35,6 +36,7 @@ type DeveloperToolsProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [developerTools, setDeveloperTools] = useSetting(settingsAtom, 'developerTools');
|
const [developerTools, setDeveloperTools] = useSetting(settingsAtom, 'developerTools');
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
@ -88,7 +90,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
<Box grow="Yes" gap="200">
|
<Box grow="Yes" gap="200">
|
||||||
<Box grow="Yes" alignItems="Center" gap="200">
|
<Box grow="Yes" alignItems="Center" gap="200">
|
||||||
<Text size="H3" truncate>
|
<Text size="H3" truncate>
|
||||||
Developer Tools
|
{t('RoomSettings.developer_tools')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
@ -103,7 +105,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<Box direction="Column" gap="700">
|
<Box direction="Column" gap="700">
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Options</Text>
|
<Text size="L400">{t('RoomSettings.options')}</Text>
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
className={SequenceCardStyle}
|
className={SequenceCardStyle}
|
||||||
variant="SurfaceVariant"
|
variant="SurfaceVariant"
|
||||||
|
|
@ -111,7 +113,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Enable Developer Tools"
|
title={t('RoomSettings.enable_developer_tools')}
|
||||||
after={
|
after={
|
||||||
<Switch
|
<Switch
|
||||||
variant="Primary"
|
variant="Primary"
|
||||||
|
|
@ -129,8 +131,8 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Room ID"
|
title={t('RoomSettings.room_id')}
|
||||||
description={`Copy room ID to clipboard. ("${room.roomId}")`}
|
description={`${t('RoomSettings.room_id_desc')} ("${room.roomId}")`}
|
||||||
after={
|
after={
|
||||||
<Button
|
<Button
|
||||||
onClick={() => copyToClipboard(room.roomId ?? '<NO_ROOM_ID_FOUND>')}
|
onClick={() => copyToClipboard(room.roomId ?? '<NO_ROOM_ID_FOUND>')}
|
||||||
|
|
@ -140,7 +142,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
radii="300"
|
radii="300"
|
||||||
outlined
|
outlined
|
||||||
>
|
>
|
||||||
<Text size="B300">Copy</Text>
|
<Text size="B300">{t('RoomSettings.copy')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
@ -150,7 +152,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
|
|
||||||
{developerTools && (
|
{developerTools && (
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Data</Text>
|
<Text size="L400">{t('RoomSettings.data')}</Text>
|
||||||
|
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
className={SequenceCardStyle}
|
className={SequenceCardStyle}
|
||||||
|
|
@ -159,8 +161,8 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="New Message Event"
|
title={t('RoomSettings.new_message_event')}
|
||||||
description="Create and send a new message event within the room."
|
description={t('RoomSettings.new_message_event_desc')}
|
||||||
after={
|
after={
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setComposeEvent({})}
|
onClick={() => setComposeEvent({})}
|
||||||
|
|
@ -170,7 +172,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
radii="300"
|
radii="300"
|
||||||
outlined
|
outlined
|
||||||
>
|
>
|
||||||
<Text size="B300">Compose</Text>
|
<Text size="B300">{t('RoomSettings.compose')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
@ -182,8 +184,8 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Room State"
|
title={t('RoomSettings.room_state')}
|
||||||
description="State events of the room."
|
description={t('RoomSettings.room_state_desc')}
|
||||||
after={
|
after={
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setExpandState(!expandState)}
|
onClick={() => setExpandState(!expandState)}
|
||||||
|
|
@ -200,15 +202,15 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text size="B300">{expandState ? 'Collapse' : 'Expand'}</Text>
|
<Text size="B300">{expandState ? t('RoomSettings.collapse') : t('RoomSettings.expand')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{expandState && (
|
{expandState && (
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Box justifyContent="SpaceBetween">
|
<Box justifyContent="SpaceBetween">
|
||||||
<Text size="L400">Events</Text>
|
<Text size="L400">{t('RoomSettings.events')}</Text>
|
||||||
<Text size="L400">Total: {roomState.size}</Text>
|
<Text size="L400">{t('RoomSettings.total', { count: roomState.size })}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<CutoutCard>
|
<CutoutCard>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|
@ -221,7 +223,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
>
|
>
|
||||||
<Box grow="Yes">
|
<Box grow="Yes">
|
||||||
<Text size="T200" truncate>
|
<Text size="T200" truncate>
|
||||||
Add New
|
{t('RoomSettings.add_new')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
@ -275,7 +277,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
>
|
>
|
||||||
<Box grow="Yes">
|
<Box grow="Yes">
|
||||||
<Text size="T200" truncate>
|
<Text size="T200" truncate>
|
||||||
Add New
|
{t('RoomSettings.add_new')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
@ -298,7 +300,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
>
|
>
|
||||||
<Box grow="Yes">
|
<Box grow="Yes">
|
||||||
<Text size="T200" truncate>
|
<Text size="T200" truncate>
|
||||||
{stateKey ? `"${stateKey}"` : 'Default'}
|
{stateKey ? `"${stateKey}"` : t('RoomSettings.default_key')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
@ -319,8 +321,8 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Account Data"
|
title={t('RoomSettings.account_data')}
|
||||||
description="Private personalization data stored within room."
|
description={t('RoomSettings.account_data_desc')}
|
||||||
after={
|
after={
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setExpandAccountData(!expandAccountData)}
|
onClick={() => setExpandAccountData(!expandAccountData)}
|
||||||
|
|
@ -337,15 +339,15 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text size="B300">{expandAccountData ? 'Collapse' : 'Expand'}</Text>
|
<Text size="B300">{expandAccountData ? t('RoomSettings.collapse') : t('RoomSettings.expand')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{expandAccountData && (
|
{expandAccountData && (
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Box justifyContent="SpaceBetween">
|
<Box justifyContent="SpaceBetween">
|
||||||
<Text size="L400">Events</Text>
|
<Text size="L400">{t('RoomSettings.events')}</Text>
|
||||||
<Text size="L400">Total: {accountData.size}</Text>
|
<Text size="L400">{t('RoomSettings.total', { count: accountData.size })}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<CutoutCard>
|
<CutoutCard>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|
@ -358,7 +360,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||||
>
|
>
|
||||||
<Box grow="Yes">
|
<Box grow="Yes">
|
||||||
<Text size="T200" truncate>
|
<Text size="T200" truncate>
|
||||||
Add New
|
{t('RoomSettings.add_new')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useCallback, useRef, useState, FormEventHandler, useEffect } from 'react';
|
import React, { useCallback, useRef, useState, FormEventHandler, useEffect } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MatrixError } from 'matrix-js-sdk';
|
import { MatrixError } from 'matrix-js-sdk';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
|
@ -31,6 +32,7 @@ export type SendRoomEventProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventProps) {
|
export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const alive = useAlive();
|
const alive = useAlive();
|
||||||
|
|
@ -114,7 +116,7 @@ export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventPro
|
||||||
onClick={requestClose}
|
onClick={requestClose}
|
||||||
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
||||||
>
|
>
|
||||||
<Text size="T300">Developer Tools</Text>
|
<Text size="T300">{t('RoomSettings.developer_tools')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
@ -135,7 +137,7 @@ export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventPro
|
||||||
aria-disabled={submitting}
|
aria-disabled={submitting}
|
||||||
>
|
>
|
||||||
<Box shrink="No" direction="Column" gap="100">
|
<Box shrink="No" direction="Column" gap="100">
|
||||||
<Text size="L400">{composeStateEvent ? 'State Event Type' : 'Message Event Type'}</Text>
|
<Text size="L400">{composeStateEvent ? t('RoomSettings.state_event_type') : t('RoomSettings.message_event_type')}</Text>
|
||||||
<Box gap="300">
|
<Box gap="300">
|
||||||
<Box grow="Yes" direction="Column">
|
<Box grow="Yes" direction="Column">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -156,7 +158,7 @@ export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventPro
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
before={submitting && <Spinner variant="Primary" fill="Solid" size="300" />}
|
before={submitting && <Spinner variant="Primary" fill="Solid" size="300" />}
|
||||||
>
|
>
|
||||||
<Text size="B400">Send</Text>
|
<Text size="B400">{t('RoomSettings.send')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
@ -168,7 +170,7 @@ export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventPro
|
||||||
</Box>
|
</Box>
|
||||||
{composeStateEvent && (
|
{composeStateEvent && (
|
||||||
<Box shrink="No" direction="Column" gap="100">
|
<Box shrink="No" direction="Column" gap="100">
|
||||||
<Text size="L400">State Key (Optional)</Text>
|
<Text size="L400">{t('RoomSettings.state_key_optional')}</Text>
|
||||||
<Input
|
<Input
|
||||||
variant="Background"
|
variant="Background"
|
||||||
name="stateKeyInput"
|
name="stateKeyInput"
|
||||||
|
|
@ -181,7 +183,7 @@ export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventPro
|
||||||
)}
|
)}
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
<Text size="L400">JSON Content</Text>
|
<Text size="L400">{t('RoomSettings.json_content')}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<TextAreaComponent
|
<TextAreaComponent
|
||||||
ref={textAreaRef}
|
ref={textAreaRef}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import {
|
||||||
Spinner,
|
Spinner,
|
||||||
Button,
|
Button,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MatrixError } from 'matrix-js-sdk';
|
import { MatrixError } from 'matrix-js-sdk';
|
||||||
import { Page, PageHeader } from '../../../components/page';
|
import { Page, PageHeader } from '../../../components/page';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
|
|
@ -41,6 +42,7 @@ type StateEventEditProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
function StateEventEdit({ type, stateKey, content, requestClose }: StateEventEditProps) {
|
function StateEventEdit({ type, stateKey, content, requestClose }: StateEventEditProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const alive = useAlive();
|
const alive = useAlive();
|
||||||
|
|
@ -118,7 +120,7 @@ function StateEventEdit({ type, stateKey, content, requestClose }: StateEventEdi
|
||||||
aria-disabled={submitting}
|
aria-disabled={submitting}
|
||||||
>
|
>
|
||||||
<Box shrink="No" direction="Column" gap="100">
|
<Box shrink="No" direction="Column" gap="100">
|
||||||
<Text size="L400">State Event</Text>
|
<Text size="L400">{t('RoomSettings.state_event')}</Text>
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
className={SequenceCardStyle}
|
className={SequenceCardStyle}
|
||||||
variant="SurfaceVariant"
|
variant="SurfaceVariant"
|
||||||
|
|
@ -138,7 +140,7 @@ function StateEventEdit({ type, stateKey, content, requestClose }: StateEventEdi
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
before={submitting && <Spinner variant="Primary" fill="Solid" size="300" />}
|
before={submitting && <Spinner variant="Primary" fill="Solid" size="300" />}
|
||||||
>
|
>
|
||||||
<Text size="B300">Save</Text>
|
<Text size="B300">{t('RoomSettings.save')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="Secondary"
|
variant="Secondary"
|
||||||
|
|
@ -148,7 +150,7 @@ function StateEventEdit({ type, stateKey, content, requestClose }: StateEventEdi
|
||||||
onClick={requestClose}
|
onClick={requestClose}
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
>
|
>
|
||||||
<Text size="B300">Cancel</Text>
|
<Text size="B300">{t('RoomSettings.cancel')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +165,7 @@ function StateEventEdit({ type, stateKey, content, requestClose }: StateEventEdi
|
||||||
</Box>
|
</Box>
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
<Text size="L400">JSON Content</Text>
|
<Text size="L400">{t('RoomSettings.json_content')}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<TextAreaComponent
|
<TextAreaComponent
|
||||||
ref={textAreaRef}
|
ref={textAreaRef}
|
||||||
|
|
@ -194,12 +196,13 @@ type StateEventViewProps = {
|
||||||
onEditContent?: (content: object) => void;
|
onEditContent?: (content: object) => void;
|
||||||
};
|
};
|
||||||
function StateEventView({ content, eventJSONStr, onEditContent }: StateEventViewProps) {
|
function StateEventView({ content, eventJSONStr, onEditContent }: StateEventViewProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Box direction="Column" style={{ padding: config.space.S400 }} gap="400">
|
<Box direction="Column" style={{ padding: config.space.S400 }} gap="400">
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Box gap="200" alignItems="End">
|
<Box gap="200" alignItems="End">
|
||||||
<Box grow="Yes">
|
<Box grow="Yes">
|
||||||
<Text size="L400">State Event</Text>
|
<Text size="L400">{t('RoomSettings.state_event')}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
{onEditContent && (
|
{onEditContent && (
|
||||||
<Box shrink="No" gap="200">
|
<Box shrink="No" gap="200">
|
||||||
|
|
@ -210,7 +213,7 @@ function StateEventView({ content, eventJSONStr, onEditContent }: StateEventView
|
||||||
outlined
|
outlined
|
||||||
onClick={() => onEditContent(content)}
|
onClick={() => onEditContent(content)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Edit</Text>
|
<Text size="B300">{t('RoomSettings.edit')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
@ -241,6 +244,7 @@ export type StateEventEditorProps = StateEventInfo & {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function StateEventEditor({ type, stateKey, requestClose }: StateEventEditorProps) {
|
export function StateEventEditor({ type, stateKey, requestClose }: StateEventEditorProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const stateEvent = useStateEvent(room, type as unknown as StateEvent, stateKey);
|
const stateEvent = useStateEvent(room, type as unknown as StateEvent, stateKey);
|
||||||
|
|
@ -271,7 +275,7 @@ export function StateEventEditor({ type, stateKey, requestClose }: StateEventEdi
|
||||||
onClick={requestClose}
|
onClick={requestClose}
|
||||||
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
||||||
>
|
>
|
||||||
<Text size="T300">Developer Tools</Text>
|
<Text size="T300">{t('RoomSettings.developer_tools')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||||
import { ImagePack } from '../../../plugins/custom-emoji';
|
import { ImagePack } from '../../../plugins/custom-emoji';
|
||||||
import { ImagePackView } from '../../../components/image-pack-view';
|
import { ImagePackView } from '../../../components/image-pack-view';
|
||||||
|
|
@ -9,6 +10,7 @@ type EmojisStickersProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function EmojisStickers({ requestClose }: EmojisStickersProps) {
|
export function EmojisStickers({ requestClose }: EmojisStickersProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [imagePack, setImagePack] = useState<ImagePack>();
|
const [imagePack, setImagePack] = useState<ImagePack>();
|
||||||
|
|
||||||
const handleImagePackViewClose = () => {
|
const handleImagePackViewClose = () => {
|
||||||
|
|
@ -25,7 +27,7 @@ export function EmojisStickers({ requestClose }: EmojisStickersProps) {
|
||||||
<Box grow="Yes" gap="200">
|
<Box grow="Yes" gap="200">
|
||||||
<Box grow="Yes" alignItems="Center" gap="200">
|
<Box grow="Yes" alignItems="Center" gap="200">
|
||||||
<Text size="H3" truncate>
|
<Text size="H3" truncate>
|
||||||
Emojis & Stickers
|
{t('RoomSettings.emojis_stickers')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import {
|
||||||
IconButton,
|
IconButton,
|
||||||
Menu,
|
Menu,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MatrixError } from 'matrix-js-sdk';
|
import { MatrixError } from 'matrix-js-sdk';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
import {
|
import {
|
||||||
|
|
@ -46,6 +47,7 @@ type CreatePackTileProps = {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
};
|
};
|
||||||
function CreatePackTile({ packs, roomId }: CreatePackTileProps) {
|
function CreatePackTile({ packs, roomId }: CreatePackTileProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const alive = useAlive();
|
const alive = useAlive();
|
||||||
|
|
||||||
|
|
@ -97,8 +99,8 @@ function CreatePackTile({ packs, roomId }: CreatePackTileProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="New Pack"
|
title={t('RoomSettings.new_pack')}
|
||||||
description="Add your own emoji and sticker pack to use in room."
|
description={t('RoomSettings.new_pack_desc')}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
style={{ marginTop: config.space.S200 }}
|
style={{ marginTop: config.space.S200 }}
|
||||||
|
|
@ -108,7 +110,7 @@ function CreatePackTile({ packs, roomId }: CreatePackTileProps) {
|
||||||
alignItems="End"
|
alignItems="End"
|
||||||
>
|
>
|
||||||
<Box direction="Column" gap="100" grow="Yes">
|
<Box direction="Column" gap="100" grow="Yes">
|
||||||
<Text size="L400">Name</Text>
|
<Text size="L400">{t('RoomSettings.name')}</Text>
|
||||||
<Input
|
<Input
|
||||||
name="nameInput"
|
name="nameInput"
|
||||||
required
|
required
|
||||||
|
|
@ -130,7 +132,7 @@ function CreatePackTile({ packs, roomId }: CreatePackTileProps) {
|
||||||
disabled={creating}
|
disabled={creating}
|
||||||
before={creating && <Spinner size="200" variant="Success" fill="Solid" />}
|
before={creating && <Spinner size="200" variant="Success" fill="Solid" />}
|
||||||
>
|
>
|
||||||
<Text size="B400">Create</Text>
|
<Text size="B400">{t('RoomSettings.create')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</SettingTile>
|
</SettingTile>
|
||||||
|
|
@ -142,6 +144,7 @@ type RoomPacksProps = {
|
||||||
onViewPack: (imagePack: ImagePack) => void;
|
onViewPack: (imagePack: ImagePack) => void;
|
||||||
};
|
};
|
||||||
export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
@ -255,7 +258,7 @@ export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
||||||
outlined
|
outlined
|
||||||
onClick={() => onViewPack(pack)}
|
onClick={() => onViewPack(pack)}
|
||||||
>
|
>
|
||||||
<Text size="B300">View</Text>
|
<Text size="B300">{t('RoomSettings.view')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -267,7 +270,7 @@ export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Packs</Text>
|
<Text size="L400">{t('RoomSettings.packs')}</Text>
|
||||||
{canEdit && <CreatePackTile roomId={room.roomId} packs={packs} />}
|
{canEdit && <CreatePackTile roomId={room.roomId} packs={packs} />}
|
||||||
{packs.map(renderPack)}
|
{packs.map(renderPack)}
|
||||||
{packs.length === 0 && (
|
{packs.length === 0 && (
|
||||||
|
|
@ -288,10 +291,10 @@ export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text size="H5" align="Center">
|
<Text size="H5" align="Center">
|
||||||
No Packs
|
{t('RoomSettings.no_packs')}
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="T200" align="Center">
|
<Text size="T200" align="Center">
|
||||||
There are no emoji or sticker packs to display at the moment.
|
{t('RoomSettings.no_packs_desc')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</SequenceCard>
|
</SequenceCard>
|
||||||
|
|
@ -315,11 +318,11 @@ export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
||||||
<Box grow="Yes" direction="Column">
|
<Box grow="Yes" direction="Column">
|
||||||
{applyState.status === AsyncStatus.Error ? (
|
{applyState.status === AsyncStatus.Error ? (
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
<b>Failed to remove packs! Please try again.</b>
|
<b>{t('RoomSettings.failed_to_remove_packs')}</b>
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
<b>Delete selected packs. ({removedPacks.length} selected)</b>
|
<b>{t('RoomSettings.delete_selected_packs', { count: removedPacks.length })}</b>
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -332,7 +335,7 @@ export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
||||||
disabled={applyingChanges}
|
disabled={applyingChanges}
|
||||||
onClick={handleCancelChanges}
|
onClick={handleCancelChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Cancel</Text>
|
<Text size="B300">{t('RoomSettings.cancel')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="300"
|
size="300"
|
||||||
|
|
@ -342,7 +345,7 @@ export function RoomPacks({ onViewPack }: RoomPacksProps) {
|
||||||
before={applyingChanges && <Spinner variant="Critical" fill="Solid" size="100" />}
|
before={applyingChanges && <Spinner variant="Critical" fill="Solid" size="100" />}
|
||||||
onClick={handleApplyChanges}
|
onClick={handleApplyChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Delete</Text>
|
<Text size="B300">{t('RoomSettings.delete')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import {
|
||||||
toRem,
|
toRem,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import { MatrixError } from 'matrix-js-sdk';
|
import { MatrixError } from 'matrix-js-sdk';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SettingTile } from '../../../components/setting-tile';
|
import { SettingTile } from '../../../components/setting-tile';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
||||||
|
|
@ -39,6 +40,7 @@ type RoomPublishedAddressesProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function RoomPublishedAddresses({ permissions }: RoomPublishedAddressesProps) {
|
export function RoomPublishedAddresses({ permissions }: RoomPublishedAddressesProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
||||||
|
|
@ -61,19 +63,17 @@ export function RoomPublishedAddresses({ permissions }: RoomPublishedAddressesPr
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Published Addresses"
|
title={t('RoomSettings.published_addresses')}
|
||||||
description={
|
description={
|
||||||
<span>
|
<span dangerouslySetInnerHTML={{ __html: t('RoomSettings.published_addresses_desc') }} />
|
||||||
If access is <b>Public</b>, Published addresses will be used to join by anyone.
|
|
||||||
</span>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<CutoutCard variant="Surface" style={{ padding: config.space.S300 }}>
|
<CutoutCard variant="Surface" style={{ padding: config.space.S300 }}>
|
||||||
{publishedAliases.length === 0 ? (
|
{publishedAliases.length === 0 ? (
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">No Addresses</Text>
|
<Text size="L400">{t('RoomSettings.no_addresses')}</Text>
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
To publish an address, it needs to be set as a local address first
|
{t('RoomSettings.no_addresses_hint')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -86,7 +86,7 @@ export function RoomPublishedAddresses({ permissions }: RoomPublishedAddressesPr
|
||||||
</Text>
|
</Text>
|
||||||
{alias === canonicalAlias && (
|
{alias === canonicalAlias && (
|
||||||
<Badge variant="Success" fill="Solid" size="500">
|
<Badge variant="Success" fill="Solid" size="500">
|
||||||
<Text size="L400">Main</Text>
|
<Text size="L400">{t('RoomSettings.main')}</Text>
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -100,7 +100,7 @@ export function RoomPublishedAddresses({ permissions }: RoomPublishedAddressesPr
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={() => setMain(undefined)}
|
onClick={() => setMain(undefined)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Unset Main</Text>
|
<Text size="B300">{t('RoomSettings.unset_main')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
) : (
|
) : (
|
||||||
<Chip
|
<Chip
|
||||||
|
|
@ -110,7 +110,7 @@ export function RoomPublishedAddresses({ permissions }: RoomPublishedAddressesPr
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={() => setMain(alias)}
|
onClick={() => setMain(alias)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Set Main</Text>
|
<Text size="B300">{t('RoomSettings.set_main')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -131,6 +131,7 @@ export function RoomPublishedAddresses({ permissions }: RoomPublishedAddressesPr
|
||||||
}
|
}
|
||||||
|
|
||||||
function LocalAddressInput({ addLocalAlias }: { addLocalAlias: (alias: string) => Promise<void> }) {
|
function LocalAddressInput({ addLocalAlias }: { addLocalAlias: (alias: string) => Promise<void> }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const userId = mx.getSafeUserId();
|
const userId = mx.getSafeUserId();
|
||||||
const server = getMxIdServer(userId);
|
const server = getMxIdServer(userId);
|
||||||
|
|
@ -183,14 +184,14 @@ function LocalAddressInput({ addLocalAlias }: { addLocalAlias: (alias: string) =
|
||||||
disabled={adding}
|
disabled={adding}
|
||||||
before={adding && <Spinner size="100" variant="Success" fill="Solid" />}
|
before={adding && <Spinner size="100" variant="Success" fill="Solid" />}
|
||||||
>
|
>
|
||||||
<Text size="B400">Save</Text>
|
<Text size="B400">{t('RoomSettings.save')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{addState.status === AsyncStatus.Error && (
|
{addState.status === AsyncStatus.Error && (
|
||||||
<Text style={{ color: color.Critical.Main }} size="T200">
|
<Text style={{ color: color.Critical.Main }} size="T200">
|
||||||
{(addState.error as MatrixError).httpStatus === 409
|
{(addState.error as MatrixError).httpStatus === 409
|
||||||
? 'Address is already in use!'
|
? t('RoomSettings.address_in_use')
|
||||||
: (addState.error as MatrixError).message}
|
: (addState.error as MatrixError).message}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
@ -207,6 +208,7 @@ function LocalAddressesList({
|
||||||
removeLocalAlias: (alias: string) => Promise<void>;
|
removeLocalAlias: (alias: string) => Promise<void>;
|
||||||
canEditCanonical?: boolean;
|
canEditCanonical?: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const alive = useAlive();
|
const alive = useAlive();
|
||||||
|
|
||||||
|
|
@ -271,7 +273,7 @@ function LocalAddressesList({
|
||||||
{selectedAliases.length > 0 && (
|
{selectedAliases.length > 0 && (
|
||||||
<Box gap="200">
|
<Box gap="200">
|
||||||
<Box grow="Yes">
|
<Box grow="Yes">
|
||||||
<Text size="L400">{selectedAliases.length} Selected</Text>
|
<Text size="L400">{t('RoomSettings.selected_count', { count: selectedAliases.length })}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No" gap="Inherit">
|
<Box shrink="No" gap="Inherit">
|
||||||
{canEditCanonical &&
|
{canEditCanonical &&
|
||||||
|
|
@ -287,7 +289,7 @@ function LocalAddressesList({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text size="B300">Unpublish</Text>
|
<Text size="B300">{t('RoomSettings.unpublish')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
) : (
|
) : (
|
||||||
<Chip
|
<Chip
|
||||||
|
|
@ -301,7 +303,7 @@ function LocalAddressesList({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text size="B300">Publish</Text>
|
<Text size="B300">{t('RoomSettings.publish')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
))}
|
))}
|
||||||
<Chip
|
<Chip
|
||||||
|
|
@ -315,7 +317,7 @@ function LocalAddressesList({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text size="B300">Delete</Text>
|
<Text size="B300">{t('RoomSettings.delete')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -343,7 +345,7 @@ function LocalAddressesList({
|
||||||
<Box shrink="No" gap="100">
|
<Box shrink="No" gap="100">
|
||||||
{published && (
|
{published && (
|
||||||
<Badge variant="Success" fill="Soft" size="500">
|
<Badge variant="Success" fill="Soft" size="500">
|
||||||
<Text size="L400">Published</Text>
|
<Text size="L400">{t('RoomSettings.published')}</Text>
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -360,6 +362,7 @@ function LocalAddressesList({
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RoomLocalAddresses({ permissions }: { permissions: RoomPermissionsAPI }) {
|
export function RoomLocalAddresses({ permissions }: { permissions: RoomPermissionsAPI }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
||||||
|
|
@ -380,8 +383,8 @@ export function RoomLocalAddresses({ permissions }: { permissions: RoomPermissio
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Local Addresses"
|
title={t('RoomSettings.local_addresses')}
|
||||||
description="Set local address so users can join through your homeserver."
|
description={t('RoomSettings.local_addresses_desc')}
|
||||||
after={
|
after={
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -396,7 +399,7 @@ export function RoomLocalAddresses({ permissions }: { permissions: RoomPermissio
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text as="span" size="B300" truncate>
|
<Text as="span" size="B300" truncate>
|
||||||
{expand ? 'Collapse' : 'Expand'}
|
{expand ? t('RoomSettings.collapse') : t('RoomSettings.expand')}
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
|
@ -406,13 +409,13 @@ export function RoomLocalAddresses({ permissions }: { permissions: RoomPermissio
|
||||||
{localAliasesState.status === AsyncStatus.Loading && (
|
{localAliasesState.status === AsyncStatus.Loading && (
|
||||||
<Box gap="100">
|
<Box gap="100">
|
||||||
<Spinner variant="Secondary" size="100" />
|
<Spinner variant="Secondary" size="100" />
|
||||||
<Text size="T200">Loading...</Text>
|
<Text size="T200">{t('RoomSettings.loading')}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{localAliasesState.status === AsyncStatus.Success &&
|
{localAliasesState.status === AsyncStatus.Success &&
|
||||||
(localAliasesState.data.length === 0 ? (
|
(localAliasesState.data.length === 0 ? (
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">No Addresses</Text>
|
<Text size="L400">{t('RoomSettings.no_addresses')}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<LocalAddressesList
|
<LocalAddressesList
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import {
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { MatrixError } from 'matrix-js-sdk';
|
import { MatrixError } from 'matrix-js-sdk';
|
||||||
import FocusTrap from 'focus-trap-react';
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
||||||
import { SettingTile } from '../../../components/setting-tile';
|
import { SettingTile } from '../../../components/setting-tile';
|
||||||
|
|
@ -35,6 +36,7 @@ type RoomEncryptionProps = {
|
||||||
permissions: RoomPermissionsAPI;
|
permissions: RoomPermissionsAPI;
|
||||||
};
|
};
|
||||||
export function RoomEncryption({ permissions }: RoomEncryptionProps) {
|
export function RoomEncryption({ permissions }: RoomEncryptionProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
||||||
|
|
@ -69,16 +71,16 @@ export function RoomEncryption({ permissions }: RoomEncryptionProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Room Encryption"
|
title={t('RoomSettings.room_encryption')}
|
||||||
description={
|
description={
|
||||||
enabled
|
enabled
|
||||||
? 'Messages in this room are protected by end-to-end encryption.'
|
? t('RoomSettings.encryption_enabled_desc')
|
||||||
: 'Once enabled, encryption cannot be disabled!'
|
: t('RoomSettings.encryption_disabled_desc')
|
||||||
}
|
}
|
||||||
after={
|
after={
|
||||||
enabled ? (
|
enabled ? (
|
||||||
<Badge size="500" variant="Success" fill="Solid" radii="300">
|
<Badge size="500" variant="Success" fill="Solid" radii="300">
|
||||||
<Text size="L400">Enabled</Text>
|
<Text size="L400">{t('RoomSettings.enabled')}</Text>
|
||||||
</Badge>
|
</Badge>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -90,7 +92,7 @@ export function RoomEncryption({ permissions }: RoomEncryptionProps) {
|
||||||
onClick={() => setPrompt(true)}
|
onClick={() => setPrompt(true)}
|
||||||
before={enabling && <Spinner size="100" variant="Primary" fill="Solid" />}
|
before={enabling && <Spinner size="100" variant="Primary" fill="Solid" />}
|
||||||
>
|
>
|
||||||
<Text size="B300">Enable</Text>
|
<Text size="B300">{t('RoomSettings.enable')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +123,7 @@ export function RoomEncryption({ permissions }: RoomEncryptionProps) {
|
||||||
size="500"
|
size="500"
|
||||||
>
|
>
|
||||||
<Box grow="Yes">
|
<Box grow="Yes">
|
||||||
<Text size="H4">Enable Encryption</Text>
|
<Text size="H4">{t('RoomSettings.enable_encryption')}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<IconButton size="300" onClick={() => setPrompt(false)} radii="300">
|
<IconButton size="300" onClick={() => setPrompt(false)} radii="300">
|
||||||
<Icon src={Icons.Cross} />
|
<Icon src={Icons.Cross} />
|
||||||
|
|
@ -129,10 +131,10 @@ export function RoomEncryption({ permissions }: RoomEncryptionProps) {
|
||||||
</Header>
|
</Header>
|
||||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||||
<Text priority="400">
|
<Text priority="400">
|
||||||
Are you sure? Once enabled, encryption cannot be disabled!
|
{t('RoomSettings.enable_encryption_confirm')}
|
||||||
</Text>
|
</Text>
|
||||||
<Button type="submit" variant="Primary" onClick={handleEnable}>
|
<Button type="submit" variant="Primary" onClick={handleEnable}>
|
||||||
<Text size="B400">Enable E2E Encryption</Text>
|
<Text size="B400">{t('RoomSettings.enable_e2e_encryption')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import {
|
||||||
import { HistoryVisibility, MatrixError } from 'matrix-js-sdk';
|
import { HistoryVisibility, MatrixError } from 'matrix-js-sdk';
|
||||||
import { RoomHistoryVisibilityEventContent } from 'matrix-js-sdk/lib/types';
|
import { RoomHistoryVisibilityEventContent } from 'matrix-js-sdk/lib/types';
|
||||||
import FocusTrap from 'focus-trap-react';
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
||||||
import { SettingTile } from '../../../components/setting-tile';
|
import { SettingTile } from '../../../components/setting-tile';
|
||||||
|
|
@ -26,16 +27,18 @@ import { useStateEvent } from '../../../hooks/useStateEvent';
|
||||||
import { stopPropagation } from '../../../utils/keyboard';
|
import { stopPropagation } from '../../../utils/keyboard';
|
||||||
import { RoomPermissionsAPI } from '../../../hooks/useRoomPermissions';
|
import { RoomPermissionsAPI } from '../../../hooks/useRoomPermissions';
|
||||||
|
|
||||||
const useVisibilityStr = () =>
|
const useVisibilityStr = () => {
|
||||||
useMemo(
|
const { t } = useTranslation();
|
||||||
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
[HistoryVisibility.Invited]: 'After Invite',
|
[HistoryVisibility.Invited]: t('RoomSettings.visibility_after_invite'),
|
||||||
[HistoryVisibility.Joined]: 'After Join',
|
[HistoryVisibility.Joined]: t('RoomSettings.visibility_after_join'),
|
||||||
[HistoryVisibility.Shared]: 'All Messages',
|
[HistoryVisibility.Shared]: t('RoomSettings.visibility_all_messages'),
|
||||||
[HistoryVisibility.WorldReadable]: 'All Messages (Guests)',
|
[HistoryVisibility.WorldReadable]: t('RoomSettings.visibility_all_messages_guests'),
|
||||||
}),
|
}),
|
||||||
[]
|
[t]
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const useVisibilityMenu = () =>
|
const useVisibilityMenu = () =>
|
||||||
useMemo(
|
useMemo(
|
||||||
|
|
@ -52,6 +55,7 @@ type RoomHistoryVisibilityProps = {
|
||||||
permissions: RoomPermissionsAPI;
|
permissions: RoomPermissionsAPI;
|
||||||
};
|
};
|
||||||
export function RoomHistoryVisibility({ permissions }: RoomHistoryVisibilityProps) {
|
export function RoomHistoryVisibility({ permissions }: RoomHistoryVisibilityProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
||||||
|
|
@ -96,8 +100,8 @@ export function RoomHistoryVisibility({ permissions }: RoomHistoryVisibilityProp
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Message History Visibility"
|
title={t('RoomSettings.history_visibility')}
|
||||||
description="Changes to history visibility will only apply to future messages. The visibility of existing history will have no effect."
|
description={t('RoomSettings.history_visibility_desc')}
|
||||||
after={
|
after={
|
||||||
<PopOut
|
<PopOut
|
||||||
anchor={menuAnchor}
|
anchor={menuAnchor}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import { color, Text } from 'folds';
|
import { color, Text } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { JoinRule, MatrixError, RestrictedAllowType } from 'matrix-js-sdk';
|
import { JoinRule, MatrixError, RestrictedAllowType } from 'matrix-js-sdk';
|
||||||
import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types';
|
import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
|
|
@ -41,6 +42,7 @@ type RoomJoinRulesProps = {
|
||||||
permissions: RoomPermissionsAPI;
|
permissions: RoomPermissionsAPI;
|
||||||
};
|
};
|
||||||
export function RoomJoinRules({ permissions }: RoomJoinRulesProps) {
|
export function RoomJoinRules({ permissions }: RoomJoinRulesProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const allowKnockRestricted = knockRestrictedSupported(room.getVersion());
|
const allowKnockRestricted = knockRestrictedSupported(room.getVersion());
|
||||||
|
|
@ -127,11 +129,11 @@ export function RoomJoinRules({ permissions }: RoomJoinRulesProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title={room.isSpaceRoom() ? 'Space Access' : 'Room Access'}
|
title={room.isSpaceRoom() ? t('RoomSettings.space_access') : t('RoomSettings.room_access')}
|
||||||
description={
|
description={
|
||||||
room.isSpaceRoom()
|
room.isSpaceRoom()
|
||||||
? 'Change how people can join the space.'
|
? t('RoomSettings.space_access_desc')
|
||||||
: 'Change how people can join the room.'
|
: t('RoomSettings.room_access_desc')
|
||||||
}
|
}
|
||||||
after={
|
after={
|
||||||
<JoinRulesSwitcher
|
<JoinRulesSwitcher
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import {
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import React, { FormEventHandler, useCallback, useMemo, useState } from 'react';
|
import React, { FormEventHandler, useCallback, useMemo, useState } from 'react';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import Linkify from 'linkify-react';
|
import Linkify from 'linkify-react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { JoinRule, MatrixError } from 'matrix-js-sdk';
|
import { JoinRule, MatrixError } from 'matrix-js-sdk';
|
||||||
|
|
@ -59,6 +60,7 @@ export function RoomProfileEdit({
|
||||||
topic,
|
topic,
|
||||||
onClose,
|
onClose,
|
||||||
}: RoomProfileEditProps) {
|
}: RoomProfileEditProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const alive = useAlive();
|
const alive = useAlive();
|
||||||
|
|
@ -140,7 +142,7 @@ export function RoomProfileEdit({
|
||||||
<Box as="form" onSubmit={handleSubmit} direction="Column" gap="400">
|
<Box as="form" onSubmit={handleSubmit} direction="Column" gap="400">
|
||||||
<Box gap="400">
|
<Box gap="400">
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Text size="L400">Avatar</Text>
|
<Text size="L400">{t('RoomSettings.avatar')}</Text>
|
||||||
{uploadAtom ? (
|
{uploadAtom ? (
|
||||||
<Box gap="200" direction="Column">
|
<Box gap="200" direction="Column">
|
||||||
<CompactUploadCardRenderer
|
<CompactUploadCardRenderer
|
||||||
|
|
@ -160,7 +162,7 @@ export function RoomProfileEdit({
|
||||||
disabled={!canEditAvatar || submitting}
|
disabled={!canEditAvatar || submitting}
|
||||||
onClick={() => pickFile('image/*')}
|
onClick={() => pickFile('image/*')}
|
||||||
>
|
>
|
||||||
<Text size="B300">Upload</Text>
|
<Text size="B300">{t('RoomSettings.upload')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
{!roomAvatar && avatar && (
|
{!roomAvatar && avatar && (
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -172,7 +174,7 @@ export function RoomProfileEdit({
|
||||||
disabled={!canEditAvatar || submitting}
|
disabled={!canEditAvatar || submitting}
|
||||||
onClick={() => setRoomAvatar(avatar)}
|
onClick={() => setRoomAvatar(avatar)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Reset</Text>
|
<Text size="B300">{t('RoomSettings.reset')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{roomAvatar && (
|
{roomAvatar && (
|
||||||
|
|
@ -185,7 +187,7 @@ export function RoomProfileEdit({
|
||||||
disabled={!canEditAvatar || submitting}
|
disabled={!canEditAvatar || submitting}
|
||||||
onClick={() => setRoomAvatar(undefined)}
|
onClick={() => setRoomAvatar(undefined)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Remove</Text>
|
<Text size="B300">{t('RoomSettings.remove')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -210,7 +212,7 @@ export function RoomProfileEdit({
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box direction="Inherit" gap="100">
|
<Box direction="Inherit" gap="100">
|
||||||
<Text size="L400">Name</Text>
|
<Text size="L400">{t('RoomSettings.name')}</Text>
|
||||||
<Input
|
<Input
|
||||||
name="nameInput"
|
name="nameInput"
|
||||||
defaultValue={name}
|
defaultValue={name}
|
||||||
|
|
@ -220,7 +222,7 @@ export function RoomProfileEdit({
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box direction="Inherit" gap="100">
|
<Box direction="Inherit" gap="100">
|
||||||
<Text size="L400">Topic</Text>
|
<Text size="L400">{t('RoomSettings.topic')}</Text>
|
||||||
<TextArea
|
<TextArea
|
||||||
name="topicTextArea"
|
name="topicTextArea"
|
||||||
defaultValue={topic}
|
defaultValue={topic}
|
||||||
|
|
@ -243,7 +245,7 @@ export function RoomProfileEdit({
|
||||||
disabled={uploadingAvatar || submitting}
|
disabled={uploadingAvatar || submitting}
|
||||||
before={submitting && <Spinner size="100" variant="Success" fill="Solid" />}
|
before={submitting && <Spinner size="100" variant="Success" fill="Solid" />}
|
||||||
>
|
>
|
||||||
<Text size="B300">Save</Text>
|
<Text size="B300">{t('RoomSettings.save')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="reset"
|
type="reset"
|
||||||
|
|
@ -253,7 +255,7 @@ export function RoomProfileEdit({
|
||||||
size="300"
|
size="300"
|
||||||
radii="300"
|
radii="300"
|
||||||
>
|
>
|
||||||
<Text size="B300">Cancel</Text>
|
<Text size="B300">{t('RoomSettings.cancel')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -264,6 +266,7 @@ type RoomProfileProps = {
|
||||||
permissions: RoomPermissionsAPI;
|
permissions: RoomPermissionsAPI;
|
||||||
};
|
};
|
||||||
export function RoomProfile({ permissions }: RoomProfileProps) {
|
export function RoomProfile({ permissions }: RoomProfileProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
@ -289,7 +292,7 @@ export function RoomProfile({ permissions }: RoomProfileProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Profile</Text>
|
<Text size="L400">{t('RoomSettings.profile')}</Text>
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
className={SequenceCardStyle}
|
className={SequenceCardStyle}
|
||||||
variant="SurfaceVariant"
|
variant="SurfaceVariant"
|
||||||
|
|
@ -311,7 +314,7 @@ export function RoomProfile({ permissions }: RoomProfileProps) {
|
||||||
<Box grow="Yes" direction="Column" gap="300">
|
<Box grow="Yes" direction="Column" gap="300">
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text className={BreakWord} size="H5">
|
<Text className={BreakWord} size="H5">
|
||||||
{name ?? 'Unknown'}
|
{name ?? t('RoomSettings.unknown')}
|
||||||
</Text>
|
</Text>
|
||||||
{topic && (
|
{topic && (
|
||||||
<Text className={classNames(BreakWord, LineClamp3)} size="T200">
|
<Text className={classNames(BreakWord, LineClamp3)} size="T200">
|
||||||
|
|
@ -329,7 +332,7 @@ export function RoomProfile({ permissions }: RoomProfileProps) {
|
||||||
onClick={() => setEdit(true)}
|
onClick={() => setEdit(true)}
|
||||||
outlined
|
outlined
|
||||||
>
|
>
|
||||||
<Text size="B300">Edit</Text>
|
<Text size="B300">{t('RoomSettings.edit')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, color, Spinner, Switch, Text } from 'folds';
|
import { Box, color, Spinner, Switch, Text } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { JoinRule, MatrixError } from 'matrix-js-sdk';
|
import { JoinRule, MatrixError } from 'matrix-js-sdk';
|
||||||
import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types';
|
import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
|
|
@ -18,6 +19,7 @@ type RoomPublishProps = {
|
||||||
permissions: RoomPermissionsAPI;
|
permissions: RoomPermissionsAPI;
|
||||||
};
|
};
|
||||||
export function RoomPublish({ permissions }: RoomPublishProps) {
|
export function RoomPublish({ permissions }: RoomPublishProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
||||||
|
|
@ -46,11 +48,11 @@ export function RoomPublish({ permissions }: RoomPublishProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Publish to Directory"
|
title={t('RoomSettings.publish_to_directory')}
|
||||||
description={
|
description={
|
||||||
room.isSpaceRoom()
|
room.isSpaceRoom()
|
||||||
? 'List the space in the public directory to make it discoverable by others.'
|
? t('RoomSettings.publish_space_desc')
|
||||||
: 'List the room in the public directory to make it discoverable by others.'
|
: t('RoomSettings.publish_room_desc')
|
||||||
}
|
}
|
||||||
after={
|
after={
|
||||||
<Box gap="200" alignItems="Center">
|
<Box gap="200" alignItems="Center">
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import {
|
||||||
Icons,
|
Icons,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import FocusTrap from 'focus-trap-react';
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MatrixError, Method } from 'matrix-js-sdk';
|
import { MatrixError, Method } from 'matrix-js-sdk';
|
||||||
import { RoomTombstoneEventContent } from 'matrix-js-sdk/lib/types';
|
import { RoomTombstoneEventContent } from 'matrix-js-sdk/lib/types';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
|
|
@ -41,6 +42,7 @@ import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||||
import { BreakWord } from '../../../styles/Text.css';
|
import { BreakWord } from '../../../styles/Text.css';
|
||||||
|
|
||||||
function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const alive = useAlive();
|
const alive = useAlive();
|
||||||
|
|
@ -103,7 +105,7 @@ function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
||||||
size="500"
|
size="500"
|
||||||
>
|
>
|
||||||
<Box grow="Yes">
|
<Box grow="Yes">
|
||||||
<Text size="H4">{room.isSpaceRoom() ? 'Space Upgrade' : 'Room Upgrade'}</Text>
|
<Text size="H4">{room.isSpaceRoom() ? t('RoomSettings.space_upgrade') : t('RoomSettings.room_upgrade')}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<IconButton size="300" onClick={requestClose} radii="300">
|
<IconButton size="300" onClick={requestClose} radii="300">
|
||||||
<Icon src={Icons.Cross} />
|
<Icon src={Icons.Cross} />
|
||||||
|
|
@ -111,10 +113,10 @@ function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
||||||
</Header>
|
</Header>
|
||||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||||
<Text priority="400" style={{ color: color.Critical.Main }}>
|
<Text priority="400" style={{ color: color.Critical.Main }}>
|
||||||
<b>This action is irreversible!</b>
|
<b>{t('RoomSettings.action_irreversible')}</b>
|
||||||
</Text>
|
</Text>
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Options</Text>
|
<Text size="L400">{t('RoomSettings.options')}</Text>
|
||||||
<RoomVersionSelector
|
<RoomVersionSelector
|
||||||
versions={roomVersions?.available ? Object.keys(roomVersions.available) : ['1']}
|
versions={roomVersions?.available ? Object.keys(roomVersions.available) : ['1']}
|
||||||
value={selectedRoomVersion}
|
value={selectedRoomVersion}
|
||||||
|
|
@ -148,7 +150,7 @@ function RoomUpgradeDialog({ requestClose }: { requestClose: () => void }) {
|
||||||
disabled={upgrading}
|
disabled={upgrading}
|
||||||
before={upgrading && <Spinner size="200" variant="Secondary" fill="Solid" />}
|
before={upgrading && <Spinner size="200" variant="Secondary" fill="Solid" />}
|
||||||
>
|
>
|
||||||
<Text size="B400">{room.isSpaceRoom() ? 'Upgrade Space' : 'Upgrade Room'}</Text>
|
<Text size="B400">{room.isSpaceRoom() ? t('RoomSettings.upgrade_space') : t('RoomSettings.upgrade_room')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
@ -163,6 +165,7 @@ type RoomUpgradeProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const { navigateRoom, navigateSpace } = useRoomNavigate();
|
const { navigateRoom, navigateSpace } = useRoomNavigate();
|
||||||
|
|
@ -213,12 +216,12 @@ export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title={room.isSpaceRoom() ? 'Upgrade Space' : 'Upgrade Room'}
|
title={room.isSpaceRoom() ? t('RoomSettings.upgrade_space') : t('RoomSettings.upgrade_room')}
|
||||||
description={
|
description={
|
||||||
replacementRoom
|
replacementRoom
|
||||||
? tombstoneContent.body ||
|
? tombstoneContent.body ||
|
||||||
`This ${room.isSpaceRoom() ? 'space' : 'room'} has been replaced!`
|
(room.isSpaceRoom() ? t('RoomSettings.space_replaced') : t('RoomSettings.room_replaced'))
|
||||||
: `Current version: ${roomVersion}.`
|
: t('RoomSettings.current_version', { version: roomVersion })
|
||||||
}
|
}
|
||||||
after={
|
after={
|
||||||
<Box alignItems="Center" gap="200">
|
<Box alignItems="Center" gap="200">
|
||||||
|
|
@ -231,7 +234,7 @@ export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
radii="300"
|
radii="300"
|
||||||
onClick={handleOpenOldRoom}
|
onClick={handleOpenOldRoom}
|
||||||
>
|
>
|
||||||
<Text size="B300">{room.isSpaceRoom() ? 'Old Space' : 'Old Room'}</Text>
|
<Text size="B300">{room.isSpaceRoom() ? t('RoomSettings.old_space') : t('RoomSettings.old_room')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{replacementRoom ? (
|
{replacementRoom ? (
|
||||||
|
|
@ -242,7 +245,7 @@ export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
radii="300"
|
radii="300"
|
||||||
onClick={handleOpenRoom}
|
onClick={handleOpenRoom}
|
||||||
>
|
>
|
||||||
<Text size="B300">{room.isSpaceRoom() ? 'Open New Space' : 'Open New Room'}</Text>
|
<Text size="B300">{room.isSpaceRoom() ? t('RoomSettings.open_new_space') : t('RoomSettings.open_new_room')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -253,7 +256,7 @@ export function RoomUpgrade({ permissions, requestClose }: RoomUpgradeProps) {
|
||||||
disabled={!canUpgrade}
|
disabled={!canUpgrade}
|
||||||
onClick={() => setPrompt(true)}
|
onClick={() => setPrompt(true)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Upgrade</Text>
|
<Text size="B300">{t('RoomSettings.upgrade')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
Text,
|
Text,
|
||||||
toRem,
|
toRem,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||||
import { RoomMember } from 'matrix-js-sdk';
|
import { RoomMember } from 'matrix-js-sdk';
|
||||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||||
|
|
@ -75,6 +76,7 @@ type MembersProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function Members({ requestClose }: MembersProps) {
|
export function Members({ requestClose }: MembersProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
@ -157,7 +159,7 @@ export function Members({ requestClose }: MembersProps) {
|
||||||
<Box grow="Yes" gap="200">
|
<Box grow="Yes" gap="200">
|
||||||
<Box grow="Yes" alignItems="Center" gap="200">
|
<Box grow="Yes" alignItems="Center" gap="200">
|
||||||
<Text size="H3" truncate>
|
<Text size="H3" truncate>
|
||||||
{room.getJoinedMemberCount()} Members
|
{t('RoomSettings.members_count', { count: room.getJoinedMemberCount() })}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
@ -182,7 +184,7 @@ export function Members({ requestClose }: MembersProps) {
|
||||||
before={<Icon size="200" src={Icons.Search} />}
|
before={<Icon size="200" src={Icons.Search} />}
|
||||||
variant="SurfaceVariant"
|
variant="SurfaceVariant"
|
||||||
size="500"
|
size="500"
|
||||||
placeholder="Search"
|
placeholder={t('RoomSettings.search')}
|
||||||
outlined
|
outlined
|
||||||
after={
|
after={
|
||||||
result && (
|
result && (
|
||||||
|
|
@ -197,8 +199,8 @@ export function Members({ requestClose }: MembersProps) {
|
||||||
>
|
>
|
||||||
<Text size="B300">
|
<Text size="B300">
|
||||||
{result.items.length === 0
|
{result.items.length === 0
|
||||||
? 'No Results'
|
? t('RoomSettings.no_results')
|
||||||
: `${result.items.length} Results`}
|
: t('RoomSettings.results_count', { count: result.items.length })}
|
||||||
</Text>
|
</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
)
|
)
|
||||||
|
|
@ -282,7 +284,7 @@ export function Members({ requestClose }: MembersProps) {
|
||||||
radii="Pill"
|
radii="Pill"
|
||||||
outlined
|
outlined
|
||||||
size="300"
|
size="300"
|
||||||
aria-label="Scroll to Top"
|
aria-label={t('RoomSettings.scroll_to_top')}
|
||||||
>
|
>
|
||||||
<Icon src={Icons.ChevronTop} size="300" />
|
<Icon src={Icons.ChevronTop} size="300" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
@ -295,7 +297,7 @@ export function Members({ requestClose }: MembersProps) {
|
||||||
|
|
||||||
{!fetchingMembers && !result && flattenTagMembers.length === 0 && (
|
{!fetchingMembers && !result && flattenTagMembers.length === 0 && (
|
||||||
<Text style={{ padding: config.space.S300 }} align="Center">
|
<Text style={{ padding: config.space.S300 }} align="Center">
|
||||||
{`No "${membershipFilter.name}" Members`}
|
{t('RoomSettings.no_membership_members', { filter: membershipFilter.name })}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/* eslint-disable react/no-array-index-key */
|
/* eslint-disable react/no-array-index-key */
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { Badge, Box, Button, Chip, config, Icon, Icons, Menu, Spinner, Text } from 'folds';
|
import { Badge, Box, Button, Chip, config, Icon, Icons, Menu, Spinner, Text } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
import { SequenceCardStyle } from '../styles.css';
|
import { SequenceCardStyle } from '../styles.css';
|
||||||
|
|
@ -34,6 +35,7 @@ export function PermissionGroups({
|
||||||
permissionGroups,
|
permissionGroups,
|
||||||
canEdit,
|
canEdit,
|
||||||
}: PermissionGroupsProps) {
|
}: PermissionGroupsProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const alive = useAlive();
|
const alive = useAlive();
|
||||||
|
|
@ -114,7 +116,7 @@ export function PermissionGroups({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Users</Text>
|
<Text size="L400">{t('RoomSettings.users')}</Text>
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
variant="SurfaceVariant"
|
variant="SurfaceVariant"
|
||||||
className={SequenceCardStyle}
|
className={SequenceCardStyle}
|
||||||
|
|
@ -122,8 +124,8 @@ export function PermissionGroups({
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Default Power"
|
title={t('RoomSettings.default_power')}
|
||||||
description="Default power level for all users."
|
description={t('RoomSettings.default_power_desc')}
|
||||||
after={
|
after={
|
||||||
<PowerSwitcher
|
<PowerSwitcher
|
||||||
powerLevelTags={powerLevelTags}
|
powerLevelTags={powerLevelTags}
|
||||||
|
|
@ -220,7 +222,7 @@ export function PermissionGroups({
|
||||||
<Text size="B300" truncate>
|
<Text size="B300" truncate>
|
||||||
{tag.name}
|
{tag.name}
|
||||||
</Text>
|
</Text>
|
||||||
{value < maxPower && <Text size="T200">& Above</Text>}
|
{value < maxPower && <Text size="T200">{t('RoomSettings.and_above')}</Text>}
|
||||||
</Chip>
|
</Chip>
|
||||||
)}
|
)}
|
||||||
</PowerSwitcher>
|
</PowerSwitcher>
|
||||||
|
|
@ -249,11 +251,11 @@ export function PermissionGroups({
|
||||||
<Box grow="Yes" direction="Column">
|
<Box grow="Yes" direction="Column">
|
||||||
{applyState.status === AsyncStatus.Error ? (
|
{applyState.status === AsyncStatus.Error ? (
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
<b>Failed to apply changes! Please try again.</b>
|
<b>{t('RoomSettings.failed_to_apply')}</b>
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
<b>Changes saved! Apply when ready.</b>
|
<b>{t('RoomSettings.changes_saved')}</b>
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -266,7 +268,7 @@ export function PermissionGroups({
|
||||||
disabled={applyingChanges}
|
disabled={applyingChanges}
|
||||||
onClick={resetChanges}
|
onClick={resetChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Reset</Text>
|
<Text size="B300">{t('RoomSettings.reset')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="300"
|
size="300"
|
||||||
|
|
@ -276,7 +278,7 @@ export function PermissionGroups({
|
||||||
before={applyingChanges && <Spinner variant="Success" fill="Solid" size="100" />}
|
before={applyingChanges && <Spinner variant="Success" fill="Solid" size="100" />}
|
||||||
onClick={handleApplyChanges}
|
onClick={handleApplyChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Apply Changes</Text>
|
<Text size="B300">{t('RoomSettings.apply_changes')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/* eslint-disable react/no-array-index-key */
|
/* eslint-disable react/no-array-index-key */
|
||||||
import React, { useState, MouseEventHandler, ReactNode } from 'react';
|
import React, { useState, MouseEventHandler, ReactNode } from 'react';
|
||||||
import FocusTrap from 'focus-trap-react';
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
|
|
@ -108,6 +109,7 @@ type PowersProps = {
|
||||||
onEdit?: () => void;
|
onEdit?: () => void;
|
||||||
};
|
};
|
||||||
export function Powers({ powerLevels, permissionGroups, onEdit }: PowersProps) {
|
export function Powers({ powerLevels, permissionGroups, onEdit }: PowersProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
@ -127,8 +129,8 @@ export function Powers({ powerLevels, permissionGroups, onEdit }: PowersProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Founders"
|
title={t('RoomSettings.founders')}
|
||||||
description="Founding members has all permissions and can only be changed during upgrade."
|
description={t('RoomSettings.founders_desc')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingTile>
|
<SettingTile>
|
||||||
|
|
@ -155,8 +157,8 @@ export function Powers({ powerLevels, permissionGroups, onEdit }: PowersProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="Power Levels"
|
title={t('RoomSettings.power_levels')}
|
||||||
description="Manage and customize incremental power levels for users."
|
description={t('RoomSettings.power_levels_desc')}
|
||||||
after={
|
after={
|
||||||
onEdit && (
|
onEdit && (
|
||||||
<Box gap="200">
|
<Box gap="200">
|
||||||
|
|
@ -168,7 +170,7 @@ export function Powers({ powerLevels, permissionGroups, onEdit }: PowersProps) {
|
||||||
outlined
|
outlined
|
||||||
onClick={onEdit}
|
onClick={onEdit}
|
||||||
>
|
>
|
||||||
<Text size="B300">Edit</Text>
|
<Text size="B300">{t('RoomSettings.edit')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import { HexColorPicker } from 'react-colorful';
|
import { HexColorPicker } from 'react-colorful';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||||
import { IPowerLevels } from '../../../hooks/usePowerLevels';
|
import { IPowerLevels } from '../../../hooks/usePowerLevels';
|
||||||
|
|
@ -58,6 +59,7 @@ type EditPowerProps = {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
};
|
};
|
||||||
function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const roomToParents = useAtomValue(roomToParentsAtom);
|
const roomToParents = useAtomValue(roomToParentsAtom);
|
||||||
|
|
@ -120,7 +122,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
<Box direction="Column" gap="300">
|
<Box direction="Column" gap="300">
|
||||||
<Box gap="200">
|
<Box gap="200">
|
||||||
<Box shrink="No" direction="Column" gap="100">
|
<Box shrink="No" direction="Column" gap="100">
|
||||||
<Text size="L400">Color</Text>
|
<Text size="L400">{t('RoomSettings.color')}</Text>
|
||||||
<Box gap="200">
|
<Box gap="200">
|
||||||
<HexColorPickerPopOut
|
<HexColorPickerPopOut
|
||||||
picker={<HexColorPicker color={tagColor} onChange={setTagColor} />}
|
picker={<HexColorPicker color={tagColor} onChange={setTagColor} />}
|
||||||
|
|
@ -137,18 +139,18 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
radii="300"
|
radii="300"
|
||||||
before={<PowerColorBadge color={tagColor} />}
|
before={<PowerColorBadge color={tagColor} />}
|
||||||
>
|
>
|
||||||
<Text size="B300">Pick</Text>
|
<Text size="B300">{t('RoomSettings.pick')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</HexColorPickerPopOut>
|
</HexColorPickerPopOut>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box grow="Yes" direction="Column" gap="100">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Text size="L400">Name</Text>
|
<Text size="L400">{t('RoomSettings.name')}</Text>
|
||||||
<Input
|
<Input
|
||||||
name="nameInput"
|
name="nameInput"
|
||||||
defaultValue={tag?.name}
|
defaultValue={tag?.name}
|
||||||
placeholder="Bot"
|
placeholder={t('RoomSettings.power_level_placeholder')}
|
||||||
size="300"
|
size="300"
|
||||||
variant="Secondary"
|
variant="Secondary"
|
||||||
radii="300"
|
radii="300"
|
||||||
|
|
@ -156,7 +158,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box style={{ maxWidth: toRem(74) }} grow="Yes" direction="Column" gap="100">
|
<Box style={{ maxWidth: toRem(74) }} grow="Yes" direction="Column" gap="100">
|
||||||
<Text size="L400">Power</Text>
|
<Text size="L400">{t('RoomSettings.power')}</Text>
|
||||||
<Input
|
<Input
|
||||||
defaultValue={power}
|
defaultValue={power}
|
||||||
name="powerInput"
|
name="powerInput"
|
||||||
|
|
@ -174,7 +176,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Icon</Text>
|
<Text size="L400">{t('RoomSettings.icon')}</Text>
|
||||||
{iconUploadAtom && !tagIconSrc ? (
|
{iconUploadAtom && !tagIconSrc ? (
|
||||||
<CompactUploadCardRenderer
|
<CompactUploadCardRenderer
|
||||||
uploadAtom={iconUploadAtom}
|
uploadAtom={iconUploadAtom}
|
||||||
|
|
@ -194,7 +196,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
fill="None"
|
fill="None"
|
||||||
radii="300"
|
radii="300"
|
||||||
>
|
>
|
||||||
<Text size="B300">Remove</Text>
|
<Text size="B300">{t('RoomSettings.remove')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -238,7 +240,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
radii="300"
|
radii="300"
|
||||||
before={<Icon size="50" src={Icons.SmilePlus} />}
|
before={<Icon size="50" src={Icons.SmilePlus} />}
|
||||||
>
|
>
|
||||||
<Text size="B300">Pick</Text>
|
<Text size="B300">{t('RoomSettings.pick')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</PopOut>
|
</PopOut>
|
||||||
)}
|
)}
|
||||||
|
|
@ -251,7 +253,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
fill="None"
|
fill="None"
|
||||||
radii="300"
|
radii="300"
|
||||||
>
|
>
|
||||||
<Text size="B300">Import</Text>
|
<Text size="B300">{t('RoomSettings.import')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
@ -267,7 +269,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
radii="300"
|
radii="300"
|
||||||
disabled={uploadingIcon}
|
disabled={uploadingIcon}
|
||||||
>
|
>
|
||||||
<Text size="B300">Save</Text>
|
<Text size="B300">{t('RoomSettings.save')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -277,7 +279,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
|
||||||
radii="300"
|
radii="300"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
<Text size="B300">Cancel</Text>
|
<Text size="B300">{t('RoomSettings.cancel')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -289,6 +291,7 @@ type PowersEditorProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
@ -365,7 +368,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
onClick={requestClose}
|
onClick={requestClose}
|
||||||
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
before={<Icon size="100" src={Icons.ArrowLeft} />}
|
||||||
>
|
>
|
||||||
<Text size="T300">Permissions</Text>
|
<Text size="T300">{t('RoomSettings.permissions')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
@ -381,7 +384,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
<Box direction="Column" gap="700">
|
<Box direction="Column" gap="700">
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Box alignItems="Baseline" gap="200" justifyContent="SpaceBetween">
|
<Box alignItems="Baseline" gap="200" justifyContent="SpaceBetween">
|
||||||
<Text size="L400">Power Levels</Text>
|
<Text size="L400">{t('RoomSettings.power_levels')}</Text>
|
||||||
<BetaNoticeBadge />
|
<BetaNoticeBadge />
|
||||||
</Box>
|
</Box>
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
|
|
@ -391,8 +394,8 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
gap="400"
|
gap="400"
|
||||||
>
|
>
|
||||||
<SettingTile
|
<SettingTile
|
||||||
title="New Power Level"
|
title={t('RoomSettings.new_power_level')}
|
||||||
description="Create a new power level."
|
description={t('RoomSettings.new_power_level_desc')}
|
||||||
after={
|
after={
|
||||||
!createTag && (
|
!createTag && (
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -404,7 +407,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
outlined
|
outlined
|
||||||
disabled={applyingChanges}
|
disabled={applyingChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Create</Text>
|
<Text size="B300">{t('RoomSettings.create')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -462,7 +465,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
disabled={applyingChanges}
|
disabled={applyingChanges}
|
||||||
onClick={() => handleToggleDelete(power)}
|
onClick={() => handleToggleDelete(power)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Undo</Text>
|
<Text size="B300">{t('RoomSettings.undo')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
) : (
|
) : (
|
||||||
<Box shrink="No" alignItems="Center" gap="200">
|
<Box shrink="No" alignItems="Center" gap="200">
|
||||||
|
|
@ -471,13 +474,13 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
<Tooltip style={{ maxWidth: toRem(200) }}>
|
<Tooltip style={{ maxWidth: toRem(200) }}>
|
||||||
{usedPowers.has(power) ? (
|
{usedPowers.has(power) ? (
|
||||||
<Box direction="Column">
|
<Box direction="Column">
|
||||||
<Text size="L400">Used Power Level</Text>
|
<Text size="L400">{t('RoomSettings.used_power_level')}</Text>
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
You have to remove its use before you can delete it.
|
{t('RoomSettings.used_power_level_desc')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Text>Delete</Text>
|
<Text>{t('RoomSettings.delete')}</Text>
|
||||||
)}
|
)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
|
|
@ -506,7 +509,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
disabled={applyingChanges}
|
disabled={applyingChanges}
|
||||||
onClick={() => setEdit(true)}
|
onClick={() => setEdit(true)}
|
||||||
>
|
>
|
||||||
<Text size="B300">Edit</Text>
|
<Text size="B300">{t('RoomSettings.edit')}</Text>
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|
@ -536,11 +539,11 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
<Box grow="Yes" direction="Column">
|
<Box grow="Yes" direction="Column">
|
||||||
{applyState.status === AsyncStatus.Error ? (
|
{applyState.status === AsyncStatus.Error ? (
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
<b>Failed to apply changes! Please try again.</b>
|
<b>{t('RoomSettings.failed_to_apply')}</b>
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Text size="T200">
|
<Text size="T200">
|
||||||
<b>Changes saved! Apply when ready.</b>
|
<b>{t('RoomSettings.changes_saved')}</b>
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -553,7 +556,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
disabled={applyingChanges}
|
disabled={applyingChanges}
|
||||||
onClick={resetChanges}
|
onClick={resetChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Reset</Text>
|
<Text size="B300">{t('RoomSettings.reset')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="300"
|
size="300"
|
||||||
|
|
@ -565,7 +568,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
|
||||||
}
|
}
|
||||||
onClick={handleApplyChanges}
|
onClick={handleApplyChanges}
|
||||||
>
|
>
|
||||||
<Text size="B300">Apply Changes</Text>
|
<Text size="B300">{t('RoomSettings.apply_changes')}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import { Avatar, Box, config, Icon, IconButton, Icons, IconSrc, MenuItem, Text } from 'folds';
|
import { Avatar, Box, config, Icon, IconButton, Icons, IconSrc, MenuItem, Text } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { JoinRule } from 'matrix-js-sdk';
|
import { JoinRule } from 'matrix-js-sdk';
|
||||||
import { PageNav, PageNavContent, PageNavHeader, PageRoot } from '../../components/page';
|
import { PageNav, PageNavContent, PageNavHeader, PageRoot } from '../../components/page';
|
||||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||||
|
|
@ -24,37 +25,39 @@ type RoomSettingsMenuItem = {
|
||||||
icon: IconSrc;
|
icon: IconSrc;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useRoomSettingsMenuItems = (): RoomSettingsMenuItem[] =>
|
const useRoomSettingsMenuItems = (): RoomSettingsMenuItem[] => {
|
||||||
useMemo(
|
const { t } = useTranslation();
|
||||||
|
return useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
page: RoomSettingsPage.GeneralPage,
|
page: RoomSettingsPage.GeneralPage,
|
||||||
name: 'General',
|
name: t('RoomSettings.general'),
|
||||||
icon: Icons.Setting,
|
icon: Icons.Setting,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
page: RoomSettingsPage.MembersPage,
|
page: RoomSettingsPage.MembersPage,
|
||||||
name: 'Members',
|
name: t('RoomSettings.members'),
|
||||||
icon: Icons.User,
|
icon: Icons.User,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
page: RoomSettingsPage.PermissionsPage,
|
page: RoomSettingsPage.PermissionsPage,
|
||||||
name: 'Permissions',
|
name: t('RoomSettings.permissions'),
|
||||||
icon: Icons.Lock,
|
icon: Icons.Lock,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
page: RoomSettingsPage.EmojisStickersPage,
|
page: RoomSettingsPage.EmojisStickersPage,
|
||||||
name: 'Emojis & Stickers',
|
name: t('RoomSettings.emojis_stickers'),
|
||||||
icon: Icons.Smile,
|
icon: Icons.Smile,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
page: RoomSettingsPage.DeveloperToolsPage,
|
page: RoomSettingsPage.DeveloperToolsPage,
|
||||||
name: 'Developer Tools',
|
name: t('RoomSettings.developer_tools'),
|
||||||
icon: Icons.Terminal,
|
icon: Icons.Terminal,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[]
|
[t]
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
type RoomSettingsProps = {
|
type RoomSettingsProps = {
|
||||||
initialPage?: RoomSettingsPage;
|
initialPage?: RoomSettingsPage;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||||
import { usePowerLevels } from '../../../hooks/usePowerLevels';
|
import { usePowerLevels } from '../../../hooks/usePowerLevels';
|
||||||
import { useRoom } from '../../../hooks/useRoom';
|
import { useRoom } from '../../../hooks/useRoom';
|
||||||
|
|
@ -20,6 +21,7 @@ type GeneralProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function General({ requestClose }: GeneralProps) {
|
export function General({ requestClose }: GeneralProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const powerLevels = usePowerLevels(room);
|
const powerLevels = usePowerLevels(room);
|
||||||
const creators = useRoomCreators(room);
|
const creators = useRoomCreators(room);
|
||||||
|
|
@ -31,7 +33,7 @@ export function General({ requestClose }: GeneralProps) {
|
||||||
<Box grow="Yes" gap="200">
|
<Box grow="Yes" gap="200">
|
||||||
<Box grow="Yes" alignItems="Center" gap="200">
|
<Box grow="Yes" alignItems="Center" gap="200">
|
||||||
<Text size="H3" truncate>
|
<Text size="H3" truncate>
|
||||||
General
|
{t('RoomSettings.general')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
@ -47,19 +49,19 @@ export function General({ requestClose }: GeneralProps) {
|
||||||
<Box direction="Column" gap="700">
|
<Box direction="Column" gap="700">
|
||||||
<RoomProfile permissions={permissions} />
|
<RoomProfile permissions={permissions} />
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Options</Text>
|
<Text size="L400">{t('RoomSettings.options')}</Text>
|
||||||
<RoomJoinRules permissions={permissions} />
|
<RoomJoinRules permissions={permissions} />
|
||||||
<RoomHistoryVisibility permissions={permissions} />
|
<RoomHistoryVisibility permissions={permissions} />
|
||||||
<RoomEncryption permissions={permissions} />
|
<RoomEncryption permissions={permissions} />
|
||||||
<RoomPublish permissions={permissions} />
|
<RoomPublish permissions={permissions} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Addresses</Text>
|
<Text size="L400">{t('RoomSettings.addresses')}</Text>
|
||||||
<RoomPublishedAddresses permissions={permissions} />
|
<RoomPublishedAddresses permissions={permissions} />
|
||||||
<RoomLocalAddresses permissions={permissions} />
|
<RoomLocalAddresses permissions={permissions} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Text size="L400">Advanced Options</Text>
|
<Text size="L400">{t('RoomSettings.advanced_options')}</Text>
|
||||||
<RoomUpgrade permissions={permissions} requestClose={requestClose} />
|
<RoomUpgrade permissions={permissions} requestClose={requestClose} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||||
import { useRoom } from '../../../hooks/useRoom';
|
import { useRoom } from '../../../hooks/useRoom';
|
||||||
import { usePowerLevels } from '../../../hooks/usePowerLevels';
|
import { usePowerLevels } from '../../../hooks/usePowerLevels';
|
||||||
|
|
@ -14,6 +15,7 @@ type PermissionsProps = {
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
export function Permissions({ requestClose }: PermissionsProps) {
|
export function Permissions({ requestClose }: PermissionsProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const powerLevels = usePowerLevels(room);
|
const powerLevels = usePowerLevels(room);
|
||||||
|
|
@ -41,7 +43,7 @@ export function Permissions({ requestClose }: PermissionsProps) {
|
||||||
<Box grow="Yes" gap="200">
|
<Box grow="Yes" gap="200">
|
||||||
<Box grow="Yes" alignItems="Center" gap="200">
|
<Box grow="Yes" alignItems="Center" gap="200">
|
||||||
<Text size="H3" truncate>
|
<Text size="H3" truncate>
|
||||||
Permissions
|
{t('RoomSettings.permissions')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box shrink="No">
|
<Box shrink="No">
|
||||||
|
|
|
||||||
|
|
@ -1,215 +1,217 @@
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MessageEvent, StateEvent } from '../../../../types/matrix/room';
|
import { MessageEvent, StateEvent } from '../../../../types/matrix/room';
|
||||||
import { PermissionGroup } from '../../common-settings/permissions';
|
import { PermissionGroup } from '../../common-settings/permissions';
|
||||||
|
|
||||||
export const usePermissionGroups = (isCallRoom: boolean): PermissionGroup[] => {
|
export const usePermissionGroups = (isCallRoom: boolean): PermissionGroup[] => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const groups: PermissionGroup[] = useMemo(() => {
|
const groups: PermissionGroup[] = useMemo(() => {
|
||||||
const messagesGroup: PermissionGroup = {
|
const messagesGroup: PermissionGroup = {
|
||||||
name: 'Messages',
|
name: t('RoomSettings.perm_messages'),
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
key: MessageEvent.RoomMessage,
|
key: MessageEvent.RoomMessage,
|
||||||
},
|
},
|
||||||
name: 'Send Messages',
|
name: t('RoomSettings.perm_send_messages'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
key: MessageEvent.Sticker,
|
key: MessageEvent.Sticker,
|
||||||
},
|
},
|
||||||
name: 'Send Stickers',
|
name: t('RoomSettings.perm_send_stickers'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
key: MessageEvent.Reaction,
|
key: MessageEvent.Reaction,
|
||||||
},
|
},
|
||||||
name: 'Send Reactions',
|
name: t('RoomSettings.perm_send_reactions'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
notification: true,
|
notification: true,
|
||||||
key: 'room',
|
key: 'room',
|
||||||
},
|
},
|
||||||
name: 'Ping @room',
|
name: t('RoomSettings.perm_ping_room'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomPinnedEvents,
|
key: StateEvent.RoomPinnedEvents,
|
||||||
},
|
},
|
||||||
name: 'Pin Messages',
|
name: t('RoomSettings.perm_pin_messages'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {},
|
location: {},
|
||||||
name: 'Other Message Events',
|
name: t('RoomSettings.perm_other_message_events'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const callSettingsGroup: PermissionGroup = {
|
const callSettingsGroup: PermissionGroup = {
|
||||||
name: 'Calls',
|
name: t('RoomSettings.perm_calls'),
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.GroupCallMemberPrefix,
|
key: StateEvent.GroupCallMemberPrefix,
|
||||||
},
|
},
|
||||||
name: 'Join Call',
|
name: t('RoomSettings.perm_join_call'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const moderationGroup: PermissionGroup = {
|
const moderationGroup: PermissionGroup = {
|
||||||
name: 'Moderation',
|
name: t('RoomSettings.perm_moderation'),
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
action: true,
|
action: true,
|
||||||
key: 'invite',
|
key: 'invite',
|
||||||
},
|
},
|
||||||
name: 'Invite',
|
name: t('RoomSettings.perm_invite'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
action: true,
|
action: true,
|
||||||
key: 'kick',
|
key: 'kick',
|
||||||
},
|
},
|
||||||
name: 'Kick',
|
name: t('RoomSettings.perm_kick'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
action: true,
|
action: true,
|
||||||
key: 'ban',
|
key: 'ban',
|
||||||
},
|
},
|
||||||
name: 'Ban',
|
name: t('RoomSettings.perm_ban'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
action: true,
|
action: true,
|
||||||
key: 'redact',
|
key: 'redact',
|
||||||
},
|
},
|
||||||
name: 'Delete Others Messages',
|
name: t('RoomSettings.perm_delete_others_messages'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
key: MessageEvent.RoomRedaction,
|
key: MessageEvent.RoomRedaction,
|
||||||
},
|
},
|
||||||
name: 'Delete Self Messages',
|
name: t('RoomSettings.perm_delete_self_messages'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const roomOverviewGroup: PermissionGroup = {
|
const roomOverviewGroup: PermissionGroup = {
|
||||||
name: 'Room Overview',
|
name: t('RoomSettings.perm_room_overview'),
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomAvatar,
|
key: StateEvent.RoomAvatar,
|
||||||
},
|
},
|
||||||
name: 'Room Avatar',
|
name: t('RoomSettings.perm_room_avatar'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomName,
|
key: StateEvent.RoomName,
|
||||||
},
|
},
|
||||||
name: 'Room Name',
|
name: t('RoomSettings.perm_room_name'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomTopic,
|
key: StateEvent.RoomTopic,
|
||||||
},
|
},
|
||||||
name: 'Room Topic',
|
name: t('RoomSettings.perm_room_topic'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const roomSettingsGroup: PermissionGroup = {
|
const roomSettingsGroup: PermissionGroup = {
|
||||||
name: 'Settings',
|
name: t('RoomSettings.perm_settings'),
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomJoinRules,
|
key: StateEvent.RoomJoinRules,
|
||||||
},
|
},
|
||||||
name: 'Change Room Access',
|
name: t('RoomSettings.perm_change_room_access'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomCanonicalAlias,
|
key: StateEvent.RoomCanonicalAlias,
|
||||||
},
|
},
|
||||||
name: 'Publish Address',
|
name: t('RoomSettings.perm_publish_address'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomPowerLevels,
|
key: StateEvent.RoomPowerLevels,
|
||||||
},
|
},
|
||||||
name: 'Change All Permission',
|
name: t('RoomSettings.perm_change_all_permission'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.PowerLevelTags,
|
key: StateEvent.PowerLevelTags,
|
||||||
},
|
},
|
||||||
name: 'Edit Power Levels',
|
name: t('RoomSettings.perm_edit_power_levels'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomEncryption,
|
key: StateEvent.RoomEncryption,
|
||||||
},
|
},
|
||||||
name: 'Enable Encryption',
|
name: t('RoomSettings.perm_enable_encryption'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomHistoryVisibility,
|
key: StateEvent.RoomHistoryVisibility,
|
||||||
},
|
},
|
||||||
name: 'History Visibility',
|
name: t('RoomSettings.perm_history_visibility'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomTombstone,
|
key: StateEvent.RoomTombstone,
|
||||||
},
|
},
|
||||||
name: 'Upgrade Room',
|
name: t('RoomSettings.perm_upgrade_room'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
},
|
},
|
||||||
name: 'Other Settings',
|
name: t('RoomSettings.perm_other_settings'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const otherSettingsGroup: PermissionGroup = {
|
const otherSettingsGroup: PermissionGroup = {
|
||||||
name: 'Other',
|
name: t('RoomSettings.perm_other'),
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.PoniesRoomEmotes,
|
key: StateEvent.PoniesRoomEmotes,
|
||||||
},
|
},
|
||||||
name: 'Manage Emojis & Stickers',
|
name: t('RoomSettings.perm_manage_emojis_stickers'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.RoomServerAcl,
|
key: StateEvent.RoomServerAcl,
|
||||||
},
|
},
|
||||||
name: 'Change Server ACLs',
|
name: t('RoomSettings.perm_change_server_acls'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
state: true,
|
state: true,
|
||||||
key: 'im.vector.modular.widgets',
|
key: 'im.vector.modular.widgets',
|
||||||
},
|
},
|
||||||
name: 'Modify Widgets',
|
name: t('RoomSettings.perm_modify_widgets'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
@ -222,7 +224,7 @@ export const usePermissionGroups = (isCallRoom: boolean): PermissionGroup[] => {
|
||||||
roomSettingsGroup,
|
roomSettingsGroup,
|
||||||
otherSettingsGroup,
|
otherSettingsGroup,
|
||||||
];
|
];
|
||||||
}, [isCallRoom]);
|
}, [isCallRoom, t]);
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { RoomMember } from 'matrix-js-sdk';
|
import { RoomMember } from 'matrix-js-sdk';
|
||||||
import { Membership } from '../../types/matrix/room';
|
import { Membership } from '../../types/matrix/room';
|
||||||
|
|
||||||
|
|
@ -21,32 +22,34 @@ export type MembershipFilterItem = {
|
||||||
filterFn: MembershipFilterFn;
|
filterFn: MembershipFilterFn;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useMembershipFilterMenu = (): MembershipFilterItem[] =>
|
export const useMembershipFilterMenu = (): MembershipFilterItem[] => {
|
||||||
useMemo(
|
const { t } = useTranslation();
|
||||||
|
return useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
name: 'Joined',
|
name: t('RoomSettings.filter_joined'),
|
||||||
filterFn: MembershipFilter.filterJoined,
|
filterFn: MembershipFilter.filterJoined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Invited',
|
name: t('RoomSettings.filter_invited'),
|
||||||
filterFn: MembershipFilter.filterInvited,
|
filterFn: MembershipFilter.filterInvited,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Left',
|
name: t('RoomSettings.filter_left'),
|
||||||
filterFn: MembershipFilter.filterLeaved,
|
filterFn: MembershipFilter.filterLeaved,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Kicked',
|
name: t('RoomSettings.filter_kicked'),
|
||||||
filterFn: MembershipFilter.filterKicked,
|
filterFn: MembershipFilter.filterKicked,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Banned',
|
name: t('RoomSettings.filter_banned'),
|
||||||
filterFn: MembershipFilter.filterBanned,
|
filterFn: MembershipFilter.filterBanned,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[]
|
[t]
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const useMembershipFilter = (
|
export const useMembershipFilter = (
|
||||||
index: number,
|
index: number,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { RoomMember } from 'matrix-js-sdk';
|
import { RoomMember } from 'matrix-js-sdk';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const MemberSort = {
|
export const MemberSort = {
|
||||||
Ascending: (a: RoomMember, b: RoomMember) =>
|
Ascending: (a: RoomMember, b: RoomMember) =>
|
||||||
|
|
@ -19,28 +20,30 @@ export type MemberSortItem = {
|
||||||
sortFn: MemberSortFn;
|
sortFn: MemberSortFn;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useMemberSortMenu = (): MemberSortItem[] =>
|
export const useMemberSortMenu = (): MemberSortItem[] => {
|
||||||
useMemo(
|
const { t } = useTranslation();
|
||||||
|
return useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
name: 'A to Z',
|
name: t('RoomSettings.sort_a_to_z'),
|
||||||
sortFn: MemberSort.Ascending,
|
sortFn: MemberSort.Ascending,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Z to A',
|
name: t('RoomSettings.sort_z_to_a'),
|
||||||
sortFn: MemberSort.Descending,
|
sortFn: MemberSort.Descending,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Newest',
|
name: t('RoomSettings.sort_newest'),
|
||||||
sortFn: MemberSort.NewestFirst,
|
sortFn: MemberSort.NewestFirst,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Oldest',
|
name: t('RoomSettings.sort_oldest'),
|
||||||
sortFn: MemberSort.Oldest,
|
sortFn: MemberSort.Oldest,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[]
|
[t]
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const useMemberSort = (index: number, memberSort: MemberSortItem[]): MemberSortItem => {
|
export const useMemberSort = (index: number, memberSort: MemberSortItem[]): MemberSortItem => {
|
||||||
const item = memberSort[index] ?? memberSort[0];
|
const item = memberSort[index] ?? memberSort[0];
|
||||||
|
|
@ -61,7 +64,7 @@ export const useMemberPowerSort = (
|
||||||
|
|
||||||
return getPowerLevel(b.userId) - getPowerLevel(a.userId);
|
return getPowerLevel(b.userId) - getPowerLevel(a.userId);
|
||||||
},
|
},
|
||||||
[creators]
|
[creators, getPowerLevel]
|
||||||
);
|
);
|
||||||
|
|
||||||
return sort;
|
return sort;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Room } from 'matrix-js-sdk';
|
import { Room } from 'matrix-js-sdk';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { IPowerLevels } from './usePowerLevels';
|
import { IPowerLevels } from './usePowerLevels';
|
||||||
import { useStateEvent } from './useStateEvent';
|
import { useStateEvent } from './useStateEvent';
|
||||||
import { MemberPowerTag, StateEvent } from '../../types/matrix/room';
|
import { MemberPowerTag, StateEvent } from '../../types/matrix/room';
|
||||||
|
|
@ -45,76 +46,91 @@ export const getUsedPowers = (powerLevels: IPowerLevels): Set<number> => {
|
||||||
return powers;
|
return powers;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_TAGS: PowerLevelTags = {
|
type TFunction = (key: string) => string;
|
||||||
|
|
||||||
|
const getDefaultTags = (t: TFunction): PowerLevelTags => ({
|
||||||
9001: {
|
9001: {
|
||||||
name: 'Goku',
|
name: t('RoomSettings.power_goku'),
|
||||||
color: '#ff6a00',
|
color: '#ff6a00',
|
||||||
},
|
},
|
||||||
150: {
|
150: {
|
||||||
name: 'Manager',
|
name: t('RoomSettings.power_manager'),
|
||||||
color: '#ff6a7f',
|
color: '#ff6a7f',
|
||||||
},
|
},
|
||||||
101: {
|
101: {
|
||||||
name: 'Founder',
|
name: t('RoomSettings.power_founder'),
|
||||||
color: '#0000ff',
|
color: '#0000ff',
|
||||||
},
|
},
|
||||||
100: {
|
100: {
|
||||||
name: 'Admin',
|
name: t('RoomSettings.power_admin'),
|
||||||
color: '#0088ff',
|
color: '#0088ff',
|
||||||
},
|
},
|
||||||
50: {
|
50: {
|
||||||
name: 'Moderator',
|
name: t('RoomSettings.power_moderator'),
|
||||||
color: '#1fd81f',
|
color: '#1fd81f',
|
||||||
},
|
},
|
||||||
0: {
|
0: {
|
||||||
name: 'Member',
|
name: t('RoomSettings.power_member'),
|
||||||
color: '#91cfdf',
|
color: '#91cfdf',
|
||||||
},
|
},
|
||||||
[-1]: {
|
[-1]: {
|
||||||
name: 'Muted',
|
name: t('RoomSettings.power_muted'),
|
||||||
color: '#888888',
|
color: '#888888',
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
const generateFallbackTag = (powerLevelTags: PowerLevelTags, power: number): MemberPowerTag => {
|
const generateFallbackTag = (powerLevelTags: PowerLevelTags, power: number, t: TFunction): MemberPowerTag => {
|
||||||
const highToLow = sortPowers(getPowers(powerLevelTags));
|
const highToLow = sortPowers(getPowers(powerLevelTags));
|
||||||
|
|
||||||
const tagPower = highToLow.find((p) => p < power);
|
const tagPower = highToLow.find((p) => p < power);
|
||||||
const tag = typeof tagPower === 'number' ? powerLevelTags[tagPower] : undefined;
|
const tag = typeof tagPower === 'number' ? powerLevelTags[tagPower] : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: tag ? `${tag.name} ${power}` : `Team ${power}`,
|
name: tag ? `${tag.name} ${power}` : `${t('RoomSettings.power_team')} ${power}`,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const LEGACY_CINNY_POWER_LEVEL_TAGS = 'in.cinny.room.power_level_tags' as StateEvent;
|
const LEGACY_CINNY_POWER_LEVEL_TAGS = 'in.cinny.room.power_level_tags' as StateEvent;
|
||||||
|
|
||||||
export const usePowerLevelTags = (room: Room, powerLevels: IPowerLevels): PowerLevelTags => {
|
export const usePowerLevelTags = (room: Room, powerLevels: IPowerLevels): PowerLevelTags => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const tagsEvent = useStateEvent(room, StateEvent.PowerLevelTags);
|
const tagsEvent = useStateEvent(room, StateEvent.PowerLevelTags);
|
||||||
const legacyTagsEvent = useStateEvent(room, LEGACY_CINNY_POWER_LEVEL_TAGS);
|
const legacyTagsEvent = useStateEvent(room, LEGACY_CINNY_POWER_LEVEL_TAGS);
|
||||||
const activeTagsEvent = tagsEvent ?? legacyTagsEvent;
|
const activeTagsEvent = tagsEvent ?? legacyTagsEvent;
|
||||||
|
|
||||||
const powerLevelTags: PowerLevelTags = useMemo(() => {
|
const powerLevelTags: PowerLevelTags = useMemo(() => {
|
||||||
|
const defaultTags = getDefaultTags(t);
|
||||||
const content = activeTagsEvent?.getContent<PowerLevelTags>();
|
const content = activeTagsEvent?.getContent<PowerLevelTags>();
|
||||||
const powerToTags: PowerLevelTags = { ...content };
|
const powerToTags: PowerLevelTags = { ...content };
|
||||||
|
|
||||||
const powers = getUsedPowers(powerLevels);
|
const powers = getUsedPowers(powerLevels);
|
||||||
Array.from(powers).forEach((power) => {
|
Array.from(powers).forEach((power) => {
|
||||||
if (powerToTags[power]?.name === undefined) {
|
if (powerToTags[power]?.name === undefined) {
|
||||||
powerToTags[power] = DEFAULT_TAGS[power] ?? generateFallbackTag(DEFAULT_TAGS, power);
|
powerToTags[power] = defaultTags[power] ?? generateFallbackTag(defaultTags, power, t);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return powerToTags;
|
return powerToTags;
|
||||||
}, [powerLevels, activeTagsEvent]);
|
}, [powerLevels, activeTagsEvent, t]);
|
||||||
|
|
||||||
return powerLevelTags;
|
return powerLevelTags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateFallbackTagSimple = (powerLevelTags: PowerLevelTags, power: number): MemberPowerTag => {
|
||||||
|
const highToLow = sortPowers(getPowers(powerLevelTags));
|
||||||
|
|
||||||
|
const tagPower = highToLow.find((p) => p < power);
|
||||||
|
const tag = typeof tagPower === 'number' ? powerLevelTags[tagPower] : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: tag ? `${tag.name} ${power}` : `#${power}`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const getPowerLevelTag = (
|
export const getPowerLevelTag = (
|
||||||
powerLevelTags: PowerLevelTags,
|
powerLevelTags: PowerLevelTags,
|
||||||
powerLevel: number
|
powerLevel: number
|
||||||
): MemberPowerTag => {
|
): MemberPowerTag => {
|
||||||
const tag: MemberPowerTag | undefined = powerLevelTags[powerLevel];
|
const tag: MemberPowerTag | undefined = powerLevelTags[powerLevel];
|
||||||
return tag ?? generateFallbackTag(powerLevelTags, powerLevel);
|
return tag ?? generateFallbackTagSimple(powerLevelTags, powerLevel);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MemberPowerTag } from '../../types/matrix/room';
|
import { MemberPowerTag } from '../../types/matrix/room';
|
||||||
|
|
||||||
const DEFAULT_TAG: MemberPowerTag = {
|
export const useRoomCreatorsTag = (): MemberPowerTag => {
|
||||||
name: 'Founder',
|
const { t } = useTranslation();
|
||||||
color: '#0000ff',
|
return useMemo(
|
||||||
|
() => ({
|
||||||
|
name: t('RoomSettings.power_founder'),
|
||||||
|
color: '#0000ff',
|
||||||
|
}),
|
||||||
|
[t]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useRoomCreatorsTag = (): MemberPowerTag => DEFAULT_TAG;
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue