Bläddra i källkod

Set horizontal layout direction based on the language

Fixes #122
JC Brand 2 år sedan
förälder
incheckning
4f9938cc88
48 ändrade filer med 215 tillägg och 190 borttagningar
  1. 5 0
      CHANGES.md
  2. 0 2
      dev.html
  3. 8 0
      docs/source/configuration.rst
  4. 1 10
      src/headless/shared/settings/api.js
  5. 31 31
      src/headless/shared/settings/constants.js
  6. 1 1
      src/headless/shared/settings/tests/settings.js
  7. 1 2
      src/headless/types/shared/settings/api.d.ts
  8. 2 2
      src/plugins/chatview/styles/chat-bottom-panel.scss
  9. 1 1
      src/plugins/chatview/styles/chat-head.scss
  10. 3 3
      src/plugins/chatview/styles/chatbox.scss
  11. 1 1
      src/plugins/chatview/styles/index.scss
  12. 16 19
      src/plugins/controlbox/styles/_controlbox.scss
  13. 8 4
      src/plugins/controlbox/styles/loginform.scss
  14. 1 1
      src/plugins/controlbox/templates/loginform.js
  15. 1 1
      src/plugins/headlines-view/styles/headlines.scss
  16. 7 2
      src/plugins/modal/styles/_modal.scss
  17. 1 1
      src/plugins/muc-views/styles/controlbox.scss
  18. 1 1
      src/plugins/muc-views/styles/muc-bottom-panel.scss
  19. 5 5
      src/plugins/muc-views/styles/muc-details-modal.scss
  20. 2 2
      src/plugins/muc-views/styles/muc-head.scss
  21. 3 3
      src/plugins/muc-views/styles/muc-occupant.scss
  22. 4 8
      src/plugins/muc-views/styles/muc-occupants.scss
  23. 2 2
      src/plugins/muc-views/styles/muc-sidebar.scss
  24. 3 2
      src/plugins/muc-views/styles/muc.scss
  25. 1 1
      src/plugins/profile/modals/styles/chat-status-modal.scss
  26. 2 2
      src/plugins/profile/modals/styles/profile.scss
  27. 7 2
      src/plugins/profile/styles/profile.scss
  28. 4 2
      src/plugins/profile/templates/profile.js
  29. 2 4
      src/plugins/roomslist/styles/roomsgroups.scss
  30. 2 1
      src/plugins/rootview/index.js
  31. 14 3
      src/plugins/rootview/root.js
  32. 2 2
      src/plugins/rootview/styles/background.scss
  33. 2 2
      src/plugins/rootview/styles/root.scss
  34. 5 3
      src/plugins/rosterview/styles/roster.scss
  35. 2 2
      src/shared/autocomplete/styles/_autocomplete.scss
  36. 1 1
      src/shared/avatar/avatar.scss
  37. 3 3
      src/shared/chat/styles/emoji.scss
  38. 3 3
      src/shared/chat/styles/message-actions.scss
  39. 1 1
      src/shared/chat/styles/message-body.scss
  40. 3 1
      src/shared/components/styles/dropdown.scss
  41. 2 2
      src/shared/components/styles/gif.scss
  42. 11 12
      src/shared/styles/_core.scss
  43. 3 3
      src/shared/styles/buttons.scss
  44. 4 3
      src/shared/styles/lists.scss
  45. 21 21
      src/shared/styles/messages.scss
  46. 3 3
      src/shared/styles/status.scss
  47. 1 1
      src/shared/styles/themes/cyberpunk.scss
  48. 8 8
      src/shared/styles/website.scss

+ 5 - 0
CHANGES.md

@@ -2,6 +2,7 @@
 
 ## 11.0.0 (Unreleased)
 
+- #122: Set horizontal layout direction based on the language
 - #698: Add support for MUC private messages
 - #1057: Removed the `mobile` view mode. Instead of setting `view_mode` to `mobile`, set it to `fullscreen`.
 - #1174: Show MUC avatars in the rooms list
@@ -59,6 +60,10 @@
 - `getAssignableRoles` and `getAssignableAffiliations` are no longer on the `_converse` object, but on the Occupant instance.
 - Removed the `chatBoxFocused` and `chatBoxBlurred` events.
 - Changed the signature of the `api.contacts.add` API method.
+- The deprecated API method `api.settings.update` has been removed. Use
+  `api.settings.extend` instead.
+- New config option [rtl_langs](https://conversejs.org/docs/html/configuration.html#rtl-langs) for specifying languages for which
+  Converse's UI should be shown in right-to-left order.
 
 ## 10.1.7 (2024-03-15)
 

+ 0 - 2
dev.html

@@ -26,7 +26,6 @@
     });
 
     converse.initialize({
-        i18n: 'af',
         theme: 'cyberpunk',
         auto_away: 300,
         enable_smacks: true,
@@ -37,7 +36,6 @@
         muc_respect_autojoin: true,
         muc_show_logs_before_join: true,
         notify_all_room_messages: ['discuss@conference.conversejs.org'],
-        // view_mode: 'fullscreen',
         websocket_url: 'wss://conversejs.org/xmpp-websocket',
         // websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
         whitelisted_plugins: ['converse-debug'],

+ 8 - 0
docs/source/configuration.rst

@@ -1922,6 +1922,14 @@ If set to ``true``, Converse will show any roster groups you might have configur
     elsewhere.
 
 
+rtl_langs
+---------
+
+* Default: ``["ar", "fa", "he", "ur"]``
+
+A list of languages which are written right-to-left and for which the UI should also be shown right-to-left.
+
+
 send_chat_state_notifications
 -----------------------------
 

+ 1 - 10
src/headless/shared/settings/api.js

@@ -1,7 +1,6 @@
 /**
  * @typedef {import('@converse/skeletor').Model} Model
  */
-import log from '../../log.js';
 import {
     extendAppSettings,
     getAppSetting,
@@ -29,7 +28,7 @@ export const settings_api = {
      * `converse.initialize`.
      *
      * @method api.settings.extend
-     * @param { object } settings The configuration settings
+     * @param {object} settings The configuration settings
      * @example
      * api.settings.extend({
      *    'enable_foo': true
@@ -45,14 +44,6 @@ export const settings_api = {
         return extendAppSettings(settings);
     },
 
-    update (settings) {
-        log.warn(
-            'The api.settings.update method has been deprecated and will be removed. ' +
-                'Please use api.settings.extend instead.'
-        );
-        return this.extend(settings);
-    },
-
     /**
      * @method _converse.api.settings.get
      * @param {string} [key]

+ 31 - 31
src/headless/shared/settings/constants.js

@@ -1,36 +1,36 @@
 /**
- * @typedef { Object } ConfigurationSettings
+ * @typedef {Object } ConfigurationSettings
  * Converse's core configuration values
- * @property { Boolean } [allow_non_roster_messaging=false]
- * @property { Boolean } [allow_url_history_change=true]
- * @property { String } [assets_path='/dist']
- * @property { ('login'|'prebind'|'anonymous'|'external') } [authentication='login']
- * @property { Boolean } [auto_login=false] - Currently only used in connection with anonymous login
- * @property { Boolean } [reuse_scram_keys=true] - Save SCRAM keys after login to allow for future auto login
- * @property { Boolean } [auto_reconnect=true]
- * @property { Array<String>} [blacklisted_plugins]
- * @property { Boolean } [clear_cache_on_logout=false]
- * @property { Object } [connection_options]
- * @property { String } [credentials_url] - URL from where login credentials can be fetched
- * @property { Boolean } [discover_connection_methods=true]
- * @property { RegExp } [geouri_regex]
- * @property { RegExp } [geouri_replacement='https://www.openstreetmap.org/?mlat=$1&mlon=$2#map=18/$1/$2']
- * @property { String } [i18n]
- * @property { String } [jid]
- * @property { Boolean } [keepalive=true]
- * @property { ('debug'|'info'|'eror') } [loglevel='info']
- * @property { Array<String> } [locales]
- * @property { String } [nickname]
- * @property { String } [password]
- * @property { ('IndexedDB'|'localStorage') } [persistent_store='IndexedDB']
- * @property { String } [rid]
- * @property { Element } [root=window.document]
- * @property { String } [sid]
- * @property { Boolean } [singleton=false]
- * @property { Boolean } [strict_plugin_dependencies=false]
- * @property { ('fullscreen'|'embedded'|'overlayed') } [view_mode='fullscreen']
- * @property { String } [websocket_url]
- * @property { Array<String>} [whitelisted_plugins]
+ * @property {Boolean} [allow_non_roster_messaging=false]
+ * @property {Boolean} [allow_url_history_change=true]
+ * @property {String} [assets_path='/dist']
+ * @property {('login'|'prebind'|'anonymous'|'external')} [authentication='login']
+ * @property {Boolean} [auto_login=false] - Currently only used in connection with anonymous login
+ * @property {Boolean} [reuse_scram_keys=true] - Save SCRAM keys after login to allow for future auto login
+ * @property {Boolean} [auto_reconnect=true]
+ * @property {Array<String>} [blacklisted_plugins]
+ * @property {Boolean} [clear_cache_on_logout=false]
+ * @property {Object} [connection_options]
+ * @property {String} [credentials_url] - URL from where login credentials can be fetched
+ * @property {Boolean} [discover_connection_methods=true]
+ * @property {RegExp} [geouri_regex]
+ * @property {RegExp} [geouri_replacement='https://www.openstreetmap.org/?mlat=$1&mlon=$2#map=18/$1/$2']
+ * @property {String} [i18n]
+ * @property {String} [jid]
+ * @property {Boolean} [keepalive=true]
+ * @property {('debug'|'info'|'eror')} [loglevel='info']
+ * @property {Array<String>} [locales]
+ * @property {String} [nickname]
+ * @property {String} [password]
+ * @property {('IndexedDB'|'localStorage')} [persistent_store='IndexedDB']
+ * @property {String} [rid]
+ * @property {Element} [root=window.document]
+ * @property {String} [sid]
+ * @property {Boolean} [singleton=false]
+ * @property {Boolean} [strict_plugin_dependencies=false]
+ * @property {('fullscreen'|'embedded'|'overlayed')} [view_mode='fullscreen']
+ * @property {String} [websocket_url]
+ * @property {Array<String>} [whitelisted_plugins]
  */
 export const DEFAULT_SETTINGS = {
     allow_non_roster_messaging: false,

+ 1 - 1
src/headless/shared/settings/tests/settings.js

@@ -7,7 +7,7 @@ describe("The \"settings\" API", function () {
 
         const { api } = _converse;
 
-        expect(Object.keys(api.settings)).toEqual(["extend", "update", "get", "set", "listen"]);
+        expect(Object.keys(api.settings)).toEqual(["extend", "get", "set", "listen"]);
         expect(api.settings.get("play_sounds")).toBe(true);
         api.settings.set("play_sounds", false);
         expect(api.settings.get("play_sounds")).toBe(false);

+ 1 - 2
src/headless/types/shared/settings/api.d.ts

@@ -8,7 +8,7 @@ export namespace settings_api {
      * `converse.initialize`.
      *
      * @method api.settings.extend
-     * @param { object } settings The configuration settings
+     * @param {object} settings The configuration settings
      * @example
      * api.settings.extend({
      *    'enable_foo': true
@@ -21,7 +21,6 @@ export namespace settings_api {
      * });
      */
     function extend(settings: object): void;
-    function update(settings: any): void;
     /**
      * @method _converse.api.settings.get
      * @param {string} [key]

+ 2 - 2
src/plugins/chatview/styles/chat-bottom-panel.scss

@@ -13,9 +13,9 @@
 
             .chat-message-form {
                 border-bottom: 0;
-                border-left: 0;
+                border-inline-start: 0;
                 border-top: 0.25em solid var(--chat-color);
-                border-right: 0.25em solid var(--chat-color);
+                border-inline-end: 0.25em solid var(--chat-color);
                 border-bottom-radius: var(--chatbox-border-radius);
                 background-clip: padding-box;
                 background-color: var(--background-color);

+ 1 - 1
src/plugins/chatview/styles/chat-head.scss

@@ -15,7 +15,7 @@
             }
 
             .avatar {
-                margin-right: 0.5em;
+                margin-inline-end: 0.5em;
             }
 
             .show-msg-author-modal {

+ 3 - 3
src/plugins/chatview/styles/chatbox.scss

@@ -10,7 +10,7 @@
 
 .conversejs {
     .chatbox {
-        text-align: left;
+        text-align: start;
 
         @media screen and (max-height: $mobile-landscape-height) {
             margin: 0;
@@ -89,7 +89,7 @@
             text-overflow: ellipsis;
             white-space: nowrap;
             &.groupchat {
-                padding-right: 0;
+                padding-inline-end: 0;
             }
             a {
                 color: var(--chat-color);
@@ -161,7 +161,7 @@
                 }
                 .close-chat-help {
                     float: right;
-                    padding-right: 1em;
+                    padding-inline-end: 1em;
                     cursor: pointer;
                     color: var(--background-color);
                     svg {

+ 1 - 1
src/plugins/chatview/styles/index.scss

@@ -216,7 +216,7 @@
             .chat-head {
                 converse-controlbox-navback {
                     margin: auto 0;
-                    margin-right: 1em;
+                    margin-inline-end: 1em;
                     display: flex;
                     .fa-arrow-left {
                         svg {

+ 16 - 19
src/plugins/controlbox/styles/_controlbox.scss

@@ -12,7 +12,7 @@
 
         li.room-info {
             display: block;
-            margin-left: 5px;
+            margin-inline-start: 5px;
         }
         p.room-info {
             line-height: var(--line-height);
@@ -52,7 +52,7 @@
 
         .brand-name-wrapper {
             font-size: 200%;
-            padding-right: 0.5em;
+            padding-inline-end: 0.5em;
         }
 
         .brand-name-wrapper--fullscreen {
@@ -73,7 +73,7 @@
 
         form.search-xmpp-contact {
             margin: 0;
-            padding-left: 5px;
+            padding-inline-start: 5px;
             padding: 0 0 5px 5px;
             input {
                 width: 8em;
@@ -81,11 +81,11 @@
         }
 
         .msgs-indicator {
-            margin-right: 0.5em;
+            margin-inline-end: 0.5em;
         }
 
         a.subscribe-to-user {
-            padding-left: 2em;
+            padding-inline-start: 2em;
             font-weight: bold;
         }
 
@@ -141,21 +141,19 @@
         }
 
         .controlbox-padded {
-            padding-left: 1em;
-            padding-right: 1em;
             align-items: center;
             line-height: normal;
         }
 
         .controlbox-pane {
-            height: 100%;
-            overflow-y: auto;
             border: 0;
             font-size: var(--font-size);
+            height: 100%;
             left: 0;
-            text-align: left;
             overflow-x: hidden;
-            padding: 0;
+            overflow-y: auto;
+            padding: 0.5em;
+            text-align: start;
 
             .add-converse-contact {
                 margin: 0 0 0.75em 0;
@@ -208,12 +206,11 @@
             }
 
             .brand-heading {
-                padding-left: 1em;
+                padding-inline-start: 1em;
                 width: 100%;
             }
 
             .converse-svg-logo {
-                margin-top: 0.25em;
                 height: 1em;
             }
         }
@@ -222,7 +219,7 @@
         &.converse-fullscreen {
             #controlbox {
                 .flyout {
-                    border-right: 0.2rem solid var(--controlbox-color);
+                    border-inline-end: 0.2rem solid var(--controlbox-color);
                 }
             }
             .toggle-controlbox {
@@ -295,10 +292,10 @@
         &.converse-fullscreen {
             #controlbox {
                 @media screen and (max-width: $mobile-portrait-length) {
-                    margin-left: 0;
+                    margin-inline-start: 0;
                 }
                 @include media-breakpoint-down(sm) {
-                    margin-left: 0;
+                    margin-inline-start: 0;
                 }
                 .box-flyout {
                     @include media-breakpoint-up(md) {
@@ -325,8 +322,8 @@
     .conversejs {
         left: 0;
         right: 0;
-        padding-left: env(safe-area-inset-left);
-        padding-right: env(safe-area-inset-right);
+        padding-inline-start: env(safe-area-inset-left);
+        padding-inline-end: env(safe-area-inset-right);
 
         .converse-chatboxes {
             margin: 0 !important;
@@ -348,7 +345,7 @@
             }
 
             #controlbox {
-                margin-left: 0;
+                margin-inline-start: 0;
                 width: 100vw !important;
                 .box-flyout {
                     width: 100vw !important;

+ 8 - 4
src/plugins/controlbox/styles/loginform.scss

@@ -27,9 +27,16 @@
     converse-chats {
         &.converse-overlayed {
             #controlbox {
+                converse-login-form {
+                    fieldset {
+                        margin-bottom: 0.5em;
+                    }
+                }
+
                 .login-trusted {
                     white-space: nowrap;
                     font-size: 90%;
+                    margin: 1em 0;
                 }
 
                 #converse-login-panel {
@@ -61,21 +68,18 @@
                 }
 
                 #converse-register, #converse-login {
+                    margin: auto;
                     @include make-col-ready();
                     @include make-col(8);
-                    @include make-col-offset(2);
 
                     @include media-breakpoint-up(sm) {
                         @include make-col(8);
-                        @include make-col-offset(2);
                     }
                     @include media-breakpoint-up(md) {
                         @include make-col(8);
-                        @include make-col-offset(2);
                     }
                     @include media-breakpoint-up(lg) {
                         @include make-col(6);
-                        @include make-col-offset(3);
                     }
                     .title, .instructions {
                         margin: 1em 0;

+ 1 - 1
src/plugins/controlbox/templates/loginform.js

@@ -16,7 +16,7 @@ const trust_checkbox = (checked) => {
     );
     const i18n_trusted = __('This is a trusted device');
     return html`
-        <div class="form-group form-check login-trusted mt-2">
+        <div class="form-group form-check login-trusted">
             <input
                 id="converse-login-trusted"
                 type="checkbox"

+ 1 - 1
src/plugins/headlines-view/styles/headlines.scss

@@ -20,7 +20,7 @@
         &.chat-msg {
             &.headline {
                 .chat-msg__body {
-                    margin-left: 0;
+                    margin-inline-start: 0;
                 }
             }
         }

+ 7 - 2
src/plugins/modal/styles/_modal.scss

@@ -7,12 +7,17 @@ $prefix: 'converse-';
     .modal-header {
         background-color: var(--primary-color);
         border-bottom: none;
+        display: flex;
+        justify-content: space-between;
         &.alert-danger {
             background-color: var(--error-color);
         }
         .modal-title {
             color: var(--background-color);
         }
+        .btn-close {
+            margin: 0;
+        }
         .close {
             color: var(--background-color);
         }
@@ -24,8 +29,8 @@ $prefix: 'converse-';
 
     .modal-body {
         .row {
-            margin-left: 0;
-            margin-right: 0;
+            margin-inline-start: 0;
+            margin-inline-end: 0;
         }
     }
 

+ 1 - 1
src/plugins/muc-views/styles/controlbox.scss

@@ -24,7 +24,7 @@
         .open-rooms-toggle {
             white-space: nowrap;
             converse-icon {
-                margin-left: 0.25em;
+                margin-inline-start: 0.25em;
                 padding-bottom: 0.1em;
             }
         }

+ 1 - 1
src/plugins/muc-views/styles/muc-bottom-panel.scss

@@ -35,7 +35,7 @@
         converse-muc-bottom-panel {
             .chat-message-form {
                 border-top: 0.25em solid var(--muc-color) !important;
-                border-right: 0 !important;
+                border-inline-end: 0 !important;
 
                 .suggestion-box__results--above {
                     bottom: 4.5em;

+ 5 - 5
src/plugins/muc-views/styles/muc-details-modal.scss

@@ -1,13 +1,13 @@
 converse-muc-details-modal {
     .features-list {
-        margin-left: 1em;
+        margin-inline-start: 1em;
     }
 
     .room-info {
         converse-avatar {
             display: block;
             margin-bottom: 0.5em;
-            margin-right: 1em;
+            margin-inline-end: 1em;
             float: left;
         }
         strong {
@@ -21,12 +21,12 @@ converse-muc-details-modal {
             padding-top: 0;
             .feature {
                 width: 100%;
-                margin-right: 0.5em;
-                padding-right: 0;
+                margin-inline-end: 0.5em;
+                padding-inline-end: 0;
                 font-size: 1em;
                 cursor: help;
                 converse-icon {
-                    margin-right: 0.5em;
+                    margin-inline-end: 0.5em;
                 }
             }
         }

+ 2 - 2
src/plugins/muc-views/styles/muc-head.scss

@@ -33,7 +33,7 @@
                     }
                 }
                 .chatbox-title__text--bookmarked {
-                    margin-left: 0.5em;
+                    margin-inline-start: 0.5em;
                 }
             }
 
@@ -70,7 +70,7 @@
                 display: block;
                 font-weight: normal;
                 margin: auto 0;
-                padding-right: 0;
+                padding-inline-end: 0;
                 white-space: nowrap;
                 .chatroom-jid {
                     font-size: var(--font-size-small);

+ 3 - 3
src/plugins/muc-views/styles/muc-occupant.scss

@@ -23,7 +23,7 @@
             }
 
             .occupant-details {
-                padding-left: 0.3em;
+                padding-inline-start: 0.3em;
                 padding-bottom: 1em;
                 border-bottom: 0.05em solid var(--secondary-color);
                 li {
@@ -32,7 +32,7 @@
                     margin-bottom: 0.5em;
                 }
                 .row {
-                    padding-left: 1em;
+                    padding-inline-start: 1em;
                 }
                 .occupant-details-nickname {
                     font-size: var(--font-size-huge);
@@ -47,7 +47,7 @@
 
             .bottom-panel {
                 .chat-message-form {
-                    border-right: none;
+                    border-inline-end: none;
                     border-top: 0.2em solid var(--secondary-color);
                     .send-button {
                         background-color: var(--secondary-color);

+ 4 - 8
src/plugins/muc-views/styles/muc-occupants.scss

@@ -23,10 +23,6 @@
                 }
             }
 
-            .fa-user-plus {
-                margin-right: 0.25em;
-            }
-
             .suggestion-box{
                 ul {
                     padding: 0;
@@ -55,7 +51,7 @@
                     padding: 0.25em 0.25em 0.25em 0;
                     text-overflow: ellipsis;
                     .fa {
-                        margin-right: 0.5em;
+                        margin-inline-end: 0.5em;
                     }
                     &.feature {
                         font-size: var(--font-size-tiny);
@@ -63,8 +59,8 @@
                     &.occupant {
                         cursor: pointer;
                         .msgs-indicator {
-                            margin-left: -3em;
-                            margin-right: 0.5em;
+                            margin-inline-start: -3em;
+                            margin-inline-end: 0.5em;
                             margin-top: -0.25em;
                             position: absolute;
                             font-size: xx-small;
@@ -155,7 +151,7 @@
             converse-muc-occupants {
                 .occupants {
                     .occupant-list {
-                        padding-left: 0.3em;
+                        padding-inline-start: 0.3em;
                     }
                 }
             }

+ 2 - 2
src/plugins/muc-views/styles/muc-sidebar.scss

@@ -10,8 +10,8 @@
             width: 100%;
             font-family: var(--heading-font);
             color: var(--muc-color);
-            padding-left: 0;
-            margin-right: 0.5em;
+            padding-inline-start: 0;
+            margin-inline-end: 0.5em;
         }
     }
 

+ 3 - 2
src/plugins/muc-views/styles/muc.scss

@@ -28,10 +28,11 @@
             background: var(--background-color);
             border: 2px solid var(--background-color);
             font-size: 0.6rem;
-            margin-top: 0;
-            margin-left: -0.3em;
             margin-bottom: -2em;
+            margin-inline-start: -0.3em;
+            margin-top: 0;
             padding: 0.1em;
+            position: relative;
 
             svg {
                 display: flex;

+ 1 - 1
src/plugins/profile/modals/styles/chat-status-modal.scss

@@ -14,7 +14,7 @@
             color: var(--secondary-color);
         }
         .chat-status {
-            padding-right: 0.5em;
+            padding-inline-end: 0.5em;
         }
     }
 }

+ 2 - 2
src/plugins/profile/modals/styles/profile.scss

@@ -16,7 +16,7 @@
             font-size: 95%;
             border-color: var(--primary-color);
             input[type="checkbox"] {
-                margin-right: 1em;
+                margin-inline-end: 1em;
             }
         }
 
@@ -30,7 +30,7 @@
             justify-content: space-between;
             font-size: 95%;
             .fingerprint {
-                margin-left: 1em;
+                margin-inline-start: 1em;
             }
         }
     }

+ 7 - 2
src/plugins/profile/styles/profile.scss

@@ -3,13 +3,18 @@ converse-user-profile {
         min-width: 25px;
         text-align: center;
         converse-icon {
-            padding-right: 0.5em;
+            padding-inline-end: 0.5em;
         }
     }
 
     .userinfo {
+        .xmpp-status__msg {
+            margin-inline-end: 0.5em;
+        }
+
         .username {
-            margin-left: 0.5em;
+            margin-inline-end: 0.5em;
+            margin-inline-start: 0.5em;
             overflow: hidden;
             text-overflow: ellipsis;
         }

+ 4 - 2
src/plugins/profile/templates/profile.js

@@ -43,12 +43,14 @@ export default (el) => {
                    data-target="#changeStatusModal"
                    @click=${el.showStatusChangeModal}>
 
-                    <span class="${chat_status} w-100 align-self-center" data-value="${chat_status}">
+                    <span class="${chat_status} w-100" data-value="${chat_status}">
                         <converse-icon
                                 color="var(--${color})"
                                 css="margin-top: -0.1em"
                                 size="0.82em"
-                                class="${classes}"></converse-icon> ${status_message}</span>
+                                class="${classes}"></converse-icon>
+                        <span class="xmpp-status__msg">${status_message}</span>
+                    </span>
                 </a>
             </div>
         </div>`

+ 2 - 4
src/plugins/roomslist/styles/roomsgroups.scss

@@ -14,21 +14,19 @@
 
         converse-rooms-list {
             display: block;
-            margin-bottom: 0.5em;
 
             svg {
                 fill: var(--muc-color);
             }
 
             .list-item {
-                padding-top: 0;
-                padding-bottom: 0;
-
+                padding: 0;
                 .open-room {
                     display: flex;
                     flex-direction: row;
                     span {
                         padding-top: 0.5em;
+                        padding-inline-end: 0.5em;
                     }
                 }
             }

+ 2 - 1
src/plugins/rootview/index.js

@@ -13,9 +13,10 @@ converse.plugins.add('converse-rootview', {
         // configuration settings.
         api.settings.extend({
             auto_insert: true,
-            theme: 'classic',
             dark_theme: 'dracula',
+            rtl_langs: ["ar", "fa", "he", "ur"],
             show_background: false,
+            theme: 'classic',
         });
 
         api.listen.on('chatBoxesInitialized', ensureElement);

+ 14 - 3
src/plugins/rootview/root.js

@@ -1,11 +1,11 @@
+import { i18n } from 'i18n';
+import { _converse, api } from '@converse/headless';
 import tplRoot from "./templates/root.js";
-import { api } from '@converse/headless';
 import { CustomElement } from 'shared/components/element.js';
 import { getTheme } from './utils.js';
 
 import './styles/root.scss';
 
-
 /**
  * `converse-root` is an optional custom element which can be used to
  * declaratively insert the Converse UI into the DOM.
@@ -15,7 +15,7 @@ import './styles/root.scss';
  */
 export default class ConverseRoot extends CustomElement {
 
-    render () { // eslint-disable-line class-methods-use-this
+    render () {
         return tplRoot();
     }
 
@@ -39,6 +39,17 @@ export default class ConverseRoot extends CustomElement {
         this.classList.add(`theme-${theme}`);
         this.setAttribute('data-bs-theme', theme);
         this.setAttribute('data-converse-theme', theme);
+
+        const lang = i18n.getLocale();
+        this.setAttribute('lang', lang);
+
+        const rtl_langs = api.settings.get('rtl_langs');
+        if (rtl_langs.includes(lang)) {
+            this.setAttribute('dir', 'rtl');
+        } else {
+            this.setAttribute('dir', 'ltr');
+        }
+
         this.requestUpdate();
     }
 }

+ 2 - 2
src/plugins/rootview/styles/background.scss

@@ -32,14 +32,14 @@ converse-bg {
         font-weight: normal;
         text-align: center;
         font-size: 140%;
-        margin-left: 0.2em;
+        margin-inline-start: 0.2em;
         .byline {
             margin: 0;
             font-family: var(--heading-font);
             font-size: 0.3em;
             opacity: 0.55;
             margin-bottom: 2em;
-            margin-left: -2.7em;
+            margin-inline-start: -2.7em;
             word-spacing: 5px;
         }
     }

+ 2 - 2
src/plugins/rootview/styles/root.scss

@@ -3,8 +3,8 @@ converse-root {
     &.converse-overlayed {
         bottom: 0;
         left: 0;
-        padding-left: env(safe-area-inset-left);
-        padding-right: env(safe-area-inset-right);
+        padding-inline-start: env(safe-area-inset-left);
+        padding-inline-end: env(safe-area-inset-right);
         position: fixed;
         z-index: 1031; // One more than bootstrap navbar
     }

+ 5 - 3
src/plugins/rosterview/styles/roster.scss

@@ -11,7 +11,7 @@
         .open-contacts-toggle {
             white-space: nowrap;
             converse-icon {
-                margin-left: 0.25em;
+                margin-inline-start: 0.25em;
                 padding-bottom: 0.1em;
             }
         }
@@ -19,6 +19,7 @@
     }
 
     #converse-roster {
+        text-align: start;
         width: 100%;
         margin: 0;
         padding: 0;
@@ -91,6 +92,7 @@
                     margin: 0;
                     padding: 0;
                     converse-icon.chat-status {
+                        position: relative;
                         border: 2px solid var(--background-color);
                         svg {
                             display: flex;
@@ -115,7 +117,7 @@
                             max-width: 60%;
                         }
                         &.contact-name--offline {
-                            margin-left: 0.25em;
+                            margin-inline-start: 0.25em;
                         }
                     }
                 }
@@ -131,7 +133,7 @@
                     display: inline-block;
                 }
                 .decline-xmpp-request {
-                    margin-left: 1em;
+                    margin-inline-start: 1em;
                 }
                 &:hover {
                     background-color: var(--highlight-color-hover);

+ 2 - 2
src/shared/autocomplete/styles/_autocomplete.scss

@@ -33,7 +33,7 @@
                 padding: .4em;
                 background: var(--background-color);
                 border: inherit;
-                border-right: 0;
+                border-inline-end: 0;
                 border-bottom: 0;
                 -webkit-transform: rotate(45deg);
                 transform: rotate(45deg);
@@ -93,7 +93,7 @@
                 padding: 0.4em;
                 background: var(--background-color);
                 border: inherit;
-                border-left: 0;
+                border-inline-start: 0;
                 border-top: 0;
                 -webkit-transform: rotate(45deg);
                 transform: rotate(45deg);

+ 1 - 1
src/shared/avatar/avatar.scss

@@ -3,7 +3,7 @@ converse-avatar {
     background: transparent;
 
     &.avatar-muc {
-        margin-right: 0.5em;
+        margin-inline-end: 0.5em;
     }
 
     &.modal-avatar {

+ 3 - 3
src/shared/chat/styles/emoji.scss

@@ -77,7 +77,7 @@
                     display: flex;
                     flex-direction: row;
                     flex-wrap: wrap;
-                    padding-left: 0;
+                    padding-inline-start: 0;
                     li {
                         padding: 0 0.25em;
                     }
@@ -94,7 +94,7 @@
                     height: calc(var(--font-size-huge) * 1.5);
                     width: calc(var(--font-size-huge) * 1.5);
                     overflow: hidden;
-                    margin-left: 0;
+                    margin-inline-start: 0;
                     list-style: none;
                     position: relative;
                     &.insert-emoji {
@@ -139,7 +139,7 @@
                 ul {
                     display: flex;
                     flex-direction: row;
-                    padding-left: 0;
+                    padding-inline-start: 0;
 
                     .emoji-category {
                         padding: 0.25em 0;

+ 3 - 3
src/shared/chat/styles/message-actions.scss

@@ -1,5 +1,5 @@
 converse-message-actions {
-    margin-left: 0.5em;
+    margin-inline-start: 0.5em;
 
     .chat-msg__actions {
         .dropdown-menu {
@@ -25,11 +25,11 @@ converse-message-actions {
         .chat-msg__action {
             width: 100%;
             padding: 0.5em 1em;
-            text-align: left;
+            text-align: start;
             white-space: nowrap;
 
             converse-icon {
-                margin-right: 0.25em;
+                margin-inline-end: 0.25em;
             }
 
             &:hover {

+ 1 - 1
src/shared/chat/styles/message-body.scss

@@ -3,7 +3,7 @@
 @import "shared/styles/_mixins.scss";
 
 converse-chat-message-body {
-    margin-right: 0.5em;
+    margin-inline-end: 0.5em;
     overflow-y: hidden; // Hide zalgo text that overflows vertically
 
     audio {

+ 3 - 1
src/shared/components/styles/dropdown.scss

@@ -30,13 +30,15 @@
         }
 
         .dropdown-item {
+            text-align: start;
             color: var(--text-color) !important;
             font-size: var(--font-size);
             padding: 0.5rem 1rem;
             converse-icon {
                 margin-top: -0.1em;
                 width: 1.25em;
-                margin-right: 0.25rem;
+                margin-inline-end: 0.25rem;
+                margin-inline-start: 0.25rem;
             }
             &:active, &.selected {
                 background-color: var(--highlight-color);

+ 2 - 2
src/shared/components/styles/gif.scss

@@ -44,8 +44,8 @@ img.gif {
 	&:after {
 	    opacity: 0;
 	    transition: opacity 0.25s ease-in-out;
-	    border-left: 20px solid #FFF;
-	    border-right: 20px solid #FFF;
+	    border-inline-start: 20px solid #FFF;
+	    border-inline-end: 20px solid #FFF;
 	    width: 50px;
 	    height: 50px;
 	}

+ 11 - 12
src/shared/styles/_core.scss

@@ -2,7 +2,6 @@
     color: var(--text-color);
     font-family: var(--normal-font);
     font-size: var(--font-size);
-    direction: ltr;
 
     .flyout {
         position: absolute;
@@ -63,7 +62,7 @@
                 font-family: var(--heading-font);
                 font-size: 0.3em;
                 margin-bottom: 0.75em;
-                margin-left: -2.7em;
+                margin-inline-start: -2.7em;
                 opacity: 0.55;
                 word-spacing: 5px;
             }
@@ -81,7 +80,7 @@
         .converse-svg-logo {
             color: var(--link-color);
             height: 1.5em;
-            margin-right: 0.25em;
+            margin-inline-end: 0.25em;
             margin-bottom: -0.25em;
             .cls-1 {
                 isolation: isolate;
@@ -109,7 +108,7 @@
             font-family: var(--heading-font);
             font-size: 0.25em;
             opacity: 0.55;
-            margin-left: -7em;
+            margin-inline-start: -7em;
             word-spacing: 5px;
         }
     }
@@ -388,7 +387,7 @@
     }
 
     .locked {
-        padding-right: 22px;
+        padding-inline-end: 22px;
     }
 
     @keyframes spin {
@@ -437,7 +436,7 @@
     }
 
     .avatar-autocomplete {
-        margin-right: 0.5em;
+        margin-inline-end: 0.5em;
         vertical-align: middle;
     }
 
@@ -480,28 +479,28 @@
 
 @media screen and (min-width: 576px) {
     .conversejs .offset-sm-2 {
-        margin-left: 16.666667%;
+        margin-inline-start: 16.666667%;
     }
 }
 @media screen and (min-width: 768px) {
     .conversejs .offset-md-2 {
-        margin-left: 16.666667%;
+        margin-inline-start: 16.666667%;
     }
     .conversejs .offset-md-3 {
-        margin-left: 25%;
+        margin-inline-start: 25%;
     }
 }
 @media screen and (min-width: 992px) {
     .conversejs .offset-lg-2 {
-        margin-left: 16.666667%;
+        margin-inline-start: 16.666667%;
     }
     .conversejs .offset-lg-3 {
-        margin-left: 25%;
+        margin-inline-start: 25%;
     }
 }
 @media screen and (min-width: 1200px) {
     .conversejs .offset-xl-2 {
-        margin-left: 16.666667%;
+        margin-inline-start: 16.666667%;
     }
 }
 @media screen and (max-height: 450px) {

+ 3 - 3
src/shared/styles/buttons.scss

@@ -8,15 +8,15 @@
         i {
             &.fa, &.far, &.fas {
                 color: var(--button-text-color);
-                margin-right: 0.5em;
+                margin-inline-end: 0.5em;
                 &.only-icon {
-                    margin-right: 0;
+                    margin-inline-end: 0;
                 }
             }
         }
         converse-icon {
             display: inline-block;
-            margin-right: 0;
+            margin-inline-end: 0;
             svg {
                 color: var(--button-text-color);
             }

+ 4 - 3
src/shared/styles/lists.scss

@@ -10,7 +10,7 @@
     }
 
     .list-container {
-        text-align: left;
+        text-align: start;
         padding: 0.3em 0;
 
         .list-toggle {
@@ -23,8 +23,9 @@
     }
 
     .items-list {
-        padding-left: 0;
-        text-align: left;
+        padding-inline-end: 0;
+        padding-inline-start: 0;
+        text-align: start;
 
         .list-item {
             border: none;

+ 21 - 21
src/shared/styles/messages.scss

@@ -16,13 +16,13 @@
         }
 
         blockquote {
-            margin-left: 0.5em;
-            margin-bottom: 0.25em;
-            padding-right: 1em;
+            border-inline-start: 0.3em solid var(--info-color);
             color: var(--info-color);
-            border-left: 0.3em solid var(--info-color);
-            padding-left: 0.5em;
             display: inline-block;
+            margin-bottom: 0.25em;
+            margin-inline-start: 0;
+            padding-inline-end: 1em;
+            padding-inline-start: 0.5em;
         }
 
         code {
@@ -100,7 +100,7 @@
             font-style: italic;
 
             .chat-msg__author {
-                padding-right: 0.2em;
+                padding-inline-end: 0.2em;
             }
         }
 
@@ -131,10 +131,10 @@
                 color: var(--background-color);
                 i {
                     color: var(--background-color);
-                    padding-right: 0.5em;
+                    padding-inline-end: 0.5em;
                 }
                 &:before {
-                    padding-right: 0.25em;
+                    padding-inline-end: 0.25em;
                     white-space: nowrap;
                 }
             }
@@ -153,7 +153,7 @@
 
             .chat-msg__content--action {
                 width: 100%;
-                margin-left: 0;
+                margin-inline-start: 0;
             }
 
             .chat-msg__message {
@@ -201,7 +201,7 @@
 
             .chat-msg__edit-modal {
                 cursor: pointer;
-                padding-right: 0.5em;
+                padding-inline-end: 0.5em;
             }
 
             .chat-msg__subject {
@@ -242,15 +242,15 @@
 
             .chat-msg__heading {
                 width: 100%;
-                padding-right: 0.25rem;
+                padding-inline-end: 0.25rem;
 
                 .badge {
-                    margin-left: 0.5em;
+                    margin-inline-start: 0.5em;
                     font-family: var(--normal_font);
                 }
                 .chat-msg__time {
-                    padding-left: 0.25em;
-                    padding-right: 0.25em;
+                    padding-inline-start: 0.25em;
+                    padding-inline-end: 0.25em;
                     color: var(--secondary-color);
                 }
                 .fa-lock {
@@ -272,14 +272,14 @@
                     width: auto;
 
                     .fa {
-                        margin-left: 0.5em;
+                        margin-inline-start: 0.5em;
                     }
                 }
                 .chat-msg__author {
                     font-size: var(--message-font-size);
                 }
                 .chat-msg__time {
-                    margin-left: 0;
+                    margin-inline-start: 0;
                 }
             }
 
@@ -293,14 +293,14 @@
                     display: none;
                 }
                 &.chat-msg--with-avatar .chat-msg__content {
-                    margin-left: 2.75rem;
+                    margin-inline-start: 2.75rem;
                     width: 100%;
                 }
             }
 
             .chat-msg__receipt {
-                margin-left: 0.5em;
-                margin-right: 0.5em;
+                margin-inline-start: 0.5em;
+                margin-inline-end: 0.5em;
                 color: var(--success-color);
             }
         }
@@ -310,7 +310,7 @@
             flex-direction: column;
             justify-content: space-between;
             align-items: stretch;
-            margin-left: 0.5rem;
+            margin-inline-start: 0.5rem;
             &:hover {
                 .btn--standalone {
                     opacity: 1;
@@ -342,7 +342,7 @@
                 &.chat-msg {
                     &.chat-msg--followup {
                         .chat-msg__content {
-                            margin-left: 0;
+                            margin-inline-start: 0;
                         }
                     }
                 }

+ 3 - 3
src/shared/styles/status.scss

@@ -1,19 +1,19 @@
 .conversejs {
     .chat-status {
         vertical-align: middle;
-        margin-right: 0;
+        margin-inline-end: 0;
         border-radius: 50%;
         font-size: 1em;
 
         &.chat-status--avatar {
           font-size: 0.6rem;
-          margin-left: -0.7em;
+          margin-inline-start: -0.7em;
           margin-bottom: -1.9em;
           border-radius: 50%;
         }
     }
     .chat-status--offline {
-        margin-right: 0.8em;
+        margin-inline-end: 0.8em;
     }
     .chat-status--online {
         color: var(--chat-status-online);

+ 1 - 1
src/shared/styles/themes/cyberpunk.scss

@@ -191,7 +191,7 @@
                     height: 100%;
                     width: 2px;
                     background-color: pink;
-                    margin-left: 4.5%;
+                    margin-inline-start: 4.5%;
                     box-shadow: 0 2px 21px pink;
                 }
             }

+ 8 - 8
src/shared/styles/website.scss

@@ -256,7 +256,7 @@ section {
         font-size: 20px;
         opacity: 0.5;
         margin-bottom: 2em;
-        margin-left: -75px;
+        margin-inline-start: -75px;
     }
 
     .subdued {
@@ -267,7 +267,7 @@ section {
 
     .converse-svg-logo {
         height: 1.2em;
-        margin-right: 0.25em;
+        margin-inline-end: 0.25em;
         margin-bottom: 0.1em;
         .cls-1 {
             isolation: isolate;
@@ -454,7 +454,7 @@ ul.contact,
 ul.integration,
 ul.screencasts,
 ul.features {
-    text-align: left;
+    text-align: start;
     font-size: 19px;
 }
 .feature-icon {
@@ -481,7 +481,7 @@ ul.features {
     position: absolute;
     bottom: 0;
     left: 50%;
-    margin-left: -0.325em;
+    margin-inline-start: -0.325em;
     width: 0.65em;
     height: 0.65em;
     display: block;
@@ -495,11 +495,11 @@ ul.features {
     width: 1px;
     height: 4.35em;
     background: white;
-    margin-left: -0.5px;
+    margin-inline-start: -0.5px;
 }
 .row {
-    margin-left: 0;
-    margin-right: 0;
+    margin-inline-start: 0;
+    margin-inline-end: 0;
 }
 
 .mastodon {
@@ -529,6 +529,6 @@ ul.features {
     list-style: none;
 }
 .sponsors-text {
-    text-align: left;
+    text-align: start;
     padding: 0 0 1em 0;
 }